@@ -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 client–server"]
|
||||
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
|
||||
|
||||
|
||||
@@ -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
@@ -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 doesn’t 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 page’s `BridgeSwarm.request(type, payload)` builds a payload that the content script forwards; the background adds an `id` and sends it to the host. The host’s `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.js’s 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 connection’s 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.
|
||||
|
||||
@@ -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`).
|
||||
|
||||
@@ -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
@@ -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 |
|
||||
|------|-----|
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
@@ -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: Application │ HTTP, 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 client–server"]
|
||||
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["Client–server · 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
|
||||
|
||||
Reference in New Issue
Block a user