npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@signageos/supra-screen

v1.0.0

Published

signageOS applet

Readme

Supra Screen

Supra Screen applet for signageOS — starts the Supra daemon, manages the screen app process (reuse/restart), and attaches the screen renderer. Built on top of the @supraio/client-sdk daemon SDK.

Build Targets

This project produces three targets:

  1. Applet (npm run build) — a signageOS applet bundle (dist/index.html + assets) that can be uploaded to Box and deployed to devices as-is. The entry point (src/index.ts) simply instantiates the SDK and starts it.
  2. SDK bundle (npm run build:sdk) — a UMD bundle (dist-sdk/supra-screen-sdk.js) exposing the public SDK surface (src/sdk.ts). SDK-owned dependencies are bundled in, so it can be dropped into a signageOS applet via a <script> tag. The host applet must provide one initialized @signageos/front-applet runtime through window.sos.
  3. SDK ES6 modules (npm run build:sdk:es6) — plain TypeScript transpilation of src/ into es6/ (ES6 target, CommonJS modules, no bundling), including .d.ts declarations and source maps. This is the target consumers should import from when they do their own bundling and tree-shaking, mirroring the es6/ output of @signageos/front-applet and @signageos/front-display.

Both SDK targets are built together by npm run clean-build:sdk.

Native Runtime Assets

SupraScreen depends on native binaries and runtime assets that cannot be bundled into a JavaScript module: WASM binaries (supra-client-daemon.wasm, supra-client-screen.wasm, samsung-wasm-decoder.wasm), the conditional H.264 fallback (h264decoder.js), NaCl executables (nacl-decoder_*.nexe), Web Workers (samsung-wasm-decoder.worker.js), and pre-built polyfills (polyfill.js, encoding.js). These files must be served at the document root alongside the applet's index.html.

The authoritative list lives in tools/native-assets.js (17 entries). During the applet build, webpack copies them from node_modules into dist/, then transpile and monkey-patch post-process several of them. That finalized dist/ directory ships in the npm package and is also the CLI's source. SDK consumers never need to locate or process raw dependency files.

Build integration (one line)

Add the copy step after your bundler finishes:

# In package.json scripts (the binary is resolved from node_modules/.bin):
"build": "webpack --mode production && supra-screen copy-assets --to dist"

# Or run directly via npm exec:
npm exec supra-screen -- copy-assets --to dist

