Add extension options, fix settings save and CSP, update docs

- Options: default max peers, ready timeout (ms), disable on file://,
  notify on host disconnect, plus existing app name, request timeout, debug
- Use storage.local instead of storage.sync so settings persist (e.g. in
  Firefox options page); add save/reset error handling in options UI
- Move options page script to options.js for CSP compliance (no inline script)
- manifest: add "notifications" permission for disconnect notification
- Docs: README (settings section, file layout), API-REFERENCE (ready timeout,
  constructor defaults, request timeout), ARCHITECTURE (storage, options page,
  content script behavior), DATA-API and examples/README (default timeout,
  file:// option)
This commit is contained in:
Raven Scott
2026-02-12 07:07:50 -05:00
parent a2068ed706
commit bef6e3fdbd
19 changed files with 1048 additions and 139 deletions
+25 -3
View File
@@ -1,6 +1,28 @@
# API Reference — Host request types and events
# API Reference — Page API and host request types
This document lists every request type the native host accepts and every event it emits. The browser uses these via the BridgeSwarm API and `BridgeSwarm.request(type, payload)`.
## Page API (browser)
These are the main APIs your page uses. For host request types and event payloads, see the sections below.
- **`BridgeSwarm.ready()`** — Returns a Promise that resolves with the `BridgeSwarm` constructor when the API is available. Use this if your script runs at load time and the extension may inject api.js after your script:
`await BridgeSwarm.ready()` or `BridgeSwarm.ready().then(swarm => { ... })`.
**Default ready timeout:** If the extension option “Default ready timeout (ms)” is set to a value > 0, `ready()` will reject after that many milliseconds with a message like `"BridgeSwarm not available within N ms"` when the API has not appeared (e.g. extension not installed or injection failed). Use 0 in options to wait indefinitely (default).
- **`new BridgeSwarm(options)`** — Constructor options are passed to Hyperswarm on the host. Supported: **`appName`** (string), **`maxPeers`** (number, cap on peer connections per swarm). If the page omits `appName` or `maxPeers`, the extension **defaults** from the options page are used (default app name, default max peers). Default max peers 0 means no limit.
- **`swarm.connections()`** — Returns an array of current connection objects (snapshot). Useful for broadcast; connection objects may later emit `end`. After `swarm.destroy()`, returns `[]`.
- **`conn.write(data)`** — Returns a **Promise** that resolves on success and rejects on host error (e.g. "Connection not found"). Also emits `error` on the connection. You can `await conn.write(data)` and handle failures.
- **Host disconnect** — When the native host disconnects, the page can listen for the custom event `bridge-swarm-host-disconnect` to show "Disconnected" or "Reconnecting…" and disable actions until the user reconnects or refreshes. If the extension option “Show notification when host disconnects” is enabled, the user also gets a browser notification. After disconnect, existing swarms/connections are stale; call `swarm.destroy()` and re-join or refresh.
- **`BridgeSwarm.request(type, payload, options)`** — Sends a request to the host. Optional third argument: `{ timeoutMs: number }` aborts after that many milliseconds and rejects with `"Request timed out after N ms"`. If the page does not pass `timeoutMs`, the extensions **default request timeout** (from the options page) is used when it is > 0.
---
## Host request types and events
This section lists every request type the native host accepts and every event it emits. The browser uses these via the BridgeSwarm API and `BridgeSwarm.request(type, payload)`.
## Message format
@@ -21,7 +43,7 @@ Used by the BridgeSwarm class. All payloads include `swarmId` (chosen by the cli
| Type | Payload | Response |
|------|---------|----------|
| `init` | `{ swarmId, options? }` — options passed to Hyperswarm (e.g. appName) | `{ ok }` |
| `init` | `{ swarmId, options? }` — options passed to Hyperswarm (e.g. `appName`, `maxPeers`; extension defaults used when page omits them) | `{ ok }` |
| `join` | `{ swarmId, topic }` — topic as 32-byte hex string; optional `opts` | `{ ok }` or `{ ok: false, error }` |
| `leave` | `{ swarmId, topic }` — topic as 32-byte hex string | `{ ok }` |
| `destroy` | `{ swarmId }` | `{ ok }` |
+4 -3
View File
@@ -6,9 +6,10 @@ This document describes the components of BridgeSwarm and how messages flow betw
### 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.
- **Content script** ([extension/content.js](../extension/content.js)): Injects [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.
- **Injected scripts** (page context): [api.js](../extension/api.js) exposes `window.BridgeSwarm` and `BridgeSwarm.request(type, payload)`. 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 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`.
### Native host
+1 -1
View File
@@ -1,6 +1,6 @@
# Native Host Data API (Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb)
The native host runs **Corestore**, **Hypercore**, **Hyperbee**, **Hyperdrive**, **Autobase**, and **Hyperdb**. The browser can call into these via `BridgeSwarm.request(type, payload)`, which sends a JSON command to the host and returns the response.
The native host runs **Corestore**, **Hypercore**, **Hyperbee**, **Hyperdrive**, **Autobase**, and **Hyperdb**. The browser can call into these via `BridgeSwarm.request(type, payload [, options])`, which sends a JSON command to the host and returns the response. Optional `options.timeoutMs` aborts after that many milliseconds; if omitted, the extensions **default request timeout** (set in the extension options page) is used when it is > 0. For connection APIs (e.g. `conn.write(data)` returning a Promise), see [API-REFERENCE.md](API-REFERENCE.md).
Storage is under `BRIDGE_SWARM_STORAGE` or `./bridge-swarm-storage` (relative to the host process). All commands use default instances (one core, one bee, one drive, one autobase) unless noted.
+1 -1
View File
@@ -24,7 +24,7 @@ Given a connection from `swarm.on('connection', (conn, peerInfo) => { ... })`, c
const mux = swarm.createProtomux(conn);
```
This wraps the connection in a framed stream and returns a new `Protomux` instance. If the Protomux bundle or framed stream script is not loaded, `createProtomux` returns `null` and logs a warning.
This wraps the connection in a framed stream and returns a new `Protomux` instance. If the Protomux bundle or framed stream script is not loaded, `createProtomux` returns `null` and logs a warning. Note: `conn.write(data)` returns a **Promise** that resolves on success and rejects on host error (see [API-REFERENCE.md](API-REFERENCE.md)).
## compact-encoding (c)