Update Docs
CI / Build & Test (push) Successful in 8m20s

This commit is contained in:
Raven Scott
2026-07-26 23:53:34 -04:00
parent 83af298eb5
commit 9810f68cb3
15 changed files with 381 additions and 389 deletions
+14
View File
@@ -159,6 +159,20 @@ These events are broadcast to all subscribed tabs (no `swarmId` filter).
---
## Examples server (host control)
Toggled from extension Settings / Dashboard (`examplesServerEnabled` in `bridgeSwarmSettings`). The background service worker sends these commands; pages do not call them directly.
| Type | Payload | Response |
|------|---------|----------|
| `examplesServer.start` | `{ host?, port? }` — default `127.0.0.1:4173` | `{ ok, running, url, root, … }` |
| `examplesServer.stop` | `{}` | `{ ok, running: false, … }` |
| `examplesServer.status` | `{}` | `{ ok, running, url, rootFound, … }` |
Serves the bundled `examples/` tree over HTTP so demos share one origin (required for extension injection). See [examples/README.md](../examples/README.md).
---
## See also
- [DATA-API.md](DATA-API.md) — Data API details and examples.
+106 -25
View File
@@ -2,25 +2,60 @@
This document describes the components of BridgeSwarm and how messages flow between the browser page and the native host.
## Overview
```mermaid
flowchart TB
subgraph Browser["Desktop browser"]
Page["Web page<br/>window.BridgeSwarm"]
CS["content.js"]
BG["background.js<br/>service worker"]
UI["options.js / dashboard.js<br/>autosave settings"]
end
subgraph Host["Native messaging host Bare"]
MSG["messenger.js<br/>4-byte LE + JSON"]
H["host.js"]
SW["Hyperswarm"]
DATA["Corestore · Hypercore · Hyperbee<br/>Hyperdrive · Autobase · Hyperdb"]
MUX["Protomux · HRPC"]
CAP["capabilities/<br/>media + live encode"]
EX["examples-server.js<br/>127.0.0.1:4173"]
end
Page <-->|postMessage| CS
CS <-->|runtime.sendMessage| BG
UI -->|storage.local<br/>bridgeSwarmSettings| BG
BG <-->|connectNative<br/>com.bridgeswarm| MSG
MSG --> H
H --> SW
H --> DATA
H --> MUX
H --> CAP
H --> EX
SW <-->|Noise P2P| Peer["Remote peers"]
```
## Components
### Extension
- **Background service worker** ([extension/background.js](../extension/background.js)): Maintains the native messaging port to the host (`chrome.runtime.connectNative('com.bridgeswarm')`). Sends requests to the host and tracks pending requests by id; forwards events to subscribed tabs. Reconnects with backoff on disconnect. Reads extension settings from **local storage** (key `bridgeSwarmSettings`); when “Show notification when host disconnects” is enabled, shows a browser notification on `port.onDisconnect`.
- **Content script** ([extension/content.js](../extension/content.js)): Reads settings from **local storage** (`bridgeSwarmSettings`). If “Do not inject on file:// URLs” is enabled and the page URL is `file://`, skips injection. Otherwise injects a small defaults script (setting `window.__BRIDGESWARM_DEFAULTS__` from settings) then [api.js](../extension/api.js), [framed-stream.js](../extension/framed-stream.js), and [protomux-bundle.js](../extension/protomux-bundle.js) into the page. Bridges the page and the background: the page cannot use `chrome.runtime` directly (it runs in the page context), so the page posts messages to the content script via `window.postMessage`, and the content script uses `chrome.runtime.sendMessage` to talk to the background. Events from the host are received by the background and sent to tabs; the content script dispatches them as `bridge-swarm-event` custom events on the window.
- **Options page** ([extension/options.html](../extension/options.html), [extension/options.js](../extension/options.js)): Settings UI (CSP-compliant: script in external `options.js`). Saves to **local storage** under `bridgeSwarmSettings` (default app name, default max peers, default request timeout, default ready timeout, disable on file://, notify on disconnect, debug).
- **Injected scripts** (page context): [api.js](../extension/api.js) exposes `window.BridgeSwarm` and `BridgeSwarm.request(type, payload)`. It merges constructor options with `__BRIDGESWARM_DEFAULTS__` (appName, maxPeers, requestTimeoutMs, readyTimeoutMs), implements `BridgeSwarm.ready()` with optional timeout from defaults, and uses the default request timeout when the page doesnt pass `timeoutMs`. It listens for `bridge-swarm-bridge` messages, forwards them to the content script, and listens for `bridge-swarm-bridge-response` and `bridge-swarm-event`.
- **Background service worker** ([extension/background.js](../extension/background.js)): Maintains the native messaging port (`chrome.runtime.connectNative('com.bridgeswarm')`). Tracks pending requests by id; routes swarm events to the tabs that own each `swarmId`; broadcasts capability events (`cap-chunk` / `cap-end` / `cap-error`) to subscribed tabs. Reconnects with backoff on disconnect. Reads **`bridgeSwarmSettings`** from local storage (autosaved from Options/Dashboard). When “Show notification when host disconnects” is enabled, shows a browser notification on `port.onDisconnect`. When **Examples server** is enabled, sends `examplesServer.start` / `stop` to the host and exposes status to the UI.
- **Content script** ([extension/content.js](../extension/content.js)): Reads settings; if “Do not inject on file:// URLs” is on and the page is `file://`, skips injection. Otherwise injects defaults then [api.js](../extension/api.js), [framed-stream.js](../extension/framed-stream.js), and [protomux-bundle.js](../extension/protomux-bundle.js). Bridges page background via `window.postMessage` / `chrome.runtime.sendMessage` (the page cannot use `chrome.runtime` directly).
- **Options & Dashboard** ([extension/options.html](../extension/options.html), [extension/dashboard.html](../extension/dashboard.html)): Settings UI. Changes **save on change** (no Save button). Includes swarm defaults, timeouts, injection/notification/debug flags, and the examples-server toggle with URL `http://127.0.0.1:4173/`.
- **Injected scripts** (page context): [api.js](../extension/api.js) exposes `window.BridgeSwarm`, `BridgeSwarm.request`, `BridgeSwarm.capabilities` / `BridgeSwarm.media` (including `liveSession` / `attachLiveReceiver`). Merges constructor options with `__BRIDGESWARM_DEFAULTS__`.
### Native host
- **Entry** ([native-host/index.mjs](../native-host/index.mjs)): Loads bare-process, [messenger.js](../native-host/messenger.js), and [host.js](../native-host/host.js). Wires stdin/stdout to the messenger and passes `handleMessage` and the send callback so the host can reply and emit events.
- **Messenger** ([native-host/messenger.js](../native-host/messenger.js)): Implements the Chrome/Firefox native messaging protocol: 4-byte little-endian length prefix followed by UTF-8 JSON. Max message size from host to browser is 1 MB. Parses incoming messages and calls `onMessage`; provides `send(msg)` to write length-prefixed JSON to stdout.
- **Host** ([native-host/host.js](../native-host/host.js)): Handles all command types (swarm lifecycle, connection, attachment, data API). Runs Hyperswarm, Corestore, Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb; can attach Protomux and HRPC to a connection. Calls `reply(result)` to respond and `emit(event, payload)` to push events to the browser.
- **Entry** ([native-host/index.mjs](../native-host/index.mjs)): Loads bare-process, registers default capability packs (media/ffmpeg), starts [messenger.js](../native-host/messenger.js) + [host.js](../native-host/host.js).
- **Messenger** ([native-host/messenger.js](../native-host/messenger.js)): Chrome/Firefox native messaging: 4-byte little-endian length + UTF-8 JSON. Max message size from host browser is **1 MB**.
- **Host** ([native-host/host.js](../native-host/host.js)): Swarm lifecycle, peer firewall/ban, auto-replicate, connection attachment (Protomux/HRPC), Hyper* data API, capability dispatch, and examples-server control (`examplesServer.start` / `stop` / `status`).
- **Examples server** ([native-host/examples-server.js](../native-host/examples-server.js)): Optional `bare-http1` static server on `127.0.0.1:4173` serving synced `examples/` (or `BRIDGESWARM_EXAMPLES_DIR`). Enabled from extension settings.
## Protocol
- **Wire format** (host ↔ browser): Each message is a 4-byte LE unsigned integer (length in bytes) followed by that many bytes of UTF-8 JSON. No CRLF translation (binary I/O).
- **Message kinds**: Requests from browser: `{ id?, type, payload }`. Responses from host: `{ id, type: 'response', payload }`. Events from host: `{ type: 'event', event, payload }`.
- **Wire format** (host ↔ browser): 4-byte LE unsigned length + UTF-8 JSON. Binary I/O (no CRLF translation).
- **Message kinds**: Requests `{ id?, type, payload }` · Responses `{ id, type: 'response', payload }` · Events `{ type: 'event', event, payload }`.
## Request/response flow
@@ -31,16 +66,16 @@ sequenceDiagram
participant Background
participant NativeHost
Page->>ContentScript: postMessage bridge-swarm-bridge, payload
ContentScript->>Background: runtime.sendMessage action send, payload
Page->>ContentScript: postMessage bridge-swarm-bridge
ContentScript->>Background: runtime.sendMessage action send
Background->>NativeHost: port.postMessage id, type, payload
NativeHost->>NativeHost: handleMessage reply(result)
NativeHost->>Background: messenger.send id, type response, payload
NativeHost->>NativeHost: handleMessage reply(result)
NativeHost->>Background: messenger.send id, type response
Background->>ContentScript: sendResponse payload
ContentScript->>Page: dispatchEvent bridge-swarm-bridge-response, detail
ContentScript->>Page: dispatchEvent bridge-swarm-bridge-response
```
The pages `BridgeSwarm.request(type, payload)` builds a payload that the content script forwards; the background adds an `id` and sends it to the host. The hosts `reply(result)` is sent back with the same `id` so the background can resolve the matching pending promise and the page receives the response.
`BridgeSwarm.request(type, payload)` builds the payload; the background assigns `id` and resolves the matching pending promise when the host replies.
## Event flow
@@ -52,24 +87,70 @@ sequenceDiagram
participant Page
NativeHost->>NativeHost: emit(event, payload)
NativeHost->>Background: messenger.send type event, event, payload
Background->>ContentScript: tabs.sendMessage bridge-swarm-event, payload
ContentScript->>Page: dispatchEvent bridge-swarm-event, detail
Page->>Page: api.js _onEvent connection data end error
NativeHost->>Background: messenger.send type event
alt swarm-scoped event
Background->>ContentScript: tabs.sendMessage only tabs owning swarmId
else capability / global event
Background->>ContentScript: tabs.sendMessage all subscribed tabs
end
ContentScript->>Page: dispatchEvent bridge-swarm-event
Page->>Page: api.js _onEvent connection data end error cap-*
```
The host emits events (e.g. `connection`, `data`, `end`, `error`) when swarms or connections change. The background broadcasts them to all subscribed tabs; the content script dispatches a custom event; api.jss BridgeSwarm instance listens and updates connection state and emits on the swarm/connection objects.
## Connection lifecycle
1. **Init swarm**: Page creates a BridgeSwarm and calls `join(topic)`. That triggers `init` (if not already inited) then `join`. The host creates a Hyperswarm and joins the topic.
2. **Connection**: When a peer connects, the host creates a `connId`, stores the socket, and emits a `connection` event with `connId`, `swarmId`, and `peerInfo`. The page receives it and gets a BridgeSwarmConnection with that `connId`.
3. **Data**: The page can `conn.write(data)` (sent as `write` with base64 data) and receives `data` events (host forwards socket data as base64 in `data` events). Or the page can **attach** the connection:
4. **Attachment**: The page sends `attachReplication({ connId, coreKeyHex? })` or `attachHrpc({ connId })`. The host stops forwarding that connections data to the browser, creates a Protomux on the socket, and either runs Hypercore replication or opens the HRPC channel. That connection is then used only by the host for that protocol. The host keeps at most one connection per peer per swarm (duplicate connections from the same peer are dropped) so both sides use the same connection pair for HRPC.
```mermaid
stateDiagram-v2
[*] --> Init: new BridgeSwarm + join(topic)
Init --> Discovering: host Hyperswarm.join
Discovering --> Connected: peer Noise handshake
Connected --> DataForward: page conn.write / data events
Connected --> Attached: attachReplication or attachHrpc
DataForward --> Closed: end / error / destroy
Attached --> Closed: end / destroy
Closed --> [*]
```
1. **Init swarm**: `join(topic)` triggers `init` (once) then `join`. Host creates Hyperswarm and joins the topic.
2. **Connection**: Host allocates `connId`, stores the socket, emits `connection` with `connId`, `swarmId`, `peerInfo`.
3. **Data**: `conn.write``write` (base64); host forwards socket bytes as `data` events — **or** the page attaches the connection:
4. **Attachment**: `attachReplication` / `attachHrpc` stops browser data forwarding; host owns Protomux on that socket (Hypercore replication or HRPC). At most one connection per peer per swarm is kept.
## Examples server flow
```mermaid
sequenceDiagram
participant UI as Options / Dashboard
participant BG as background.js
participant Host as Native host
participant Browser as Browser tab
UI->>UI: toggle examplesServerEnabled<br/>autosave bridgeSwarmSettings
UI->>BG: storage.onChanged
BG->>Host: examplesServer.start host 127.0.0.1 port 4173
Host->>Host: bare-http1 serve examples/
Host-->>BG: running url http://127.0.0.1:4173/
Browser->>Host: GET /live-encode/
Note over Browser: content script injects BridgeSwarm on http origin
```
## Live media encode (capability)
```mermaid
flowchart LR
Cam["Page capture<br/>canvas / getDisplayMedia"] -->|JPEG frames<br/>or WebM slices| API["BridgeSwarm.media.liveSession"]
API -->|encodePushFrame<br/>via NMH| Enc["host bare-ffmpeg<br/>VP9 / WebM"]
Enc -->|cap-chunk kind segment| MSE["Page MSE player"]
Enc -->|BSML on socket| Peer["Remote peer conn"]
Enc -->|archive| File["cap-jobs/sessionId/live.webm"]
```
## See also
- [API-REFERENCE.md](API-REFERENCE.md) — All request types and events.
- [DATA-API.md](DATA-API.md) — Data API and connection attachment.
- [CAPABILITIES.md](CAPABILITIES.md) — Media pack and live encode.
- [DEFAULT-MODULES.md](DEFAULT-MODULES.md) — Modules in the default host.
- [PROTOMUX.md](PROTOMUX.md) — Protomux in the browser and attachment from the host.
- [HRPC.md](HRPC.md) — HRPC on the host.
- [examples/README.md](../examples/README.md) — Demo gallery URLs.
+8
View File
@@ -70,6 +70,14 @@ Shipped in the standard `bridge-swarm-host` artifact (`bare-media` + `bare-ffmpe
### Live encode notes
```mermaid
flowchart LR
In["Page ingest<br/>JPEG frames / WebM slices"] --> Host["media.encode*<br/>bare-ffmpeg VP9"]
Host -->|cap-chunk segment| PageOut["MSE on page"]
Host -->|BSML socket write| SwarmOut["Peer connections"]
Host --> FileOut["cap-jobs/session/live.webm"]
```
- Chrome NMH ~1 MB/message → ingest **compressed JPEG frames** (or WebM slices), not raw RGBA.
- Defaults for demos: **640×360 @ 10fps**; soft max ~720p @ 15fps; session max duration 10 minutes.
- Egress: `page` (MSE segments), `swarm` (BSML-framed binary on Hyperswarm sockets), `file` (`cap-jobs/<sessionId>/live.webm`).
+2 -1
View File
@@ -10,9 +10,10 @@ Curated modules shipped in the **default** BridgeSwarm native host. Not every `b
| `bare` | Bare runtime |
| `bare-process` | `process` global for packed host |
| `bare-module` | Addon / module loading |
| `bare-fs` | Storage, cap-jobs, Hyper* on disk |
| `bare-fs` | Storage, cap-jobs, Hyper* on disk, serve example files |
| `bare-path` | Path join/resolve under allowlists |
| `bare-stream` | Duplex bridges for NMH / HRPC |
| `bare-http1` | Local examples server (`127.0.0.1:4173`) when enabled in Settings |
### Holepunch data + swarm
| Module | Why |