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
+67 -64
View File
@@ -13,10 +13,16 @@ Traditional web applications use a **client-server model** - all communication g
**BridgeSwarm enables peer-to-peer (P2P) communication** directly between browsers:
```
Traditional: [Browser] ──────► [Server] ──────► [Browser]
P2P: [Browser] ◄──────► [Browser]
(Direct connection)
```mermaid
flowchart LR
subgraph Traditional["Traditional clientserver"]
B1[Browser] -->|HTTP| S[Server]
S -->|HTTP| B2[Browser]
end
subgraph P2P["BridgeSwarm P2P"]
P1[Browser] <-->|Noise / Hyperswarm| P2[Browser]
end
```
## Features
@@ -134,33 +140,37 @@ swarm.destroy();
## Architecture
```
┌─────────────────────────────────────────────────────────────┐
│ Your Web Page
│ │
│ window.BridgeSwarm │
│ ├── new BridgeSwarm({ appName }) │
│ ├── swarm.join(topic) │
│ ├── swarm.on('connection', ...) │
│ ├── conn.write(data) │
│ └── BridgeSwarm.request('beeGet', { key }) │
└─────────────────────────────────────────────────────────────┘
│ window.postMessage
┌─────────────────────────────────────────────────────────────┐
│ Chrome Extension │
│ │
│ content.js ─────► background.js ─────► native host │
│ (injects API) (service worker) (P2P networking) │
└─────────────────────────────────────────────────────────────┘
```mermaid
flowchart TB
subgraph Page["Web page"]
API["window.BridgeSwarm<br/>join / write / request / media.*"]
end
subgraph Ext["Browser extension MV3"]
CS["content.js<br/>injects api.js"]
BG["background.js<br/>service worker"]
OPT["Settings / Dashboard<br/>autosave + examples toggle"]
end
subgraph Host["Native host Bare"]
NH["host.js<br/>Hyperswarm · Hyper* · HRPC"]
CAP["Capability packs<br/>media / live encode"]
EX["examples-server<br/>http://127.0.0.1:4173/"]
end
API <-->|postMessage| CS
CS <-->|runtime.sendMessage| BG
BG <-->|native messaging<br/>4-byte LE + JSON| NH
NH --> CAP
BG -->|examplesServer.start/stop| EX
OPT --> BG
```
### How It Works
1. **Extension** (Manifest V3): Background service worker maintains native messaging port; content script injects `api.js` into pages
2. **Native host** (Bare runtime): Runs Hyperswarm, data stores, handles connections
3. **Protocol**: 4-byte LE length prefix + JSON; binary data base64-encoded
1. **Extension** (Manifest V3): Background service worker maintains the native messaging port; content script injects `api.js` into pages. Settings autosave to `bridgeSwarmSettings` (including the examples-server toggle).
2. **Native host** (Bare runtime): Runs Hyperswarm, Hyper* data stores, HRPC/Protomux attachment, default media capabilities, and the optional local examples HTTP server.
3. **Protocol**: 4-byte LE length prefix + JSON; binary data base64-encoded (NMH ~1 MB limit).
## Security
@@ -267,28 +277,34 @@ window.addEventListener('bridge-swarm-host-disconnect', () => {
## Extension Settings
Right-click the extension icon → **Options**:
Open **Options** or the **Dashboard → Settings**. Changes **save automatically** (no Save button).
- **Swarm defaults**: Default app name, max peers
- **Requests**: Default request timeout (ms)
- **API**: Default ready timeout (ms)
- **Injection**: Skip injection on `file://` URLs
- **Notifications**: Show notification on host disconnect
- **Examples**: Enable the bundled demos server at **http://127.0.0.1:4173/** (native host)
- **Debug**: Enable debug logging
## Examples
| Example | Description |
|---------|-------------|
| **chat-advanced** | Full-featured P2P chat with rooms, user presence, emoji, file sharing, typing indicators |
| **chat** | Minimal P2P chat - join topic, send messages |
| **data-demo** | Data API demo - Hyperbee, Hyperdrive, Hyperdb |
| **sdk-demo** | BridgeSwarm + Protomux usage |
| **hrpc-demo** | HRPC ping demo |
| **chat-advanced** | Full-featured P2P chat with rooms, presence, emoji, file sharing |
| **chat** | Minimal P2P chat |
| **firewall-room** | Peer firewall allowlist/denylist + ban |
| **data-demo** | Hyperbee, Hyperdrive, Hyperdb |
| **sync-demo** | Auto-replicate Hyper* resources |
| **sdk-demo** | BridgeSwarm + Protomux |
| **hrpc-demo** | HRPC (unary + streaming) |
| **whiteboard** | Collaborative drawing |
| **screenshare** | P2P screen sharing (WebRTC + BridgeSwarm) |
| **screenshare** | P2P screen sharing (WebRTC + BridgeSwarm signaling) |
| **live-encode** | Live VP9/WebM encode via host `bare-ffmpeg` → MSE |
| **media-demo** | Batch media transforms / transcode |
| **clip-studio** | Nearline clip tooling on the media pack |
Open any example's `index.html` in your browser to try it.
Enable **Examples server** in Settings, then open **http://127.0.0.1:4173/** (not `file://`).
## Theory & Documentation
@@ -342,36 +358,23 @@ npm run build:dist:package # All platforms + zip archives (CI)
### File Layout
```mermaid
flowchart TB
root[BridgeSwarm]
root --> theory["theory/<br/>guides + essays"]
root --> docs["docs/<br/>ARCHITECTURE · API · DATA · CAPABILITIES · HRPC…"]
root --> examples["examples/<br/>source of truth for demos"]
root --> extension["extension/<br/>MV3 + synced examples/"]
root --> native["native-host/<br/>Bare host + examples-server"]
root --> scripts["scripts/<br/>install · pack · sync-examples · serve"]
examples --> demos["chat · firewall-room · live-encode · media-demo · …"]
extension --> extFiles["api.js · background.js · content.js · options · dashboard"]
native --> hostFiles["host.js · messenger.js · capabilities/ · examples-server.js"]
```
BridgeSwarm/
├── theory/ # Comprehensive documentation
│ └── bridgeswarm-for-dummies.md # Complete guide
├── docs/ # API documentation
│ ├── ARCHITECTURE.md
│ ├── API-REFERENCE.md
│ ├── DATA-API.md
│ ├── CAPABILITIES.md
│ ├── DEFAULT-MODULES.md
│ ├── PROTOMUX.md
│ └── HRPC.md
├── examples/ # Example applications
│ ├── chat-advanced/ # Full-featured chat
│ ├── chat/ # Basic chat
│ ├── data-demo/ # Data API demo
│ ├── sdk-demo/ # SDK demo
│ ├── hrpc-demo/ # HRPC demo
│ ├── whiteboard/ # Collaborative whiteboard
│ └── screenshare/ # Screen sharing
├── extension/ # Browser extension (MV3)
│ ├── api.js # Main API
│ ├── background.js # Service worker
│ ├── content.js # Content script
│ └── manifest.json
└── native-host/ # Native messaging host
├── host.js # Main host logic
├── messenger.js # Protocol handler
└── index.mjs # Entry point
```
`npm run sync:examples` / `npm run pack` copy `examples/` into `extension/examples/` and `native-host/examples/` for packaging.
## Compatibility
+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 |
+10 -1
View File
@@ -16,7 +16,16 @@ npm run examples
Either way, use **http://127.0.0.1:4173/** (two browser tabs for P2P demos). Do not open `file://` or `chrome-extension://` copies for demos that need BridgeSwarm injection.
Shared chrome lives in [`shared/`](shared/) (`theme.css`, `chrome.css`, `boot.js`).
```mermaid
flowchart LR
Settings["Extension Settings<br/>examplesServerEnabled"] -->|autosave| BG[background.js]
BG -->|examplesServer.start| Host[Native host]
Host -->|bare-http1| URL["http://127.0.0.1:4173/"]
URL --> Tab[Browser tab]
Tab -->|content script injects| API[window.BridgeSwarm]
```
Shared chrome lives in [`shared/`](shared/) (`theme.css`, `chrome.css`, `boot.js`). Source of truth is this `examples/` tree; `npm run sync:examples` copies it into `extension/examples/` and `native-host/examples/` for packaging.
| Demo | URL |
|------|-----|
+1 -1
View File
@@ -43,7 +43,7 @@ A feature-rich P2P chat application built on BridgeSwarm with real-time messagin
## How to Run
1. Load the BridgeSwarm extension and native host.
2. From the repo root: `npm run examples`
2. Enable **Examples server** in extension Settings (or from the repo: `npm run examples`)
3. Open **http://127.0.0.1:4173/chat-advanced/** in two tabs.
Do **not** open via `file://` — browsers treat each local file as a unique security origin.
+3 -1
View File
@@ -10,7 +10,9 @@ Install the [BridgeSwarm extension and native host](../../README.md#easy-install
## How to run
From the repo root:
**Recommended:** Extension Settings → enable **Examples server**, then open the demo URL below.
Dev alternative from the repo root:
```bash
npm run examples
+4
View File
@@ -10,6 +10,10 @@ Install the [BridgeSwarm extension and native host](../../README.md#easy-install
## How to run
**Recommended:** Extension Settings → enable **Examples server**, then open the demo URL below.
Dev alternative from the repo root:
```bash
npm run examples
```
+4
View File
@@ -10,6 +10,10 @@ Install the [BridgeSwarm extension and native host](../../README.md#easy-install
## How to run
**Recommended:** Extension Settings → enable **Examples server**, then open the demo URL below.
Dev alternative from the repo root:
```bash
npm run examples
```
+4
View File
@@ -10,6 +10,10 @@ Install the [BridgeSwarm extension and native host](../../README.md#easy-install
## How to run
**Recommended:** Extension Settings → enable **Examples server**, then open the demo URL below.
Dev alternative from the repo root:
```bash
npm run examples
```
+4
View File
@@ -10,6 +10,10 @@ Install the [BridgeSwarm extension and native host](../../README.md#easy-install
## How to run
**Recommended:** Extension Settings → enable **Examples server**, then open the demo URL below.
Dev alternative from the repo root:
```bash
npm run examples
```
+4
View File
@@ -10,6 +10,10 @@ Install the [BridgeSwarm extension and native host](../../README.md#easy-install
## How to run
**Recommended:** Extension Settings → enable **Examples server**, then open the demo URL below.
Dev alternative from the repo root:
```bash
npm run examples
```
@@ -20,34 +20,26 @@ Native messaging lets an extension spawn a process outside the browser and commu
The crucial realization hit me like a freight train: the native process can run whatever code it wants. JavaScript in the browser can't do P2P networking, but JavaScript running in a native process outside the browser can do absolutely anything. The extension becomes a bridge between the privileged world inside the browser and the powerful world outside.
```
┌─────────────────────────────────────────────────────────────────┐
│ Chrome Browser │
│ │
│ ┌─────────────┐ ┌─────────────────────────────────┐ │
│ │ Web Page │ │ Chrome Extension │ │
│ │ │ │ │ │
│ │ window.Bridge│◄──────►│ content.js ──► background.js │ │
│ │ Swarm │ │ (service worker) │ │
│ └─────────────┘ └──────────────┬──────────────────┘ │
│ │ │
└──────────────────────────────────────────│──────────────────────┘
│ native messaging
│ (stdin/stdout)
┌─────────────────────────────────────────────────────────────────┐
│ Native Host (Bare/Node.js) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ Hyperswarm │ │ Hyperbee │ │ Hyperdrive │ │
│ │ (P2P DHT) │ │ (key/value) │ │ (file system) │ │
│ └──────────────┘ └──────────────┘ └────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ Hypercore │ │ Autobase │ │ Hyperdb │ │
│ │ (append-log) │ │(multi-writer)│ │ (database) │ │
│ └──────────────┘ └──────────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
```mermaid
flowchart TB
subgraph Browser["Desktop browser"]
Page["Web page<br/>window.BridgeSwarm"]
Ext["Extension MV3<br/>content.js → background.js"]
Page <--> Ext
end
Ext <-->|native messaging<br/>stdin/stdout · 4-byte LE + JSON| Host
subgraph Host["Native host Bare"]
HS["Hyperswarm<br/>P2P DHT"]
HB["Hyperbee<br/>key/value"]
HD["Hyperdrive<br/>file system"]
HC["Hypercore<br/>append-only log"]
AB["Autobase<br/>multi-writer"]
HDB["Hyperdb<br/>schema DB"]
CAP["Capabilities<br/>media · live ffmpeg encode"]
EX["Examples server<br/>127.0.0.1:4173"]
end
```
The native host runs Hyperswarm, which handles all the peer discovery through the distributed hash table. It manages the NAT traversal magic that lets connections work behind home routers and corporate firewalls. It performs the Noise protocol handshake to establish encrypted sessions. It runs all the data storage systems that Hyperswarm supports. Nothing P2P happens without the native host being involved.
+130 -268
View File
@@ -147,22 +147,16 @@ To truly understand P2P networking, it helps to compare it to the traditional ne
The **OSI (Open Systems Interconnection) Model** is the conceptual framework that describes how data moves through a network. It has **7 layers**:
```
┌─────────────────────────────────────────────────────────────────┐
Layer 7: ApplicationHTTP, WebSocket, DNS
├─────────────────────────────────────────────────────────────────┤
Layer 6: Presentation │ TLS/SSL, JPEG, GIF, UTF-8 │
├─────────────────────────────────────────────────────────────────┤
Layer 5: Session │ Session management, API │
├─────────────────────────────────────────────────────────────────┤
Layer 4: Transport │ TCP, UDP │
├─────────────────────────────────────────────────────────────────┤
│ Layer 3: Network │ IP, Routing │
├─────────────────────────────────────────────────────────────────┤
│ Layer 2: Data Link │ Ethernet, WiFi, MAC addresses │
├─────────────────────────────────────────────────────────────────┤
│ Layer 1: Physical │ Cables, fiber, radio waves │
└─────────────────────────────────────────────────────────────────┘
```mermaid
flowchart TB
L7["Layer 7 · Application<br/>HTTP, WebSocket, DNS"]
L6["Layer 6 · Presentation<br/>TLS/SSL, JPEG, GIF, UTF-8"]
L5["Layer 5 · Session<br/>Session management, API"]
L4["Layer 4 · Transport<br/>TCP, UDP"]
L3["Layer 3 · Network<br/>IP, Routing"]
L2["Layer 2 · Data Link<br/>Ethernet, WiFi, MAC"]
L1["Layer 1 · Physical<br/>Cables, fiber, radio"]
L7 --> L6 --> L5 --> L4 --> L3 --> L2 --> L1
```
In traditional client-server networking:
@@ -192,21 +186,18 @@ P2P networking doesn't replace the OSI model - it's built **on top of it**. The
P2P applications still use all 7 OSI layers - they just use them differently:
```
Traditional Web (Client-Server):
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Browser │ ──────► │ Server │ ◄───────│ Browser │
└─────────┘ HTTP └─────────┘ HTTP └─────────┘
(Central)
```mermaid
flowchart LR
subgraph CS["Traditional web clientserver"]
B1[Browser] -->|HTTP| S[Central server]
S -->|HTTP| B2[Browser]
end
P2P Networking:
┌─────────┐ ┌─────────┐
│ Browser │ ◄───────│ Browser │
└─────────┘ Noise └─────────┘ (Direct)
│ │
└──────────────┘
DHT
(for discovery only)
subgraph P2P["P2P networking"]
P1[Browser] <-->|Noise direct| P2[Browser]
DHT[(DHT discovery only)] -.-> P1
DHT -.-> P2
end
```
### The Role of Each Layer in P2P
@@ -257,15 +248,18 @@ P2P uses **NAT traversal** (hole punching):
**Client-Server**: Server runs 24/7, clients connect as needed
**P2P**: Peers can come and go; the network adapts
```
Traditional: [Client] ──────► [Server] ──────► [Client]
Always-on Always-on
```mermaid
flowchart TB
subgraph Traditional["Clientserver · always-on middle"]
C1[Client] --> Srv[Server]
Srv --> C2[Client]
end
P2P: [Peer A] ──────► [Peer B]
(may join/leave anytime)
[Peer C] ──────► (discovers via DHT)
subgraph P2PNet["P2P · peers may join/leave"]
A[Peer A] <--> B[Peer B]
C[Peer C] -.->|discovers via DHT| A
C <--> B
end
```
#### 4. Trust Model
@@ -284,24 +278,13 @@ P2P: [Peer A] ──────► [Peer B]
BridgeSwarm brings P2P capabilities to browsers, but browsers are inherently client-side. Here's how it works:
```
┌──────────────────────────────────────────────────────────────────┐
Your Web Page
│ │
│ JavaScript calls: swarm.join('topic'), conn.write(data) │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Browser Extension (api.js) │ │
│ │ Converts JavaScript calls to native messaging │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Native Host (Hyperswarm) │ │
│ │ Actually does P2P: DHT discovery, NAT traversal │ │
│ └─────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```mermaid
flowchart TB
Page["Your web page<br/>swarm.join · conn.write · BridgeSwarm.media.*"]
Ext["Browser extension<br/>api.js bridge to native messaging"]
Host["Native host Bare<br/>Hyperswarm DHT · NAT · Noise · Hyper* · media"]
Page --> Ext --> Host
Host <-->|P2P| Peers[Remote peers]
```
The key insight: **your web page doesn't do P2P directly**. The native host does. The browser extension just provides the API.
@@ -363,63 +346,27 @@ BridgeSwarm exposes this functionality to browsers through its extension.
BridgeSwarm consists of three main parts working together:
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Your Web Page
│ │
│ window.BridgeSwarm │
│ ├── new BridgeSwarm({ appName: 'chat' }) │
│ ├── swarm.join('topic') │
│ ├── swarm.on('connection', (conn, peerInfo) => {}) │
│ ├── conn.write(data) │
│ └── BridgeSwarm.request('beeGet', { key: 'foo' }) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ window.postMessage
┌─────────────────────────────────────────────────────────────────────────────┐
│ Chrome Extension (Content Script) │
│ │
│ content.js │
│ ├── Receives messages from page via postMessage │
│ ├── Forwards to background via chrome.runtime.sendMessage │
│ ├── Receives events from background │
│ ├── Dispatches as CustomEvents to page │
│ └── Injects api.js, framed-stream.js, protomux-bundle.js │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ chrome.runtime.sendMessage
┌─────────────────────────────────────────────────────────────────────────────┐
│ Chrome Extension (Background Service Worker) │
│ │
│ background.js │
│ ├── Maintains native messaging port to host │
│ ├── Tracks pending requests (promises) │
│ ├── Routes events to correct tabs │
│ ├── Manages swarm/tab associations │
│ ├── Handles reconnection on disconnect │
│ └── Stores extension settings │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ Native Messaging (stdin/stdout)
│ 4-byte length prefix + JSON
┌──────────────────────────────────────────────────────────────────────────────┐
│ Native Host (Node.js/Bare) │
│ │
│ host.js │
│ ├── Runs Hyperswarm for P2P networking │
│ ├── Manages swarms (join/leave topics) │
│ ├── Handles connections (data, end, error events) │
│ ├── Runs Corestore/Hypercore/Hyperbee/Hyperdrive/Autobase/Hyperdb │
│ ├── Can attach Protomux and HRPC to connections │
│ └── Sends events and responses back to extension │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```mermaid
flowchart TB
subgraph Page["Web page"]
API["window.BridgeSwarm<br/>new · join · on connection · write · request · media.*"]
end
subgraph Content["Extension · content.js"]
CS["postMessage bridge<br/>inject api.js · framed-stream · protomux-bundle<br/>CustomEvent dispatch"]
end
subgraph Background["Extension · background.js"]
BG["native messaging port<br/>pending requests · swarm/tab routing<br/>reconnect · settings · examplesServer"]
end
subgraph Host["Native host Bare"]
NH["host.js<br/>Hyperswarm · Hyper* · Protomux/HRPC<br/>capabilities · examples-server"]
end
API <-->|window.postMessage| CS
CS <-->|runtime.sendMessage| BG
BG <-->|stdin/stdout<br/>4-byte LE + JSON| NH
```
---
@@ -436,18 +383,21 @@ The extension is a **Manifest V3** extension consisting of:
- **api.js**: Injected into page, provides `window.BridgeSwarm` API
- **framed-stream.js**: Adapter for Protomux compatibility
- **protomux-bundle.js**: Browser bundle of Protomux + compact-encoding + b4a
- **options.html/js**: Settings UI
- **dashboard.html/js**: Status dashboard
- **options.html/js**: Settings UI (autosave on change)
- **dashboard.html/js**: Status dashboard + same settings
- **examples/** (synced into the packed extension): demo gallery assets
### 2. The Native Host
A **native messaging host** that runs outside the browser:
- Written in **JavaScript** running on **Node.js** or **Bare** runtime
- Written in **JavaScript** on the **Bare** runtime (release installs ship a packed Bare binary)
- Uses **Chrome/Firefox native messaging protocol**
- Implements the Hyperswarm P2P stack
- Manages data storage (Hypercore, Hyperbee, Hyperdrive, etc.)
- Manages data storage (Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb)
- Default **media** capability pack (`bare-media` + `bare-ffmpeg`, including live VP9 encode)
- Can attach Protomux and HRPC to connections
- Optional **examples HTTP server** (`bare-http1` on `127.0.0.1:4173`) toggled from Settings
- Communicates with extension via stdin/stdout
### 3. The Bridge (Communication Protocol)
@@ -469,55 +419,41 @@ The connection between extension and native host uses a specific protocol:
When your web page calls `BridgeSwarm.request('beeGet', { key: 'foo' })`:
```
1. api.js (in page)
└─> Creates request with type 'beeGet', payload { key: 'foo' }
└─> Sends via window.postMessage to content script
```mermaid
sequenceDiagram
participant Page as api.js
participant CS as content.js
participant BG as background.js
participant Host as host.js
2. content.js (in extension)
└─> Receives via window.addEventListener('message')
└─> Forwards via chrome.runtime.sendMessage to background
3. background.js (service worker)
└─> Adds unique request ID
└─> Sends via port.postMessage to native host
└─> Stores promise resolve/reject for later
4. host.js (native host)
└─> Receives via messenger.js
└─> Parses JSON
└─> Executes command (e.g., Hyperbee get)
└─> Sends response via messenger.send()
5. Response travels back the same path
└─> background.js resolves the pending promise
└─> content.js dispatches CustomEvent
└─> api.js resolves the original Promise
Page->>CS: postMessage beeGet payload
CS->>BG: runtime.sendMessage
BG->>BG: assign id · store pending Promise
BG->>Host: port.postMessage
Host->>Host: Hyperbee get
Host->>BG: response id + payload
BG->>CS: sendResponse
CS->>Page: bridge-swarm-bridge-response
Page->>Page: resolve original Promise
```
### Event Flow
When the native host detects a new peer connection:
```
1. host.js (native host)
└─> Hyperswarm emits 'connection' event
└─> Creates connection entry, generates connId
└─> Sends event via messenger.send()
```mermaid
sequenceDiagram
participant Host as host.js
participant BG as background.js
participant CS as content.js
participant Page as api.js
2. background.js (service worker)
└─> Receives event
└─> Looks up which tab(s) have this swarm registered
└─> Sends to those specific tabs via tabs.sendMessage
3. content.js (in extension)
└─> Receives via runtime.onMessage
└─> Dispatches CustomEvent 'bridge-swarm-event'
4. api.js (in page)
└─> Listens for 'bridge-swarm-event'
└─> Creates BridgeSwarmConnection object
└─> Emits 'connection' event to your code
Host->>Host: Hyperswarm connection · alloc connId
Host->>BG: event connection swarmId peerInfo
BG->>BG: find tabs registered for swarmId
BG->>CS: tabs.sendMessage bridge-swarm-event
CS->>Page: CustomEvent bridge-swarm-event
Page->>Page: BridgeSwarmConnection · emit connection
```
---
@@ -1281,50 +1217,19 @@ const result = await BridgeSwarm.request('hrpcInvoke', {
When the native host needs to notify your page about something (new connection, received data, etc.), here's the complete flow:
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ NATIVE HOST (host.js) │
│ │
│ 1. Something happens (e.g., new peer connection) │
│ 2. Creates connection entry │
│ 3. Calls emit('connection', { connId, swarmId, peerInfo }) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ messenger.send()
┌──────────────────────────────────────────────────────────────────────────────┐
│ BACKGROUND (background.js) │
│ │
│ 4. Receives: { type: 'event', event: 'connection', payload: {...} } │
│ 5. Gets swarmId from payload │
│ 6. Finds tabs that registered this swarmId │
│ 7. For each matching tab, calls tabs.sendMessage() │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
│ chrome.runtime.sendMessage
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONTENT SCRIPT (content.js) │
│ │
│ 8. Receives: { type: 'bridge-swarm-event', payload: {...} } │
│ 9. Dispatches: new CustomEvent('bridge-swarm-event', { detail: payload }) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ window.dispatchEvent
┌─────────────────────────────────────────────────────────────────────────────┐
│ PAGE (api.js) │
│ │
│ 10. Listens for 'bridge-swarm-event' │
│ 11. Checks if swarmId matches this BridgeSwarm instance │
│ 12. Creates BridgeSwarmConnection if needed │
│ 13. Emits appropriate event ('connection', 'data', 'end', 'error') │
│ 14. Your code receives the event! │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```mermaid
sequenceDiagram
participant Host as host.js
participant BG as background.js
participant CS as content.js
participant Page as api.js
Host->>Host: peer connection · emit connection
Host->>BG: messenger.send event
BG->>BG: resolve tabs for swarmId
BG->>CS: tabs.sendMessage bridge-swarm-event
CS->>Page: CustomEvent bridge-swarm-event
Page->>Page: match swarmId · BridgeSwarmConnection<br/>emit connection / data / end / error
```
### Key Filter: swarmId Matching
@@ -1346,71 +1251,24 @@ This ensures that if you have multiple BridgeSwarm instances in the same page, e
When you call `BridgeSwarm.request('beeGet', { key: 'foo' })`, here's what happens:
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ YOUR PAGE │
│ │
│ 1. api.js:sendToBridge({ type: 'beeGet', payload: { key: 'foo' } }) │
│ 2. Creates unique request ID │
│ 3. Sets up one-time event listener for response │
│ 4. Posts message to content script │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ window.postMessage
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONTENT SCRIPT (content.js) │
│ │
│ 5. Receives via window.addEventListener('message') │
│ 6. Forwards via chrome.runtime.sendMessage() │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ chrome.runtime.sendMessage
┌─────────────────────────────────────────────────────────────────────────────┐
│ BACKGROUND (background.js) │
│ │
│ 7. Adds unique ID if not present │
│ 8. Stores { resolve, reject } in pending Map │
│ 9. Sends to native host via port.postMessage() │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ Native Messaging (stdin)
┌─────────────────────────────────────────────────────────────────────────────┐
│ NATIVE HOST (host.js) │
│ │
│ 10. Receives via messenger │
│ 11. Parses JSON │
│ 12. Switches on type ('beeGet') │
│ 13. Executes Hyperbee get operation │
│ 14. Sends response via messenger.send() │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ Native Messaging (stdout)
┌─────────────────────────────────────────────────────────────────────────────┐
│ BACKGROUND (background.js) │
│ │
│ 15. Receives: { id, type: 'response', payload: {...} } │
│ 16. Looks up pending[id] │
│ 17. Calls resolve(payload) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
│ (async, stored promise)
┌──────────────────────────────────────────────────────────────────────────────┐
│ YOUR PAGE │
│ │
│ 18. Original Promise resolves │
│ 19. Your code continues: const result = await ... │
│ │
└──────────────────────────────────────────────────────────────────────────────┘
```mermaid
sequenceDiagram
participant Page as Page api.js
participant CS as content.js
participant BG as background.js
participant Host as host.js
Page->>Page: sendToBridge beeGet + request id
Page->>CS: window.postMessage
CS->>BG: runtime.sendMessage
BG->>BG: pending Map resolve/reject
BG->>Host: port.postMessage stdin
Host->>Host: Hyperbee get
Host->>BG: response stdout
BG->>BG: resolve pending id
BG->>CS: sendResponse
CS->>Page: bridge-swarm-bridge-response
Page->>Page: await continues with result
```
---
@@ -2355,7 +2213,7 @@ function onData(chunk) {
### Settings Available
The BridgeSwarm extension stores these settings (in Chrome storage):
The BridgeSwarm extension stores these settings under `bridgeSwarmSettings` in `chrome.storage.local`. The Options page and Dashboard **save automatically** when you change a control (no Save button).
| Setting | Default | Description |
|---------|---------|-------------|
@@ -2365,13 +2223,17 @@ The BridgeSwarm extension stores these settings (in Chrome storage):
| `readyTimeoutMs` | 0 | Timeout for BridgeSwarm.ready() (0 = wait forever) |
| `disableOnFileUrls` | false | Skip injection on file:// URLs |
| `notifyOnDisconnect` | false | Show notification when host disconnects |
| `examplesServerEnabled` | false | Start host examples server at http://127.0.0.1:4173/ |
| `debug` | false | Enable debug logging |
When `examplesServerEnabled` flips, `background.js` sends `examplesServer.start` or `examplesServer.stop` to the native host.
### How Settings Are Applied
1. **content.js reads settings** from Chrome storage
2. **Sets `window.__BRIDGESWARM_DEFAULTS__`**
3. **api.js merges with constructor options**
4. **background.js** applies notify-on-disconnect and examples-server start/stop
```javascript
// In api.js - BridgeSwarm constructor