Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

roku-deploy

RokuCommunity16.3kMIT3.12.4TypeScript support: included

Package and publish a Roku application using Node.js

readme

roku-deploy

Publish Roku projects to a Roku device by using Node.js.

build status coverage status monthly downloads npm version license Slack

Installation

npm install roku-deploy

Requirements

  1. Your project must be structured the way that Roku expects. The source files can be in a subdirectory (using the rootDir config option), but whever your roku files exist, they must align with the following folder structure:

    components/ images/ source/ manifest

  2. You should create a rokudeploy.json file at the root of your project that contains all of the overrides to the default options. roku-deploy will auto-detect this file and use it when possible. (note: rokudeploy.json is jsonc, which means it supports comments).

sample rokudeploy.json

{
    "host": "192.168.1.101",
    "password": "securePassword"
}

Usage

From a node script

var rokuDeploy = require('roku-deploy');

//deploy a .zip package of your project to a roku device
rokuDeploy.deploy({
    host: 'ip-of-roku',
    password: 'password for roku dev admin portal'
    //other options if necessary
}).then(function(){
    //it worked
}, function(error) {
    //it failed
    console.error(error);
});

Or

//create a signed package of your project
rokuDeploy.deployAndSignPackage({
    host: 'ip-of-roku',
    password: 'password for roku dev admin portal',
    signingPassword: 'signing password'
    //other options if necessary
}).then(function(pathToSignedPackage){
    console.log('Signed package created at ', pathToSignedPackage);
}, function(error) {
    //it failed
    console.error(error);
});

Copying the files to staging

If you'd like to use roku-deploy to copy files to a staging folder, you can do the following:

rokuDeploy.prepublishToStaging({
    rootDir: "folder/with/your/source/code",
    stagingDir: 'path/to/staging/folder',
    files: [
        "source/**/*",
        "components/**/*",
        "images/**/*",
        "manifest"
    ],
    //...other options if necessary
}).then(function(){
    //the files have been copied to staging
}, function(error) {
    //it failed
    console.error(error);
});

Creating a zip from an already-populated staging folder

Use this logic if you'd like to create a zip from your application folder.

/create a signed package of your project
rokuDeploy.zipPackage({
    outDir: 'folder/to/put/zip',
    stagingDir: 'path/to/files/to/zip',
    outFile: 'filename-of-your-app.zip'
    //...other options if necessary
}).then(function(){
    //the zip has been created
}, function(error) {
    //it failed
    console.error(error);
});

Deploying an existing zip

If you've already created a zip using some other tool, you can use roku-deploy to sideload the zip.

/create a signed package of your project
rokuDeploy.publish({
    host: 'ip-of-roku',
    password: 'password for roku dev admin portal',
    outDir: 'folder/where/your/zip/resides/',
    outFile: 'filename-of-your-app.zip'
    //...other options if necessary
}).then(function(){
    //the app has been sideloaded
}, function(error) {
    //it failed
    console.error(error);
});

running roku-deploy as an npm script

From an npm script in package.json. (Requires rokudeploy.json to exist at the root level where this is being run)

{
    "scripts": {
        "deploy": "roku-deploy"
    }
}

You can provide a callback in any of the higher level methods, which allows you to modify the copied contents before the package is zipped. An info object is passed in with the following attributes

  • manifestData: [key: string]: string Contains all the parsed values from the manifest file
  • stagingDir: string Path to staging folder to make it so you only need to know the relative path to what you're trying to modify

      let options = {
          host: 'ip-of-roku',
          password: 'password for roku dev admin portal'
          //other options if necessary
      };
    
      rokuDeploy.deploy(options, (info) => {
          //modify staging dir before it's zipped.
          //At this point, all files have been copied to the staging directory.
          manipulateFilesInStagingFolder(info.stagingDir)
          //this function can also return a promise,
          //which will be awaited before roku-deploy starts deploying.
      }).then(function(){
          //it worked
      }, function(){
          //it failed
      });

bsconfig.json

Another common config file is bsconfig.json, used by the BrighterScript project and the BrightScript extension for VSCode. Since many of the config settings are shared between roku-deploy.json and bsconfig.json, roku-deploy supports reading from that file as well. Here is the loading order:

  • if roku-deploy.json is found, those settings are used.
  • if roku-deploy.json is not found, look for bsconfig.json and use those settings.

