diff --git a/package-lock.json b/package-lock.json index bb11aa4..8198fd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1297,14 +1297,24 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001271", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz", - "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==", + "version": "1.0.30001579", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", + "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] }, "node_modules/caseless": { "version": "0.12.0", @@ -5844,9 +5854,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001271", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz", - "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==", + "version": "1.0.30001579", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", + "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", "dev": true }, "caseless": { diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts index 0e0daea..43ef5c8 100644 --- a/src/RokuDeploy.spec.ts +++ b/src/RokuDeploy.spec.ts @@ -919,6 +919,34 @@ describe('index', () => { } catch (e) { } }); + it('uses overridden route', async () => { + const stub = mockDoPostRequest(); + await rokuDeploy.publish({ + ...options, + packageUploadOverrides: { + route: 'alt_path' + } + }); + expect(stub.getCall(0).args[0].url).to.eql('http://0.0.0.0:80/alt_path'); + }); + + it('overrides formData', async () => { + const stub = mockDoPostRequest(); + await rokuDeploy.publish({ + ...options, + remoteDebug: true, + packageUploadOverrides: { + formData: { + remotedebug: null, + newfield: 'here' + } + } + }); + expect(stub.getCall(0).args[0].formData).to.include({ + newfield: 'here' + }).and.to.not.haveOwnProperty('remotedebug'); + }); + it('does not delete the archive by default', async () => { let zipPath = `${options.outDir}/${options.outFile}`; @@ -2230,6 +2258,9 @@ describe('index', () => { it('rejects the promise when an error occurs', async () => { //zip path doesn't exist await assertThrowsAsync(async () => { + sinon.stub(fsExtra, 'outputFile').callsFake(() => { + throw new Error(); + }); await rokuDeploy.zipFolder('source', '.tmp/some/zip/path/that/does/not/exist'); }); }); diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts index 5468799..64e956b 100644 --- a/src/RokuDeploy.ts +++ b/src/RokuDeploy.ts @@ -142,7 +142,7 @@ export class RokuDeploy { if (options.incrementBuildNumber) { let timestamp = dateformat(new Date(), 'yymmddHHMM'); parsedManifest.build_version = timestamp; //eslint-disable-line camelcase - await this.fsExtra.writeFile(manifestPath, this.stringifyManifest(parsedManifest)); + await this.fsExtra.outputFile(manifestPath, this.stringifyManifest(parsedManifest)); } if (beforeZipCallback) { @@ -433,7 +433,9 @@ export class RokuDeploy { readStream.on('open', resolve); }); - let requestOptions = this.generateBaseRequestOptions('plugin_install', options, { + const route = options.packageUploadOverrides?.route ?? 'plugin_install'; + + let requestOptions = this.generateBaseRequestOptions(route, options, { mysubmit: 'Replace', archive: readStream }); @@ -449,6 +451,16 @@ export class RokuDeploy { requestOptions.formData.remotedebug_connect_early = '1'; } + //apply any supplied formData overrides + for (const key in options.packageUploadOverrides?.formData ?? {}) { + const value = options.packageUploadOverrides.formData[key]; + if (value === undefined || value === null) { + delete requestOptions.formData[key]; + } else { + requestOptions.formData[key] = value; + } + } + //try to "replace" the channel first since that usually works. let response: HttpResponse; try { @@ -985,7 +997,7 @@ export class RokuDeploy { options = this.getOptions(options); let zipFileName = options.outFile; - if (!zipFileName.toLowerCase().endsWith('.zip')) { + if (!zipFileName.toLowerCase().endsWith('.zip') && !zipFileName.toLowerCase().endsWith('.squashfs')) { zipFileName += '.zip'; } let outFolderPath = path.resolve(options.outDir); @@ -1170,7 +1182,7 @@ export class RokuDeploy { await Promise.all(promises); // level 2 compression seems to be the best balance between speed and file size. Speed matters more since most will be calling squashfs afterwards. const content = await zip.generateAsync({ type: 'nodebuffer', compressionOptions: { level: 2 } }); - return this.fsExtra.writeFile(zipFilePath, content); + return this.fsExtra.outputFile(zipFilePath, content); } } diff --git a/src/RokuDeployOptions.ts b/src/RokuDeployOptions.ts index 75e4378..8b44f99 100644 --- a/src/RokuDeployOptions.ts +++ b/src/RokuDeployOptions.ts @@ -158,6 +158,22 @@ export interface RokuDeployOptions { * If true, the previously installed dev channel will be deleted before installing the new one */ deleteInstalledChannel?: boolean; + + /** + * Overrides for values used during the zip upload process. You probably don't need to change these... + */ + packageUploadOverrides?: { + /** + * The route to use for uploading to the Roku device. Defaults to 'plugin_install' + * @default 'plugin_install' + */ + route?: string; + + /** + * A dictionary of form fields to be included in the package upload request. Set a value to null to delete from the form + */ + formData?: Record; + }; } export type FileEntry = (string | { src: string | string[]; dest?: string });