# Using the brs-node Library
This guide explains how to use the `brs-node` library in your Node.js applications and testing environments. The library provides programmatic access to the **BrightScript Simulation Engine**, allowing you to execute BrightScript code, run Roku applications, and test your BrightScript implementations.
## Table of Contents
- [Using the brs-node Library](#using-the-brs-node-library)
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Using in Node.js Applications](#using-in-nodejs-applications)
- [Basic Setup](#basic-setup)
- [Executing BrightScript Files](#executing-brightscript-files)
- [Complete Example](#complete-example)
- [Executing BrightScript from In-Memory Files](#executing-brightscript-from-in-memory-files)
- [SceneGraph App Example](#scenegraph-app-example)
- [Using the REPL Interpreter](#using-the-repl-interpreter)
- [Handling Callbacks](#handling-callbacks)
- [Working with SharedArrayBuffer](#working-with-sharedarraybuffer)
- [Using in Tests](#using-in-tests)
- [Setting up Jest Tests](#setting-up-jest-tests)
- [Testing with E2E Helper Functions](#testing-with-e2e-helper-functions)
- [Testing Best Practices](#testing-best-practices)
- [1. Reset File System Between Tests](#1-reset-file-system-between-tests)
- [2. Use Fake Timers for Time-Dependent Tests](#2-use-fake-timers-for-time-dependent-tests)
- [3. Test with Deep Links](#3-test-with-deep-links)
- [API Reference](#api-reference)
- [Core Functions](#core-functions)
- [`registerCallback(callback, sharedBuffer?)`](#registercallbackcallback-sharedbuffer)
- [`createPayloadFromFiles(files, device, deepLink?, root?, ext?)`](#createpayloadfromfilesfiles-device-deeplink-root-ext)
- [`createPayloadFromFileMap(fileMap, device, deepLink?)`](#createpayloadfromfilemapfilemap-device-deeplink)
- [`executeFile(payload, options?)`](#executefilepayload-options)
- [`getReplInterpreter(options)`](#getreplinterpreteroptions)
- [`executeLine(line, interpreter)`](#executelineline-interpreter)
- [File System API](#file-system-api)
- [`BrsDevice.fileSystem.resetMemoryFS()`](#brsdevicefilesystemresetmemoryfs)
- [Additional Resources](#additional-resources)
- [Support](#support)
---
## Installation
Install the package via npm:
```bash
npm install brs-node
```
Or using yarn:
```bash
yarn add brs-node
```
---
## Using in Node.js Applications
### Basic Setup
Import the library in your Node.js application:
```javascript
const brs = require("brs-node");
```
Or using ES6 imports (TypeScript):
```typescript
import * as brs from "brs-node";
```
### Executing BrightScript Files
The library provides several functions to execute BrightScript code. The main workflow involves:
1. Creating a payload from your BrightScript files
2. Registering a callback to handle output and events
3. Executing the payload
#### Complete Example
```javascript
const brs = require("brs-node");
const fs = require("fs");
const path = require("path");
// Register a callback to handle interpreter messages
brs.registerCallback((message, data) => {
if (typeof message === "string") {
const [messageType, content] = message.split(",", 2);
switch (messageType) {
case "print":
console.log(content);
break;
case "warning":
console.warn(content);
break;
case "error":
console.error(content);
break;
case "end":
console.log(`Execution finished: ${content}`);
break;
}
} else if (message instanceof Map) {
// Registry updates
console.log("Registry updated:", message);
}
});
// Define device configuration
const deviceData = {
developerId: "34c6fceca75e456f25e7e99531e2425c6c1de443",
friendlyName: "BrightScript Test Device",
deviceModel: "8000X",
clientId: "6c5bf3a5-b2a5-4918-824d-7691d5c85364",
RIDA: "f51ac698-bc60-4409-aae3-8fc3abc025c4",
countryCode: "US",
timeZone: "US/Eastern",
locale: "en_US",
clockFormat: "12h",
displayMode: "1080p",
customFeatures: [],
localIps: ["192.168.1.100"],
};
// Create payload from BrightScript files
const files = [
path.join(__dirname, "main.brs"),
path.join(__dirname, "lib", "utils.brs")
];
const payload = brs.createPayloadFromFiles(
files,
deviceData,
new Map(), // deepLink parameters (optional)
"/path/to/pkg/root", // root directory for pkg:/ (optional)
"/path/to/ext/root" // root directory for ext1:/ (optional)
);
// Execute the payload
(async () => {
try {
const result = await brs.executeFile(payload);
console.log(`Exit reason: ${result.exitReason}`);
// Handle encrypted package generation if password was provided
if (result.exitReason === "PACKAGED") {
console.log("Package encrypted successfully");
// Save the encrypted package
const encryptedData = new Uint8Array(result.cipherText);
fs.writeFileSync("app.bpk", encryptedData);
}
} catch (error) {
console.error("Execution failed:", error);
}
})();
```
### Executing BrightScript from In-Memory Files
You can also create a payload from in-memory file content using `createPayloadFromFileMap`. This is useful when working with uploaded files, network resources, or dynamically generated content:
```javascript
const brs = require("brs-node");
// Register callback (same as above)
brs.registerCallback((message) => {
// Handle messages...
});
// Create file map with Blob content
const fileMap = new Map();
// Add BrightScript source files
const mainBrsCode = `
sub Main()
print "Hello from in-memory BrightScript!"
print "Device model: "; CreateObject("roDeviceInfo").GetModel()
end sub
`;
fileMap.set("main.brs", new Blob([mainBrsCode], { type: "text/plain" }));
// Add manifest file
const manifestContent = `
title=My In-Memory App
major_version=1
minor_version=0
build_version=1
`;
fileMap.set("manifest", new Blob([manifestContent], { type: "text/plain" }));
// Add additional library file
const libCode = `
function GetAppVersion() as string
return "1.0.1"
end function
`;
fileMap.set("lib/utils.brs", new Blob([libCode], { type: "text/plain" }));
// Execute the in-memory files
(async () => {
try {
// Create payload from file map
const payload = await brs.createPayloadFromFileMap(fileMap, deviceData);
// Execute the payload
const result = await brs.executeFile(payload);
console.log(`Exit reason: ${result.exitReason}`);
} catch (error) {
console.error("Execution failed:", error);
}
})();
```
#### SceneGraph App Example
For SceneGraph applications, organize files in the proper folder structure:
```javascript
const fileMap = new Map();
// Manifest for SceneGraph app
const manifest = `
title=My SceneGraph App
major_version=1
minor_version=0
ui_resolutions=hd
splash_min_time=0
`;
fileMap.set("manifest", new Blob([manifest], { type: "text/plain" }));
// Main application source (executed)
const mainCode = `
sub Main()
print "SceneGraph app starting..."
screen = CreateObject("roSGScreen")
m.port = CreateObject("roMessagePort")
screen.setMessagePort(m.port)
scene = screen.CreateScene("MainScene")
screen.show()
print "Scene created and displayed"
' Event loop
while true
msg = wait(1000, m.port)
if msg <> invalid
if msg.isScreenClosed()
exit while
end if
else
exit while ' Timeout for demo
end if
end while
end sub
`;
fileMap.set("source/main.brs", new Blob([mainCode], { type: "text/plain" }));
// Scene component XML (packaged, not executed)
const sceneXml = `