Note that When roku-deploy is called from within a NodeJS script, the options passed into the roku-deploy methods will override any options found in roku-deploy.json and bsconfig.json.

Files Array

The files array is how you specify what files are included in your project. Any strings found in the files array must be relative to rootDir, and are used as include filters, meaning that if a file matches the pattern, it is included.

For most standard projects, the default files array should work just fine:

{
    "files": [
        "source/**/*",
        "components/**/*",
        "images/**/*",
        "manifest"
    ]
}

This will copy all files from the standard roku folders directly into the package while maintaining each file's relative file path within rootDir.

If you want to include additonal files, you will need to provide the entire array. For example, if you have a folder with other assets, you could do the following:

{
    "files": [
        "source/**/*",
        "components/**/*",
        "images/**/*",
        "manifest"
        //your folder with other assets
        "assets/**/*",
    ]
}

Excluding Files

You can also prefix your file patterns with "!" which will exclude files from the output. This is useful in cases where you want everything in a folder EXCEPT certain files. The files array is processed top to bottom. Here's an example:

{
    "files": [
        "source/**/*",
        "!source/some/unwanted/file.brs"
    ]
}

Top-level String Rules

  • All patterns will be resolved relative to rootDir, with their relative positions within rootDir maintained.

  • No pattern may reference a file outside of rootDir. (You can use {src;dest} objects to accomplish) For example:

      {
          "rootDir": "C:/projects/CatVideoPlayer",
          "files": [
              "source/main.brs",
    
              //NOT allowed because it navigates outside the rootDir
              "../common/promise.brs"
          ]
      }
  • Any valid glob pattern is supported. See glob on npm for more information.

  • Empty folders are not copied

  • Paths to folders will be ignored. If you want to copy a folder and its contents, use the glob syntax (i.e. some_folder/**/*)

Advanced Usage

For more advanced use cases, you may provide an object which contains the source pattern and output path. This allows you to get very specific about what files to copy, and where they are placed in the output folder. This option also supports copying files from outside the project.

The object structure is as follows:

{
    /**
     * a glob pattern string or file path, or an array of glob pattern strings and/or file paths.
     * These can be relative paths or absolute paths.
     * All non-absolute paths are resolved relative to the rootDir
     */
    src: Array<string|string[]>;
    /**
     * The relative path to the location in the output folder where the files should be placed, relative to the root of the output folder
     */
    dest: string|undefined
}

{ src; dest } Object Rules

  • if src is a non-glob path to a single file, then dest should include the filename and extension. For example: { src: "lib/Promise/promise.brs", dest: "source/promise.brs"}

  • if src is a glob pattern, then dest should be a path to the folder in the output directory. For example: { src: "lib/*.brs", dest: "source/lib"}

  • if src is a glob pattern that includes **, then all files found in src after the ** will retain their relative paths in src when copied to dest. For example: { src: "lib/**.brs", dest: "source/lib"}

  • if src is a path to a folder, it will be ignored. If you want to copy a folder and its contents, use the glob syntax. The following example will copy all files from the lib/vendor folder recursively: { src: "lib/vendor/**/*", dest: "vendor" }

  • if dest is not specified, the root of the output folder is assumed

    Collision Handling

    roku-deploy processes file entries in order, so if you want to override a file, just make sure the one you want to keep is later in the files array

For example, if you have a base project, and then a child project that wants to override specific files, you could do the following:

{
    "files": [
        {
            //copy all files from the base project
            "src": "../BaseProject/**/*"
        },
        //override "../BaseProject/themes/theme.brs" with "${rootDir}/themes/theme.brs"
        "themes/theme.brs"
    ]
}

roku-deploy Options

