diff --git a/CHANGELOG.md b/CHANGELOG.md
index 702b77e..5fe7ae8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
+## [4.0.0-alpha.3] - unreleased
+### Changed (Breaking)
+ - Renamed `RekeyDeviceOptions.rekeySignedPackage` → `pkg` to match CLI `--pkg` option
+ - Renamed `ZipOptions.stagingDir` → `dir` to match CLI `--dir` option
+ - Renamed `remotePort` → `ecpPort` throughout all options interfaces and `getOptions()` defaults
+ - CLI `sideload` command: replaced `--noclose` flag with `--close` boolean (use `--no-close` to skip closing the channel)
+### Added
+ - `sideload()` now accepts `zip` (explicit zip path) and `rootDir` (auto-zip a directory) options directly
+ - `sideload()` now automatically calls `closeChannel()` before sideloading (controlled by new `close` option, defaults to `true`)
+ - CLI `sideload --no-close` flag to skip closing the channel before sideloading
+
+
+
## [4.0.0-alpha.2](https://github.com/rokucommunity/roku-deploy/compare/4.0.0-alpha.1...v4.0.0-alpha.2) - 2025-06-02
### Added
- Add interactive remote mode ([#169](https://github.com/rokucommunity/roku-deploy/pull/169))
diff --git a/README.md b/README.md
index b3a9d68..8e8f88d 100644
--- a/README.md
+++ b/README.md
@@ -105,13 +105,16 @@ Lastly, the default files array has changed. node modules and static analysis fi
## CLI Usage
### Sideload a project to your Roku device
-Sideload a .zip package or directory to a roku device:
+Sideload a .zip package or directory to a roku device. By default, the channel is closed before sideloading. Use `--no-close` to skip.
```shell
# Sideload a zip file
npx roku-deploy sideload --host 'ip.of.roku' --password 'password' --zip './path/to/your/app.zip'
# Sideload from a directory (will be zipped first automatically)
npx roku-deploy sideload --host 'ip.of.roku' --password 'password' --rootDir './path/to/your/project'
+
+# Sideload without closing the channel first
+npx roku-deploy sideload --host 'ip.of.roku' --password 'password' --zip './path/to/your/app.zip' --no-close
```
### Create a signed package from an existing dev channel
@@ -212,7 +215,7 @@ Use this logic if you'd like to create a zip from your application folder.
//create a signed package of your project
rokuDeploy.zip({
outDir: 'folder/to/put/zip',
- stagingDir: 'path/to/files/to/zip',
+ dir: 'path/to/files/to/zip',
outFile: 'filename-of-your-app.zip'
//...other options if necessary
}).then(function(){
@@ -232,14 +235,26 @@ rokuDeploy.keyPress({
```
### Sideloading a project
-If you've already created a zip using some other tool, you can use roku-deploy to sideload the zip.
+Sideload a zip file, a directory, or a pre-built zip at the default `outDir`/`outFile` location. The current dev channel is closed before sideloading by default; pass `close: false` to skip.
```typescript
-//sideload a package onto a specified Roku
+// Sideload a zip file
rokuDeploy.sideload({
host: 'ip-of-roku',
password: 'password for roku dev admin portal',
- outDir: 'folder/where/your/zip/resides/',
- outFile: 'filename-of-your-app.zip'
+ zip: './path/to/your/app.zip'
+ //...other options if necessary
+}).then(function(){
+ //the app has been sideloaded
+}, function(error) {
+ //it failed
+ console.error(error);
+});
+
+// Sideload from a source directory (will be zipped automatically)
+rokuDeploy.sideload({
+ host: 'ip-of-roku',
+ password: 'password for roku dev admin portal',
+ rootDir: './path/to/your/project'
//...other options if necessary
}).then(function(){
//the app has been sideloaded
@@ -263,8 +278,7 @@ rokuDeploy.convertToSquashfs({
rokuDeploy.createSignedPackage({
host: '1.2.3.4',
password: 'password',
- signingPassword: 'signing password',
- stagingDir: './path/to/staging/directory'
+ signingPassword: 'signing password'
//...other options if necessary
})
```
@@ -294,7 +308,7 @@ rokuDeploy.captureScreenshot({
rokuDeploy.rekeyDevice({
host: 'ip-of-roku',
password: 'password',
- rekeySignedPackage: './path/to/signed.pkg'
+ pkg: './path/to/signed.pkg'
//...other options if necessary
})
```
@@ -482,7 +496,7 @@ Here are the available options for customizing to your developer-specific workfl
- **signingPassword:** string (*required for signing*)
The password used for creating signed packages.
-- **rekeySignedPackage:** string (*required for rekeying*)
+- **pkg:** string (*required for rekeying*)
Path to a copy of the signed package you want to use for rekeying.
- **devId:** string
@@ -555,10 +569,10 @@ Here are the available options for customizing to your developer-specific workfl
just in case roku adds support for custom usernames in the future.
- **packagePort?:** number = `80`
- The port used for package-related requests. This is mainly used for things like emulators, or when your roku is behind a firewall with a port-forward.
+ The port used for package-related requests. This is mainly used when your roku is behind a firewall with a port-forward.
-- **remotePort?:** number = `8060`
- The port used for sending remote control commands (like home press or back press). This is mainly used for things like emulators, or when your roku is behind a firewall with a port-forward.
+- **ecpPort?:** number = `8060`
+ The port used for sending ECP/remote control commands (like key presses). This is mainly used when your roku is behind a firewall with a port-forward.
- **screenshotDir?:** string = `"./tmp/roku-deploy/screenshots/"`
The directory where screenshots should be saved. Will use the OS temp directory by default.
diff --git a/src/RokuDeploy.spec.ts b/src/RokuDeploy.spec.ts
index 6901d02..8503d49 100644
--- a/src/RokuDeploy.spec.ts
+++ b/src/RokuDeploy.spec.ts
@@ -39,7 +39,7 @@ describe('RokuDeploy', () => {
stagingDir: stagingDir,
signingPassword: '12345',
host: 'localhost',
- rekeySignedPackage: `${tempDir}/testSignedPackage.pkg`
+ pkg: `${tempDir}/testSignedPackage.pkg`
});
options.rootDir = rootDir;
fsExtra.emptyDirSync(tempDir);
@@ -416,7 +416,7 @@ describe('RokuDeploy', () => {
it('should use given port if provided', async () => {
const stub = mockDoGetRequest(body);
- await rokuDeploy.getDeviceInfo({ host: '1.1.1.1', remotePort: 9999 });
+ await rokuDeploy.getDeviceInfo({ host: '1.1.1.1', ecpPort: 9999 });
expect(stub.getCall(0).args[0].url).to.eql('http://1.1.1.1:9999/query/device-info');
});
@@ -427,7 +427,7 @@ describe('RokuDeploy', () => {
29380007-0800-1025-80a4-d83154332d7e
`);
- const result = await rokuDeploy.getDeviceInfo({ host: '192.168.1.10', remotePort: 8060, enhance: true });
+ const result = await rokuDeploy.getDeviceInfo({ host: '192.168.1.10', ecpPort: 8060, enhance: true });
expect(result.isStick).not.to.exist;
});
@@ -443,7 +443,7 @@ describe('RokuDeploy', () => {
it('should sanitize additional data when the host+param+format signature is triggered', async () => {
mockDoGetRequest(body);
- const result = await rokuDeploy.getDeviceInfo({ host: '192.168.1.10', remotePort: 8060, enhance: true });
+ const result = await rokuDeploy.getDeviceInfo({ host: '192.168.1.10', ecpPort: 8060, enhance: true });
expect(result).to.include({
// make sure the number fields are turned into numbers
softwareBuild: 4170,
@@ -482,7 +482,7 @@ describe('RokuDeploy', () => {
it('converts keys to camel case when enabled', async () => {
mockDoGetRequest(body);
- const result = await rokuDeploy.getDeviceInfo({ host: '192.168.1.10', remotePort: 8060, enhance: true });
+ const result = await rokuDeploy.getDeviceInfo({ host: '192.168.1.10', ecpPort: 8060, enhance: true });
const props = [
'udn',
'serialNumber',
@@ -742,7 +742,7 @@ describe('RokuDeploy', () => {
try {
fsExtra.ensureDirSync(options.stagingDir);
await rokuDeploy.zip({
- stagingDir: s`${tempDir}/path/to/nowhere`,
+ dir: s`${tempDir}/path/to/nowhere`,
outDir: outDir
});
} catch (e) {
@@ -755,7 +755,7 @@ describe('RokuDeploy', () => {
let err;
try {
await rokuDeploy.zip({
- stagingDir: s`${tempDir}/path/to/nowhere`,
+ dir: s`${tempDir}/path/to/nowhere`,
outDir: outDir
});
} catch (e) {
@@ -816,7 +816,7 @@ describe('RokuDeploy', () => {
resolve();
});
});
- await rokuDeploy.keyPress({ ...options, host: '1.2.3.4', remotePort: 987, key: 'home' });
+ await rokuDeploy.keyPress({ ...options, host: '1.2.3.4', ecpPort: 987, key: 'home' });
await promise;
});
@@ -841,7 +841,7 @@ describe('RokuDeploy', () => {
resolve();
});
});
- await rokuDeploy.keyPress({ ...options, host: '1.2.3.4', remotePort: 987, key: 'home', timeout: 1000 });
+ await rokuDeploy.keyPress({ ...options, host: '1.2.3.4', ecpPort: 987, key: 'home', timeout: 1000 });
await promise;
});
});
@@ -1646,7 +1646,7 @@ describe('RokuDeploy', () => {
${options.devId}
`;
mockDoGetRequest(body);
- fsExtra.outputFileSync(path.resolve(rootDir, options.rekeySignedPackage), '');
+ fsExtra.outputFileSync(path.resolve(rootDir, options.pkg), '');
});
it('does not crash when archive is undefined', async () => {
@@ -1657,7 +1657,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: options.rekeySignedPackage,
+ pkg: options.pkg,
signingPassword: options.signingPassword,
devId: options.devId
});
@@ -1678,7 +1678,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: s`notReal.pkg`,
+ pkg: s`notReal.pkg`,
signingPassword: options.signingPassword,
devId: options.devId
});
@@ -1695,7 +1695,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: s`${tempDir}/testSignedPackage.pkg`,
+ pkg: s`${tempDir}/testSignedPackage.pkg`,
signingPassword: options.signingPassword,
devId: options.devId
});
@@ -1709,7 +1709,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: options.rekeySignedPackage,
+ pkg: options.pkg,
signingPassword: options.signingPassword,
devId: options.devId
});
@@ -1723,7 +1723,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: options.rekeySignedPackage,
+ pkg: options.pkg,
signingPassword: options.signingPassword,
devId: undefined
});
@@ -1735,7 +1735,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: options.rekeySignedPackage,
+ pkg: options.pkg,
signingPassword: options.signingPassword,
devId: options.devId
});
@@ -1755,7 +1755,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: options.rekeySignedPackage,
+ pkg: options.pkg,
signingPassword: options.signingPassword,
devId: options.devId
});
@@ -1775,7 +1775,7 @@ describe('RokuDeploy', () => {
await rokuDeploy.rekeyDevice({
host: '1.2.3.4',
password: 'password',
- rekeySignedPackage: options.rekeySignedPackage,
+ pkg: options.pkg,
signingPassword: options.signingPassword,
devId: '45fdc2019903ac333ff624b0b2cddd2c733c3e74'
});
@@ -2969,7 +2969,7 @@ describe('RokuDeploy', () => {
});
await rokuDeploy.zip({
- stagingDir: stagingDir,
+ dir: stagingDir,
outDir: outDir
});
const data = fsExtra.readFileSync(rokuDeploy['getOutputZipFilePath']({ outDir: outDir }));
@@ -3762,13 +3762,13 @@ describe('RokuDeploy', () => {
});
- describe('remotePort', () => {
+ describe('ecpPort', () => {
it('defaults to 8060', () => {
- expect(rokuDeploy.getOptions({}).remotePort).to.equal(8060);
+ expect(rokuDeploy.getOptions({}).ecpPort).to.equal(8060);
});
it('can be overridden', () => {
- expect(rokuDeploy.getOptions({ remotePort: 1234 }).remotePort).to.equal(1234);
+ expect(rokuDeploy.getOptions({ ecpPort: 1234 }).ecpPort).to.equal(1234);
});
});
@@ -3857,10 +3857,10 @@ describe('RokuDeploy', () => {
});
it('throws error when rekeyDevice is missing required options', async () => {
- const requiredOptions: Partial = { host: '1.2.3.4', password: 'abcd', rekeySignedPackage: 'abcd', signingPassword: 'abcd' };
+ const requiredOptions: Partial = { host: '1.2.3.4', password: 'abcd', pkg: 'abcd', signingPassword: 'abcd' };
await testRequiredOptions('rekeyDevice', requiredOptions, 'host');
await testRequiredOptions('rekeyDevice', requiredOptions, 'password');
- await testRequiredOptions('rekeyDevice', requiredOptions, 'rekeySignedPackage');
+ await testRequiredOptions('rekeyDevice', requiredOptions, 'pkg');
await testRequiredOptions('rekeyDevice', requiredOptions, 'signingPassword');
});
diff --git a/src/RokuDeploy.ts b/src/RokuDeploy.ts
index e97f369..6bfc1e0 100644
--- a/src/RokuDeploy.ts
+++ b/src/RokuDeploy.ts
@@ -62,18 +62,24 @@ export class RokuDeploy {
* @param options
*/
public async zip(options: ZipOptions) {
- logger.info('Beginning to zip staging folder');
+ logger.info('Beginning to zip folder');
options = this.getOptions(options) as any;
+ if (options.dir) {
+ options.dir = path.resolve((options as any).cwd, options.dir);
+ } else {
+ options.dir = (options as any).stagingDir;
+ }
+
let zipFilePath = this.getOutputZipFilePath(options as any);
- //ensure the manifest file exists in the staging folder
- if (!await util.fileExistsCaseInsensitive(`${options.stagingDir}/manifest`)) {
- throw new Error(`Cannot zip package: missing manifest file in "${options.stagingDir}"`);
+ //ensure the manifest file exists in the folder to be zipped
+ if (!await util.fileExistsCaseInsensitive(`${options.dir}/manifest`)) {
+ throw new Error(`Cannot zip package: missing manifest file in "${options.dir}"`);
}
- //create a zip of the staging folder
- await this.makeZip(options.stagingDir, zipFilePath);
+ //create a zip of the folder
+ await this.makeZip(options.dir, zipFilePath);
logger.info('Zip created at:', zipFilePath);
}
@@ -217,7 +223,7 @@ export class RokuDeploy {
let filledOptions = this.getOptions(options);
// press the home button to return to the main screen
return this.doPostRequest({
- url: `http://${filledOptions.host}:${filledOptions.remotePort}/${filledOptions.action}/${filledOptions.key}`,
+ url: `http://${filledOptions.host}:${filledOptions.ecpPort}/${filledOptions.action}/${filledOptions.key}`,
timeout: filledOptions.timeout
}, false);
}
@@ -236,9 +242,32 @@ export class RokuDeploy {
* @param options
*/
public async sideload(options: SideloadOptions): Promise<{ message: string; results: any }> {
- logger.info('Beggining to sideload package');
+ logger.info('Beginning to sideload package');
this.checkRequiredOptions(options, ['host', 'password']);
+
+ // Resolve zip/rootDir before getOptions so outDir/outFile are set correctly
+ if (options.zip) {
+ options.zip = path.resolve(options.cwd ?? process.cwd(), options.zip);
+ options.outDir = path.dirname(options.zip);
+ options.outFile = path.basename(options.zip);
+ options.retainDeploymentArchive = true;
+ } else if (options.rootDir) {
+ options.rootDir = path.resolve(options.cwd ?? process.cwd(), options.rootDir);
+ }
+
options = this.getOptions(options) as any;
+
+ // Close the channel before sideloading unless explicitly disabled
+ if (options.close !== false) {
+ await this.closeChannel(options as CloseChannelOptions);
+ }
+
+ // If rootDir was provided (and no zip), zip it first then sideload
+ if (!options.zip && options.rootDir) {
+ await this.zip({ dir: options.rootDir, outDir: options.outDir, outFile: options.outFile, cwd: options.cwd });
+ options.retainDeploymentArchive = false;
+ }
+
//make sure the outDir exists
await fsExtra.ensureDir(options.outDir);
@@ -411,16 +440,16 @@ export class RokuDeploy {
}
/**
- * resign Roku Device with supplied pkg and
+ * resign Roku Device with a supplied signed pkg and
* @param options
*/
public async rekeyDevice(options: RekeyDeviceOptions) {
- this.checkRequiredOptions(options, ['host', 'password', 'rekeySignedPackage', 'signingPassword']);
+ this.checkRequiredOptions(options, ['host', 'password', 'pkg', 'signingPassword']);
options = this.getOptions(options) as any;
- let rekeySignedPackagePath = options.rekeySignedPackage;
- if (!path.isAbsolute(options.rekeySignedPackage)) {
- rekeySignedPackagePath = path.join(options.rootDir, options.rekeySignedPackage);
+ let pkgPath = options.pkg;
+ if (!path.isAbsolute(options.pkg)) {
+ pkgPath = path.join(options.rootDir, options.pkg);
}
let requestOptions = this.generateBaseRequestOptions('plugin_inspect', options as any, {
mysubmit: 'Rekey',
@@ -430,7 +459,7 @@ export class RokuDeploy {
let results: HttpResponse;
try {
- requestOptions.formData.archive = fsExtra.createReadStream(rekeySignedPackagePath);
+ requestOptions.formData.archive = fsExtra.createReadStream(pkgPath);
results = await this.doPostRequest(requestOptions);
} finally {
//ensure the stream is closed
@@ -885,7 +914,7 @@ export class RokuDeploy {
failOnCompileError: true,
deleteDevChannel: true,
packagePort: 80,
- remotePort: 8060,
+ ecpPort: 8060,
timeout: 150000,
rootDir: './',
files: [...DefaultFiles],
@@ -978,7 +1007,7 @@ export class RokuDeploy {
//try using the host as-is (it'll probably fail...)
}
- const url = `http://${options.host}:${options.remotePort}/query/device-info`;
+ const url = `http://${options.host}:${options.ecpPort}/query/device-info`;
let response;
try {
@@ -1021,7 +1050,7 @@ export class RokuDeploy {
* Get the External Control Protocol (ECP) setting mode of the device. This determines whether
* the device accepts remote control commands via the ECP API.
*
- * @param options - Configuration options including host, remotePort, timeout, etc.
+ * @param options - Configuration options including host, ecpPort, timeout, etc.
* @returns The ECP setting mode:
* - 'enabled': fully enabled and accepting commands
* - 'disabled': ECP is disabled (device may still be reachable but ECP commands won't work)
@@ -1235,7 +1264,7 @@ export interface GetDeviceInfoOptions {
/**
* The port to use to send the device-info request (defaults to the standard 8060 ECP port)
*/
- remotePort?: number;
+ ecpPort?: number;
/**
* The number of milliseconds at which point this request should timeout and return a rejected promise
*/
@@ -1254,7 +1283,7 @@ export interface SendKeyEventOptions {
host: string;
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
key: RokuKey | string;
- remotePort?: number;
+ ecpPort?: number;
timeout?: number;
}
@@ -1280,7 +1309,7 @@ export interface SendTextOptions extends SendKeyEventOptions {
export interface CloseChannelOptions {
host: string;
- remotePort?: number;
+ ecpPort?: number;
timeout?: number;
}
@@ -1292,7 +1321,7 @@ export interface StageOptions {
}
export interface ZipOptions {
- stagingDir?: string;
+ dir?: string;
outDir?: string;
outFile?: string;
cwd?: string;
@@ -1302,6 +1331,19 @@ export interface SideloadOptions {
appType?: 'channel' | 'dcl';
host: string;
password: string;
+ /**
+ * The path to an existing zip file to sideload. Takes precedence over `rootDir`.
+ */
+ zip?: string;
+ /**
+ * The root folder to zip and then sideload. Used when `zip` is not provided.
+ */
+ rootDir?: string;
+ /**
+ * Close the channel before sideloading. Defaults to true.
+ * Set to false to skip closing the channel.
+ */
+ close?: boolean;
remoteDebug?: boolean;
remoteDebugConnectEarly?: boolean;
failOnCompileError?: boolean;
@@ -1309,6 +1351,8 @@ export interface SideloadOptions {
outDir?: string;
outFile?: string;
deleteDevChannel?: boolean;
+ ecpPort?: number;
+ timeout?: number;
cwd?: string;
packageUploadOverrides?: PackageUploadOverridesOptions;
}
@@ -1334,7 +1378,7 @@ export interface ConvertToSquashfsOptions {
export interface RekeyDeviceOptions {
host: string;
password: string;
- rekeySignedPackage: string;
+ pkg: string;
signingPassword: string;
rootDir?: string;
devId: string;
@@ -1390,7 +1434,7 @@ export interface GetDevIdOptions {
/**
* The port to use to send the device-info request (defaults to the standard 8060 ECP port)
*/
- remotePort?: number;
+ ecpPort?: number;
/**
* The number of milliseconds at which point this request should timeout and return a rejected promise
*/
diff --git a/src/RokuDeployOptions.ts b/src/RokuDeployOptions.ts
index 8879ad3..99e87cb 100644
--- a/src/RokuDeployOptions.ts
+++ b/src/RokuDeployOptions.ts
@@ -84,7 +84,7 @@ export interface RokuDeployOptions {
* This is mainly useful for things like emulators that use alternate ports,
* or when sending commands through some type of port forwarding.
*/
- remotePort?: number;
+ ecpPort?: number;
/**
* The directory where screenshots should be saved. Will use the OS temp directory by default
@@ -118,7 +118,7 @@ export interface RokuDeployOptions {
/**
* Path to a copy of the signed package you want to use for rekeying
*/
- rekeySignedPackage?: string;
+ pkg?: string;
/**
* Dev ID we are expecting the device to have. If supplied we check that the dev ID returned after keying matches what we expected
diff --git a/src/cli.ts b/src/cli.ts
index e3975ba..d31010c 100755
--- a/src/cli.ts
+++ b/src/cli.ts
@@ -1,6 +1,5 @@
#!/usr/bin/env node
import * as yargs from 'yargs';
-import * as path from 'path';
import { SendTextCommand } from './commands/SendTextCommand';
import { StageCommand } from './commands/StageCommand';
import { SideloadCommand } from './commands/SideloadCommand';
@@ -28,7 +27,7 @@ void yargs
.option('password', { type: 'string', description: 'The password of the target Roku', demandOption: false })
.option('ecpPort', { type: 'number', description: 'The port to use for ECP commands (like pressing the home button)', demandOption: false })
.option('packagePort', { type: 'number', description: 'The port to use for sending a packaging to the device', demandOption: false })
- .option('noclose', { type: 'boolean', description: 'Should the command not close the channel before sideloading', demandOption: false })
+ .option('close', { type: 'boolean', description: 'Close the channel before sideloading. Use --no-close to skip.', demandOption: false })
.option('timeout', { type: 'number', description: 'The timeout for this command', demandOption: false })
.option('remoteDebug', { type: 'boolean', description: 'Should the command be run in remote debug mode', demandOption: false })
.option('remoteDebugConnectEarly', { type: 'boolean', description: 'Should the command connect to the debugger early', demandOption: false })
@@ -51,14 +50,6 @@ void yargs
.option('devId', { type: 'string', description: 'The dev ID', demandOption: false })
.option('cwd', { type: 'string', description: 'The current working directory to use for relative paths', demandOption: false });
}, (args: any) => {
- if (args.out) {
- if (!args.out.endsWith('.pkg')) {
- throw new Error('Out must end with a .pkg');
- }
- args.out = path.resolve(args.cwd, args.out);
- args.outDir = path.dirname(args.out);
- args.outFile = path.basename(args.out);
- }
return new CreateSignedPackageCommand().run(args);
})
@@ -69,9 +60,6 @@ void yargs
.option('ecpPort', { type: 'number', description: 'The port to use for ECP commands like remote key presses', demandOption: false })
.option('timeout', { type: 'number', description: 'The timeout for this command', demandOption: false });
}, (args: any) => {
- if (args.ecpPort) {
- args.remotePort = args.ecpPort;
- }
return new KeyPressCommand().run(args);
})
@@ -82,9 +70,6 @@ void yargs
.option('ecpPort', { type: 'number', description: 'The port to use for ECP commands like remote key presses', demandOption: false })
.option('timeout', { type: 'number', description: 'The timeout for this command', demandOption: false });
}, (args: any) => {
- if (args.ecpPort) {
- args.remotePort = args.ecpPort;
- }
return new KeyUpCommand().run(args);
})
@@ -95,9 +80,6 @@ void yargs
.option('ecpPort', { type: 'number', description: 'The port to use for ECP commands like remote key presses', demandOption: false })
.option('timeout', { type: 'number', description: 'The timeout for this command', demandOption: false });
}, (args: any) => {
- if (args.ecpPort) {
- args.remotePort = args.ecpPort;
- }
return new KeyDownCommand().run(args);
})
@@ -108,9 +90,6 @@ void yargs
.option('ecpPort', { type: 'number', description: 'The port to use for ECP commands like remote key presses', demandOption: false })
.option('timeout', { type: 'number', description: 'The timeout for this command', demandOption: false });
}, (args: any) => {
- if (args.ecpPort) {
- args.remotePort = args.ecpPort;
- }
return new SendTextCommand().run(args);
})
@@ -119,9 +98,6 @@ void yargs
.option('host', { type: 'string', description: 'The IP Address of the target Roku', demandOption: false })
.option('ecpPort', { type: 'number', description: 'The port to use for ECP commands like remote key presses', demandOption: false });
}, (args: any) => {
- if (args.ecpPort) {
- args.remotePort = args.ecpPort;
- }
return new RemoteControlCommand().run(args);
})
@@ -152,7 +128,6 @@ void yargs
.option('devId', { type: 'string', description: 'The dev ID', demandOption: false })
.option('cwd', { type: 'string', description: 'The current working directory to use for relative paths', demandOption: false });
}, (args: any) => {
- args.rekeySignedPackage = path.resolve(args.cwd, args.pkg);
return new RekeyDeviceCommand().run(args);
})
@@ -171,11 +146,6 @@ void yargs
.option('out', { type: 'string', description: 'The location where the screenshot will be saved relative to cwd', demandOption: false, defaultDescription: './out/roku-deploy.jpg' })
.option('cwd', { type: 'string', description: 'The current working directory to use for relative paths', demandOption: false });
}, (args: any) => {
- if (args.out) {
- args.out = path.resolve(args.cwd, args.out);
- args.screenshotDir = path.dirname(args.out);
- args.screenshotFile = path.basename(args.out);
- }
return new CaptureScreenshotCommand().run(args);
})
@@ -199,14 +169,6 @@ void yargs
.option('out', { type: 'string', description: 'the path to the zip file that will be created, relative to cwd', demandOption: false, alias: 'outZip' })
.option('cwd', { type: 'string', description: 'The current working directory to use for relative paths', demandOption: false });
}, (args: any) => {
- if (args.out) {
- args.out = path.resolve(args.cwd, args.out);
- args.outDir = path.dirname(args.out);
- args.outFile = path.basename(args.out);
- }
- if (args.dir) {
- args.stagingDir = path.resolve(args.cwd, args.dir);
- }
return new ZipCommand().run(args);
})
diff --git a/src/commands/CaptureScreenshotCommand.ts b/src/commands/CaptureScreenshotCommand.ts
index 6a75ed5..bedf22a 100644
--- a/src/commands/CaptureScreenshotCommand.ts
+++ b/src/commands/CaptureScreenshotCommand.ts
@@ -1,11 +1,19 @@
import { rokuDeploy, util } from '../index';
+import * as path from 'path';
export class CaptureScreenshotCommand {
async run(args) {
+ args.cwd ??= process.cwd();
+
let options = {
...util.getOptionsFromJson(args),
...args
};
+ if (args.out) {
+ args.out = path.resolve(args.cwd, args.out);
+ options.screenshotDir = path.dirname(args.out);
+ options.screenshotFile = path.basename(args.out);
+ }
await rokuDeploy.captureScreenshot(options);
}
}
diff --git a/src/commands/CreateSignedPackageCommand.ts b/src/commands/CreateSignedPackageCommand.ts
index 904a9fe..4571975 100644
--- a/src/commands/CreateSignedPackageCommand.ts
+++ b/src/commands/CreateSignedPackageCommand.ts
@@ -1,11 +1,22 @@
import { rokuDeploy, util } from '../index';
+import * as path from 'path';
export class CreateSignedPackageCommand {
async run(args) {
+ args.cwd ??= process.cwd();
+
let options = {
...util.getOptionsFromJson(args),
...args
};
+ if (args.out) {
+ if (!args.out.endsWith('.pkg')) {
+ throw new Error('Out must end with a .pkg');
+ }
+ args.out = path.resolve(args.cwd, args.out);
+ options.outDir = path.dirname(args.out);
+ options.outFile = path.basename(args.out);
+ }
await rokuDeploy.createSignedPackage(options);
}
}
diff --git a/src/commands/RekeyDeviceCommand.ts b/src/commands/RekeyDeviceCommand.ts
index ca00fd8..b07ae56 100644
--- a/src/commands/RekeyDeviceCommand.ts
+++ b/src/commands/RekeyDeviceCommand.ts
@@ -1,11 +1,17 @@
import { rokuDeploy, util } from '../index';
+import * as path from 'path';
export class RekeyDeviceCommand {
async run(args) {
+ args.cwd ??= process.cwd();
+
let options = {
...util.getOptionsFromJson(args),
...args
};
+ if (args.pkg) {
+ options.pkg = path.resolve(args.cwd, args.pkg);
+ }
await rokuDeploy.rekeyDevice(options);
}
}
diff --git a/src/commands/SideloadCommand.ts b/src/commands/SideloadCommand.ts
index c488b32..f35775d 100644
--- a/src/commands/SideloadCommand.ts
+++ b/src/commands/SideloadCommand.ts
@@ -1,47 +1,24 @@
import { rokuDeploy, util } from '../index';
-import type { CloseChannelOptions } from '../RokuDeploy';
import * as path from 'path';
export class SideloadCommand {
async run(args) {
+ args.cwd ??= process.cwd();
+
let options = {
...util.getOptionsFromJson(args),
...args
};
- // Process args so that they can be compatible with the RokuDeploy
- args.cwd ??= process.cwd();
if (args.zip) {
- args.zip = path.resolve(args.cwd, args.zip);
- options.outDir = path.dirname(args.zip);
- options.outFile = path.basename(args.zip);
+ options.zip = path.resolve(args.cwd, args.zip);
}
if (args.rootDir) {
options.rootDir = path.resolve(args.cwd, args.rootDir);
}
-
if (args.outZip) {
options.outZip = path.resolve(args.cwd, args.outZip);
}
-
- if (args.ecpPort) {
- options.remotePort = args.ecpPort;
- }
-
- if (args.noclose !== true) {
- await rokuDeploy.closeChannel(options as CloseChannelOptions);
- }
-
-
- if (args.zip) {
- options.retainDeploymentArchive = true;
- await rokuDeploy.sideload(options);
- } else if (args.rootDir) {
- await rokuDeploy.zip(options);
- options.retainDeploymentArchive = false;
- await rokuDeploy.sideload(options);
- } else {
- throw new Error('Either zip or rootDir must be provided for sideload command');
- }
+ await rokuDeploy.sideload(options);
}
}
diff --git a/src/commands/StageCommand.ts b/src/commands/StageCommand.ts
index 8cdf460..5f45796 100644
--- a/src/commands/StageCommand.ts
+++ b/src/commands/StageCommand.ts
@@ -6,6 +6,9 @@ export class StageCommand {
...util.getOptionsFromJson(args),
...args
};
+ if (options.out) {
+ options.stagingDir = options.out;
+ }
await rokuDeploy.stage(options);
}
}
diff --git a/src/commands/ZipCommand.ts b/src/commands/ZipCommand.ts
index b03e80d..183c7aa 100644
--- a/src/commands/ZipCommand.ts
+++ b/src/commands/ZipCommand.ts
@@ -1,11 +1,22 @@
import { rokuDeploy, util } from '../index';
+import * as path from 'path';
export class ZipCommand {
async run(args) {
+ args.cwd ??= process.cwd();
+
let options = {
...util.getOptionsFromJson(args),
...args
};
+ if (args.out) {
+ args.out = path.resolve(args.cwd, args.out);
+ options.outDir = path.dirname(args.out);
+ options.outFile = path.basename(args.out);
+ }
+ if (args.dir) {
+ options.dir = path.resolve(args.cwd, args.dir);
+ }
await rokuDeploy.zip(options);
}
}