Skip to content

Packaging & CLI

A plugin is distributed as a single .rbp archive. Build it with the bundled CLI, or programmatically from the SDK.

.rbp format

.rbp is a standard ZIP (magic bytes PK\x03\x04). Layout:

my-plugin.rbp
├── manifest.json     ← required
├── index.js          ← required, path = manifest.entry
├── icon.png          ← optional, displayed in the Plugin Store
├── data/...          ← optional dataset files
└── assets/...        ← optional static assets

CLI

The SDK installs an rbrowser-plugin binary (run via npx rbrowser-plugin or an npm script).

rbrowser-plugin pack [options]

  --manifest <path>   default ./manifest.json
  --bundle   <path>   default ./dist/index.js
  --icon     <path>   optional
  --extra    <dir>    optional, may be repeated (e.g. --extra ./data --extra ./assets)
  --out      <path>   default ./dist/<id>-<version>.rbp

Exit codes: 0 success, 1 usage / I/O error, 2 manifest validation error.

A common package.json wiring (used by both example plugins) builds then packs in one step:

{
  "scripts": {
    "build": "vite build",
    "pack": "vite build && rbrowser-plugin pack"
  }
}

Programmatic API

For build scripts and tooling, the SDK exports the pack/unpack primitives:

Function Description
packRbp(input) Build .rbp bytes from { manifest, bundleSource, iconBytes?, extra? }.
unpackRbp(bytes) Parse .rbp{ manifest, bundleSource, bundleBytes, iconBytes?, files }.
looksLikeRbp(bytes) Magic-byte sniff (PK\x03\x04).
looksLikeLegacyJsonRbp(bytes) Detect an old v1 (JSON) .rbp so callers can suggest a repack.
validateManifestForPacking(m) Structural check; returns an error message or null.
rbpFilename(manifest) Canonical <id>-<version>.rbp filename.

Constants: RBP_FORMAT_VERSION ('rbp-v2'), RBP_MANIFEST_PATH ('manifest.json'), RBP_ICON_PATH ('icon.png').

Debug bridge

In dev mode only, the host publishes window.__rbrowser__.connect(pluginId). getDebugHost(pluginId?) is a typed wrapper for DevTools experiments:

import { getDebugHost } from '@rbrowser/plugin-sdk'

const host = getDebugHost('com.example.hello')
host.getState()

Production plugins must not call this

A shipped plugin receives a capability-scoped host from the loader in render. getDebugHost exists only for local experimentation.