Here are the available options. The defaults are shown to the right of the option name, but all can be overridden:

  • host: string (required) The IP address or hostname of the target Roku device. Example: "192.168.1.21"

  • password: string (required) The password for logging in to the developer portal on the target Roku device

  • signingPassword: string (required for signing) The password used for creating signed packages

  • rekeySignedPackage: string (required for rekeying) Path to a copy of the signed package you want to use for rekeying

  • devId: 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

  • outDir?: string = "./out" A full path to the folder where the zip/pkg package should be placed

  • outFile?: string = "roku-deploy" The base filename the zip/pkg file should be given (excluding the extension)

  • rootDir?: string = './' The root path to the folder holding your project. The manifest file should be directly underneath this folder. Use this option when your roku project is in a subdirectory of where roku-deploy is installed.

  • files?: ( string | { src: string; dest: string; } ) [] =

      [
          "source/**/*.*",
          "components/**/*.*",
          "images/**/*.*",
          "manifest"
      ]

    An array of file paths, globs, or {src:string;dest:string} objects that will be copied into the deployment package.

    Using the {src;dest} objects will allow you to move files into different destination paths in the deployment package. This would be useful for copying environment-specific configs into a common config location (i.e. copy from "ProjectRoot\configs\dev.config.json" to "roku-deploy.zip\config.json"). Here's a sample:

      //deploy configs/dev.config.json as config.json
      {
          "src": "configs/dev.config.json",
          "dest": "config.json"
      }
      //you can omit the filename in dest if you want the file to keep its name. Just end dest with a trailing slash.
      {
          "src": "languages/english/language.xml",
          "dest": "languages/"
      }
    

    This will result in the [sourceFolder]/configs/dev.config.json file being copied to the zip file and named "config.json".