The CLI copies all 17 native assets into the specified directory, creating it recursively if needed. Existing files are overwritten deterministically so rebuilds are idempotent. The source assets are resolved relative to the installed @signageos/supra-screen package (not the consumer's working directory), so no additional configuration is needed.

Direct CLI usage

supra-screen copy-assets --to <directory>
supra-screen --help

The copy-assets command exits nonzero with a descriptive message when:

  • the command or --to flag is missing
  • the destination cannot be created
  • a packaged source asset is missing (indicates a broken package build)

Why no postinstall?

A postinstall script would couple the copy destination to a hard-coded path, break npm ci caching, slow down every install, and fail in monorepo hoisting setups. The explicit build-script approach gives consumers full control over where assets land and when they are copied.

Troubleshooting 404s for native assets

If the browser fails to load supra-client-daemon.wasm, polyfill.js, or other native files:

  1. Verify the build script includes supra-screen copy-assets --to <output-dir>.
  2. Confirm the output directory matches the bundler's output path (e.g. dist/).
  3. Check that the dev server or CDN serves files from the same directory.
  4. Run ls <output-dir>/supra-client-daemon.wasm to confirm the file exists.
  5. If using output.clean: true in webpack, place the copy step after webpack.

Usage

A consuming applet must initialize @signageos/front-applet once and wait for readiness before starting Supra Screen:

import sos from "@signageos/front-applet";
import { SupraScreen } from "@signageos/supra-screen/es6/sdk";

sos.onReady().then(async () => {
	const app = await new SupraScreen().start();
});

@signageos/front-applet is a peer dependency and is deliberately not imported by the SDK. This keeps sos.config, authentication, and runtime event state in the host-owned singleton.

start() resolves with a SupraScreenApp handle as soon as the local rendering client is attached. The handle lets you stop that client later:

// Clean up and exit the local client. The server app keeps running.
await app.stop();

// Clean up the local client, then terminate the server app process.
await app.stop({ terminate: true });

stop() resolves only after the local renderer reports that cleanup and exit completed. It rejects if stop dispatch fails, cleanup fails, or the renderer does not exit within 10 seconds. A failed local stop never proceeds with server-process termination.

Note: most devices cannot run multiple instances at different positions simultaneously, even though the SDK API would allow it.

By default all configuration is read from the host-owned global sos.config and platform defaults. Everything can be overridden via start() options:

await new SupraScreen().start({
	appName: "chromium-browser",
	appArgs: "--temp-profile --kiosk",
	extraArgs: ["--headless"],
	onAppStarted: ({ appName }) => console.log(`app ${appName} running`),
	onError: (error) => report(error),
});

Troubleshooting front-applet runtime errors

FrontAppletRuntimeError means window.sos is missing or has not been initialized. It can also indicate that multiple front-applet copies or entry points created separate in-memory runtime objects.

  1. Import @signageos/front-applet only in the host applet entry point.
  2. Await sos.onReady() before calling SupraScreen.start().
  3. Run npm ls @signageos/front-applet and align incompatible versions.
  4. Run npm dedupe, or use package-manager overrides when transitive packages require incompatible copies.
  5. Do not mix @signageos/front-applet and @signageos/front-applet/es6/bundle imports. For legacy dependency graphs, alias all front-applet imports to one physical package and one entry point in the bundler.

Libraries must declare front-applet as a peer dependency instead of a production dependency. This prevents each library from bundling its own stateful runtime instance.

Options

All options are optional (SupraScreenOptions). When not set, values are resolved from sos.config and platform-specific defaults.

| Option | Type | Description | | ------ | ---- | ----------- | | appName | string | App process to run (google-chrome, chromium-browser, display-supra, …) | | appArgs | string \| string[] | Extra arguments passed to the app process | | appDataPath | string | Persistent data path of the app | | extraArgs | string \| string[] | Additional daemon CLI arguments | | forceScreenSize | string | Forced screen resolution, e.g. 1920x1080 | | daemonPort | number \| string | Port the daemon listens on | | streamProtocol | StreamProtocol | Streaming protocol override (platform default otherwise) | | logDriver | string | Daemon log driver | | daemonRegistry | string | Daemon image registry | | daemonUsername / daemonPassword | string | Daemon registry credentials | | daemonVersion | string | Daemon image version | | androidApp | string \| AndroidAppOptions | Android app to run via the supra-app-launcher applet. Pass a plain package ID string (e.g. com.example.myapp) for defaults, or an object { appId, instanceId?, baseUrl?, appletVersion?, runtime?, identity?, display? } to customize. instanceId is always forwarded and defaults to appId. identity defaults to sos.authHash (without it the launcher runs in standalone mode). Prepended to extraArgs. | | geometry | { x, y, width, height } | Screen position and size (pixels) where the app is rendered. Requires platform renderers with geometry support. Defaults to fullscreen. For androidApp, width and height also set the Redroid runtime display resolution. | | instanceId | string | Supra Screen slot used for process persistence and renderer switching. Defaults to androidApp.appId in Android mode, otherwise to appName. This outer slot does not replace androidApp.instanceId, which is always forwarded to the launcher. | | debug | boolean | Enables debug mode: shows the debug overlay and appends --debug to the started app arguments (e.g. display-supra enables its own debug output). Also settable via debug in sos.config. The overlay can be hidden ad-hoc by its ✕ button (current applet session only, not persisted). |

Events / Callbacks

Lifecycle callbacks let the SDK consumer react to the boot process:

| Callback | When | | -------- | ---- | | onStarting | Before anything starts | | onDaemonStarting | Daemon start requested | | onDaemonReady | Daemon is ready | | onAppStarting | New app process is being spawned | | onAppResuming | Existing app process is being reused (no restart needed) | | onAppRestarting | Existing app process is being closed and restarted | | onAppStarted | App process is running | | onScreenStarting | Screen renderer is being attached | | onError | Boot failed with an error | | onRefreshing | Recovery refresh/restart fallback is running (fires when rendering stops without a manual stop()) |

Android App Launcher

Instead of hand-building the complex supra-app-launcher URL, pass the Android package ID directly:

const app = await new SupraScreen().start({
	androidApp: "com.example.myapp",
	geometry: { x: 100, y: 100, width: 800, height: 600 },
});

SupraScreen forwards the floored geometry dimensions to the launcher as displayWidth and displayHeight, so Redroid boots at the render viewport resolution instead of the physical display resolution. The generated URL is equivalent to:

https://2.signageos.io/applet/@signageos/supra-app-launcher/0.1.0/dist/index.html?type=android&runtime=redroid&appId=com.example.myapp&instanceId=com.example.myapp&displayWidth=800&displayHeight=600

The launcher query contract is:

  • type=android is always sent.
  • runtime defaults to redroid.
  • appId is the Android package ID.
  • instanceId is always sent. It defaults to appId and can be overridden with androidApp.instanceId.
  • displayWidth and displayHeight are both sent when geometry is supplied.
  • identity is sent when androidApp.identity or sos.authHash is available; without it the launcher runs in standalone mode.

Supra Screen itself runs the content renderer process (by default chromium-browser) and passes the launcher applet URL through --url. The launcher then owns the Android/Redroid runtime. An outer device host such as display-supra is separate from this content-renderer process, so using the browser default here does not replace or bypass that host.

Supra Screen and the launcher only select Android applications that are already registered by package ID. They do not install APKs, and neither the string nor object form of androidApp accepts an APK URL.

To customize the launcher URL, use the object form:

const app = await new SupraScreen().start({
	androidApp: {
		appId: "com.example.myapp",
		instanceId: "android-slot", // default appId; always forwarded
		baseUrl: "https://staging.signageos.io", // default https://2.signageos.io
		appletVersion: "2.0.0", // default 1.1.0
		runtime: "waydroid", // default redroid
		identity: "…", // default sos.authHash
	},
});

Source Layout

| Path | Role | | ---- | ---- | | src/index.ts | Thin applet entry — new SupraScreen().start() | | src/sdk.ts | Public SDK surface for the library target | | src/SupraScreen.ts | SupraScreen class — orchestration, dependency injection | | src/config/ | Config resolution, platform specs, raw sos.config access, parsers | | src/apps/ | App process registry (per-app CLI arguments) | | src/process/ | Process management, restart decision, process polyfills | | src/polyfills/ | Browser polyfills applied at startup | | src/utils/ | Small utilities (wait, …) | | tools/native-assets.js | Authoritative manifest of 17 native runtime assets | | tools/cli.js | supra-screen CLI binary (copy-assets --to <dir>) | | tools/monkey-patch.sh | Post-build patches for transpiled daemon/polyfill files |

Testing

npm test        # unit + integration tests (node:test, compiled via tsconfig.test.json)
npm run check   # eslint + prettier + tsc --noEmit

Integration tests in src/SupraScreen.test.ts run the full SupraScreen.start() flow with fully mocked dependencies and assert the exact call and callback order.