You can also provide negated globs (thanks to [glob-all](https://www.npmjs.com/package/glob-all)). So something like this would include all component files EXCEPT for specs.
```
files: [
    'components/**/*.*',
    '!components/**/*.spec.*'
]
```

*NOTE:* If you override this "files" property, you need to provide **all** config values, as your array will completely overwrite the default.
  • retainStagingFolder?: boolean = false Set this to true to prevent the staging folder from being deleted after creating the package. This is helpful for troubleshooting why your package isn't being created the way you expected.

  • stagingDir?: string = `${options.outDir}/.roku-deploy-staging` The path to the staging folder (where roku-deploy places all of the files right before zipping them up).

  • convertToSquashfs?: boolean = false If true we convert to squashfs before creating the pkg file

  • incrementBuildNumber?: boolean = false If true we increment the build number to be a timestamp in the format yymmddHHMM

  • username?: string = "rokudev" The username for the roku box. This will always be 'rokudev', but allow to be passed in just in case roku adds support for custom usernames in the future

  • packagePort?: string = 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.

  • remotePort?: string = 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.

  • remoteDebug?: boolean = false When publishing a side loaded channel this flag can be used to enable the socket based BrightScript debug protocol. This should always be false unless you're creating a plugin for an editor such as VSCode, Atom, Sublime, etc. More information on the BrightScript debug protocol can be found here: https://developer.roku.com/en-ca/docs/developer-program/debugging/socket-based-debugger.md

  • deleteInstalledChannel?: boolean = true If true the previously installed dev channel will be deleted before installing the new one

Click here to see the typescript interface for these options

Troubleshooting

  • if you see a ESOCKETTIMEDOUT error during deployment, this can be caused by an antivirus blocking network traffic, so consider adding a special exclusion for your Roku device.

Changelog

Click here to view the changelog

changelog

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

3.12.4 - 2025-01-22

Fixed

  • fixed an issue with 577 error codes (#182)

3.12.3 - 2024-12-06

Changed

  • Identify when a 577 error is thrown, send a new developer friendly message (#180)

    Fixed

  • issues with detecting "check for updates required" (#181)

3.12.2 - 2024-10-18

Fixed

  • updated regex to find a signed package on /plugin_package page (#176)

3.12.1 - 2024-07-19

Changed

  • fix-node14 CI/CD issues (#165)

    Fixed

  • bug with absolute paths and getDestPath (#171)

3.12.0 - 2024-03-01

Changed

  • Support overriding various package upload form data (#136)

3.11.3 - 2024-02-29

Fixed

  • Retry the convertToSquahsfs request to mitigate the HPE_INVALID_CONSTANT error (#145)

3.11.2 - 2023-12-20

Changed

  • Update wrong host password error message (#134)

3.11.1 - 2023-11-30

Fixed

  • Wait for file stream to close before resolving promise (#133)

3.11.0 - 2023-11-28

Changed

  • Add public function normalizeDeviceInfoFieldValue to normalize device-info field values (#129)

3.10.5 - 2023-11-14

Changed

  • better device-info docs (#128)
  • Better deploy error detection (#127)

3.10.4 - 2023-11-03

Changed

  • Enhance getDeviceInfo() method to support camelCase and convert bool|number strings to their primitive types (#120)

3.10.3 - 2023-07-22

Changed

  • Bump word-wrap from 1.2.3 to 1.2.4 (#117)

3.10.2 - 2023-05-10

Changed

  • remove request in favor of postman-request to fix security issues
  • remove dev dependency coveralls in favor of coveralls-next to fix security issues

    Fixed

  • compatibility issues with Node.js v19 and above (#115)
  • npm audit issues (#116)

3.10.1 - 2023-04-14

Changed

  • Bump xml2js from 0.4.23 to 0.5.0 (#112)
  • Fix build status badge (ad2c9ec)

3.10.0 - 2023-03-16

Changed

  • Use micromatch instead of picomatch (#109)

3.9.3 - 2023-01-12

Changed

  • Bump minimatch from 3.0.4 to 3.1.2 (#107)
  • Bump json5 from 2.2.0 to 2.2.3 (#106)

3.9.2 - 2022-10-03

Fixed

  • Replace minimatch with picomatch (#101)

3.9.1 - 2022-09-19

Fixed

  • Sync retainStagingFolder, stagingFolderPath with options, fixing a critical backwards compatibility bug (#100)

3.9.0 - 2022-09-16

Added

  • Add stagingDir and retainStagingDir. (#99)

    Changed

  • deprecated stagingFolderPath and `retainStagingFolder. (#99)

3.8.1 - 2022-09-02

Changed

  • Bump moment from 2.29.2 to 2.29.4 (#98)

3.8.0 - 2022-08-30

Added

  • add support for remotedebug_connect_early form field (#97)
  • Better compile error handling (#96)

3.7.1 - 2022-06-08

Fixed

  • make the json parser less sensitive to trailing commas (#95)

3.7.0 - 2022-05-23

Added

  • new files parameter to zipFolder() to allow including/excluding files when building the zip
  • new rokuDeploy.takeScreenshot() function (#92)
  • export rokuDeploy const to improve the docs. Developers should switch to import { rokuDeploy } from 'roku-deploy' instead of import * as rokuDeploy from 'roku-deploy'.

3.6.0 - 2022-04-13

Added

  • deleteInstalledChannel option to specify whether the previously installed dev channel will be deleted before installing the new one

3.5.4 - 2022-03-17

Changed

  • use fast-glob instead of glob for globbing. (#86)

    Fixed

  • significant performance issues during globbing. (#86)

3.5.3 - 2022-02-16

Fixed

  • removed request property from RokuDeploy class that was only there for unit testing, and was causing typescript issues in downstream dependencies. (#84)

3.5.2 - 2021-11-02

Fixed

  • bug introduced in v3.5.0 with retrieveSignedPackage that would produce an empty package. (#82)

3.5.1 - 2021-11-02

Fixed

  • bug introduced in v3.5.0 with rekeyDevice that would crash because the read stream was closed before the request got sent. (#81)

3.5.0 - 2021-10-27

Added

  • ability to use negated non-rootDir top-level patterns in the files array (#78)

3.4.2 - 2021-09-17

Fixed

3.4.1 - 2021-06-01

Fixed

  • incorrect path separator issue on windows.
  • missing chalk prod dependency causing import issues

3.4.0 - 2021-05-28

Added

  • preFileZipCallback parameter to RokuDeploy.zipFolder to allow per-file modifications before adding the file to the zip

    Changed

  • switch internal zip library to jszip which seems to yield 75% faster zip times.

3.3.0 - 2021-02-05

Added

  • support for timeout option to fail deploys after a certain amount of time

3.2.4 - 2021-01-08

Fixed

  • don't fail deployment when home press command returns 202 http status code

3.2.3 - 2020-08-14

Changed

  • throw exception during copyToStaging when rootDir does not exist
  • throw exception during zipPackage when ${stagingFolder}/manifest does not exist

3.2.2 - 2020-07-14

Fixed

  • bug when loading stagingFolderPath from rokudeploy.json or bsconfig.json that would cause an exception.

3.2.1 - 2020-07-07

Changed

  • rokudeploy.json now supports jsonc (json with comments)

    Fixed

  • loading bsconfig.json file with comments would fail the entire roku-deploy process.

3.2.0 - 2020-07-06

Added

  • support for loading bsconfig.json files.

3.1.1 - 2020-05-08

Added

  • export DefaultFilesArray so other tools can use that as their defaults as well.

3.1.0 - 2020-05-08

Added

  • config setting retainDeploymentArchive which specifies if the zip should be deleted after a publish.

3.0.2 - 2020-04-10

Fixed

  • issue where prepublishToStaging wasn't recognizing nested files inside a symlinked folder.

3.0.1 - 2020-04-03

Changed

  • coerce rootDir to an absolute path in rokuDeploy.getDestPath and rokuDeploy.getFilePaths.

3.0.0 - 2020-03-23

Added

  • all changes from v3.0.0-beta1-v3.0.0-beta.8

3.0.0-beta.8 - 2020-03-06

Added

  • all changes from 2.7.0

2.7.0 - 2020-03-06

Added

  • support for remoteDebug property which enables the experimental remote debug protocol on newer versions of Roku hardware. See this for more information.

3.0.0-beta.7 - 2020-01-10

Fixed

  • bug during file copy that was not prepending stagingFolderPath to certain file operations.

3.0.0-beta.6 - 2020-01-06

Fixed

  • bug that was not discarding duplicate file entries targeting the same dest path.

3.0.0-beta.5 - 2019-12-20

Added

  • all changes from 2.6.1

3.0.0-beta.4 - 2019-11-12

Added

  • all changes from 2.6.0

3.0.0-beta.3 - 2019-11-12

Added

  • RokuDeploy.getDestPath function which returns the dest path for a full file path. Useful for figuring out where a file will be placed in the pkg.

    Changed

  • made RokuDeploy.normalizeFilesArray public
  • disallow using explicit folder paths in files array. You must use globs for folders.

3.0.0-beta.2 - 2019-10-23

Changed

  • signature of getFilePaths() to no longer accept stagingFolderPath
  • getFilePaths() now returns dest file paths relative to pkg instead of absolute file paths. These paths do not include a leading slash

3.0.0-beta.1 - 2019-10-16

Added

  • information in the readme about the files array
  • support for file overrides in the files array. This supports including the same file from A and B, and letting the final file override previous files.

    Changed

  • the files array is now a bit more strict, and has a more consistent approach.

    [2.6.1] - 2019-12-20

    Fixed

  • Throw better error message during publish when missing the zip file.

2.6.0 - 2019-12-04

Added

  • remotePort and packagePort for customizing the ports used for network-related roku requests. Mainly useful for emulators or communicating with Rokus behind port-forwards.

2.6.0-beta.0 - 2019-11-18

Added

  • remotePort and packagePort for customizing the ports used for network-related roku requests. Mainly useful for emulators or communicating with Rokus behind port-forwards.

2.5.0 - 2019-10-05

Added

  • stagingFolderPath option to allow overriding the location of the staging folder

2.4.1 - 2019-08-27

Changed

2.4.0 - 2019-08-26

Added

  • deleteInstalledChannel method that will delete the installed channel on the remote Roku

    Changed

  • deploy now deletes any installed channel before publishing the new channel

2.3.0 - 2019-08-20

Added

  • support for returning a promise in the createPackage beforeZipCallback parameter.

2.2.1 - 2019-08-07

Fixed

  • colors starting with # symbol in manifest file that were being treated as comments. This removes the dependency on ini in favor of a local function.

2.2.0 - 2019-07-05

Added

  • support for converting to squashfs

    Fixed

  • issue where manifest files with bs_const weren't being handled correctly

2.1.0 - 2019-05-14

Added

  • rekeying capability

2.1.0-beta1 - 2019-02-15

Added

  • Support for signed package creation
  • ability to register a callback function before the package is zipped.
  • incrementBuildNumber option

    Changed

  • Stop calling home button on deploy
  • outFile to be baseName so it can be used for both zip and pkg file names

2.0.0 - 2019-01-07

Added

  • support for absolute file paths in the files property
  • dereference symlinks on file copy

2.0.0-beta5 - 2019-01-18

Changed

  • Changed normalizeFilesOption to be sync instead of async, since it didn't need to be async.

2.0.0-beta4 - 2019-01-17

Fixed

  • bug that wasn't using rootDir for glob matching

2.0.0-beta3 - 2019-01-17

Changed

  • export the getFilepaths for use in external libraries

2.0.0-beta2 - 2019-01-15

Changed

  • prevent empty directories from being created

    Fixed

  • bug in src/dest globs.
  • bug that wasn't copying folders properly

2.0.0-beta1 - 2019-01-07

Changed

  • removed the requirement for manifest to be located at the top of rootDir. Instead, it is simply assumed to exist.

    Fixed

  • regression issue that prevented folder names from being used without globs

1.0.0 - 2018-12-18

Added

  • support for negated globs