docs
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
# API Reference — Host request types and events
|
||||
|
||||
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)`.
|
||||
|
||||
## Message format
|
||||
|
||||
- **Request** (browser → host): `{ id?, type, payload }`. The extension adds an `id` if omitted. The host uses `id` to match responses.
|
||||
- **Response** (host → browser): `{ id, type: 'response', payload }`. The payload is the command result (e.g. `{ ok: true, ... }` or `{ ok: false, error: '...' }`).
|
||||
- **Event** (host → browser): `{ type: 'event', event, payload }`. The extension forwards these to subscribed tabs; the page receives them via the `bridge-swarm-event` custom event (handled by api.js).
|
||||
|
||||
## Response shape
|
||||
|
||||
- **Success**: Payload includes `ok: true` and command-specific fields (e.g. `{ ok: true, key, length, writable }` for coreInfo).
|
||||
- **Error**: Payload is `{ ok: false, error: string }`. The promise returned by the bridge still resolves; check `response.ok` and use `response.error` when false.
|
||||
|
||||
---
|
||||
|
||||
## Swarm lifecycle
|
||||
|
||||
Used by the BridgeSwarm class. All payloads include `swarmId` (chosen by the client).
|
||||
|
||||
| Type | Payload | Response |
|
||||
|------|---------|----------|
|
||||
| `init` | `{ swarmId, options? }` — options passed to Hyperswarm (e.g. appName) | `{ 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 }` |
|
||||
|
||||
---
|
||||
|
||||
## Connection
|
||||
|
||||
Connections are created when the host’s Hyperswarm emits a connection; the host then emits a `connection` event to the browser with `connId`. The browser can send data on that connection or attach replication/hrpc.
|
||||
|
||||
### Events (host → browser)
|
||||
|
||||
| Event | Payload |
|
||||
|-------|---------|
|
||||
| `connection` | `{ connId, swarmId, peerInfo }` — peerInfo: `{ publicKey (hex), topics? (hex[]) }` |
|
||||
| `data` | `{ connId, swarmId, data }` — data is base64-encoded bytes |
|
||||
| `end` | `{ connId, swarmId }` |
|
||||
| `error` | `{ connId, swarmId, message }` |
|
||||
|
||||
### Requests
|
||||
|
||||
| Type | Payload | Response |
|
||||
|------|---------|----------|
|
||||
| `write` | `{ connId, data }` — data as base64 string | `{ ok }` or `{ ok: false, error }` |
|
||||
| `destroyConnection` | `{ connId }` | `{ ok }` |
|
||||
|
||||
---
|
||||
|
||||
## Connection attachment
|
||||
|
||||
After a connection is established, the browser can ask the host to “take over” that connection for Hypercore replication or HRPC. The connection then stops being forwarded to the browser.
|
||||
|
||||
| Type | Payload | Response |
|
||||
|------|---------|----------|
|
||||
| `attachReplication` | `{ connId, coreKeyHex? }` — if coreKeyHex omitted, host uses default core | `{ ok }` or `{ ok: false, error }` |
|
||||
| `attachHrpc` | `{ connId }` | `{ ok }` or `{ ok: false, error }` |
|
||||
|
||||
See [DATA-API.md](DATA-API.md) and [HRPC.md](HRPC.md) for details.
|
||||
|
||||
---
|
||||
|
||||
## Data API (Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb)
|
||||
|
||||
All commands return `{ ok: true, ... }` on success or `{ ok: false, error }` on failure. Binary data is base64-encoded in payloads and responses.
|
||||
|
||||
| Type | Payload | Response |
|
||||
|------|---------|----------|
|
||||
| `coreInfo` | — | `{ ok, key (hex), length, writable }` |
|
||||
| `coreAppend` | `{ data }` or `{ base64 }` | `{ ok, length }` |
|
||||
| `coreGet` | `{ index }` (number) | `{ ok, data }` (base64 or null) |
|
||||
| `beeGet` | `{ key }` | `{ ok, key?, value?, seq? }` or `{ ok, value: null }` |
|
||||
| `beePut` | `{ key, value }` | `{ ok }` |
|
||||
| `beeDel` | `{ key }` | `{ ok }` |
|
||||
| `driveGet` | `{ path? }` (default `'/'`) | `{ ok, data }` (base64 or null) |
|
||||
| `drivePut` | `{ path, data? }` or `{ path, base64? }` | `{ ok }` |
|
||||
| `driveList` | `{ path? }` (default `'/'`) | `{ ok, entries }` (array of `{ key, value }`) |
|
||||
| `driveDel` | `{ path }` | `{ ok }` |
|
||||
| `autobaseAppend` | `{ value? }` or `{ data? }` | `{ ok, length }` |
|
||||
| `autobaseViewGet` | `{ index }` (number) | `{ ok, data }` (base64 or null) |
|
||||
| `autobaseInfo` | — | `{ ok, length, signedLength }` |
|
||||
| `hyperdbGet` | `{ collection, query }` | `{ ok, doc }` (doc or null) |
|
||||
| `hyperdbInsert` | `{ collection, doc }` — doc: `{ id, value }` strings | `{ ok }` |
|
||||
| `hyperdbDelete` | `{ collection, query }` | `{ ok }` |
|
||||
| `hyperdbFindToArray` | `{ collectionOrIndex, query?, limit?, reverse? }` | `{ ok, docs }` |
|
||||
| `hyperdbFlush` | — | `{ ok }` |
|
||||
|
||||
Full details and examples: [DATA-API.md](DATA-API.md).
|
||||
|
||||
---
|
||||
|
||||
## See also
|
||||
|
||||
- [DATA-API.md](DATA-API.md) — Data API details and examples.
|
||||
- [HRPC.md](HRPC.md) — HRPC (attachHrpc) and commands.
|
||||
- [PROTOMUX.md](PROTOMUX.md) — Protomux in the browser and connection attachment.
|
||||
- [ARCHITECTURE.md](ARCHITECTURE.md) — Message flow and components.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Architecture
|
||||
|
||||
This document describes the components of BridgeSwarm and how messages flow between the browser page and the native host.
|
||||
|
||||
## 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.
|
||||
- **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`.
|
||||
|
||||
### 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.
|
||||
|
||||
## 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 }`.
|
||||
|
||||
## Request/response flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Page
|
||||
participant ContentScript
|
||||
participant Background
|
||||
participant NativeHost
|
||||
|
||||
Page->>ContentScript: postMessage bridge-swarm-bridge, payload
|
||||
ContentScript->>Background: runtime.sendMessage action send, payload
|
||||
Background->>NativeHost: port.postMessage id, type, payload
|
||||
NativeHost->>NativeHost: handleMessage reply(result)
|
||||
NativeHost->>Background: messenger.send id, type response, payload
|
||||
Background->>ContentScript: sendResponse payload
|
||||
ContentScript->>Page: dispatchEvent bridge-swarm-bridge-response, detail
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## Event flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant NativeHost
|
||||
participant Background
|
||||
participant ContentScript
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## See also
|
||||
|
||||
- [API-REFERENCE.md](API-REFERENCE.md) — All request types and events.
|
||||
- [DATA-API.md](DATA-API.md) — Data API and connection attachment.
|
||||
- [PROTOMUX.md](PROTOMUX.md) — Protomux in the browser and attachment from the host.
|
||||
- [HRPC.md](HRPC.md) — HRPC on the host.
|
||||
+12
-4
@@ -1,6 +1,6 @@
|
||||
# Native Host Data API (Hypercore, Hyperbee, Hyperdrive, Autobase)
|
||||
# Native Host Data API (Hypercore, Hyperbee, Hyperdrive, Autobase, Hyperdb)
|
||||
|
||||
The native host runs **Corestore**, **Hypercore**, **Hyperbee**, **Hyperdrive**, and **Autobase**. 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)`, which sends a JSON command to the host and returns the response.
|
||||
|
||||
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.
|
||||
|
||||
@@ -60,11 +60,14 @@ The default Hyperdb instance uses a minimal definition with a single collection
|
||||
| `hyperdbFindToArray` | `{ collectionOrIndex, query?, limit?, reverse? }` | `{ ok, docs }` (array of docs) |
|
||||
| `hyperdbFlush` | — | `{ ok }` |
|
||||
|
||||
### Replication
|
||||
### Connection attachment
|
||||
|
||||
These commands attach host-side behavior to a connection (identified by `connId` from a `connection` event). After attachment, that connection is no longer forwarded to the browser.
|
||||
|
||||
| Type | Payload | Response |
|
||||
|------|---------|----------|
|
||||
| `attachReplication` | `{ connId, coreKeyHex? }` | `{ ok }` — Attach core replication to connection; that connection stops being forwarded to the browser. |
|
||||
| `attachReplication` | `{ connId, coreKeyHex? }` | `{ ok }` — Attach Hypercore replication to the connection. If `coreKeyHex` is provided, the host uses that core; otherwise the default core. |
|
||||
| `attachHrpc` | `{ connId }` | `{ ok }` — Enable HRPC on the connection (Protomux channel `bridgeswarm-hrpc`). See [HRPC.md](HRPC.md). |
|
||||
|
||||
## Example: Hyperbee
|
||||
|
||||
@@ -111,6 +114,11 @@ await BridgeSwarm.request('hyperdbDelete', { collection, query: { id: 'foo' } })
|
||||
await BridgeSwarm.request('hyperdbFlush'); // flush pending writes
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [API-REFERENCE.md](API-REFERENCE.md) — Full list of all host request types and events.
|
||||
- [ARCHITECTURE.md](ARCHITECTURE.md) — Message flow and components.
|
||||
|
||||
## Errors
|
||||
|
||||
If the host returns `{ ok: false, error: '...' }`, the promise still resolves. Check `response.ok` and use `response.error` when `ok` is false.
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
# HRPC on the Native Host
|
||||
|
||||
The native host can run **[hrpc](https://www.npmjs.com/package/hrpc)** over a connection: schema-defined, code-generated RPC with support for unary calls, request-streams, response-streams, duplex streams, and send-only commands. HRPC runs **only on the native host** over a Protomux channel; the browser does not run hrpc. From the browser you only send `attachHrpc` to enable it on a connection; the host then speaks the hrpc protocol with the remote peer (or with another host that has also attached hrpc).
|
||||
|
||||
## Enabling HRPC
|
||||
|
||||
From the browser, after you have a connection (e.g. from `swarm.on('connection', (conn, peerInfo) => { ... })`), call:
|
||||
|
||||
```javascript
|
||||
const res = await BridgeSwarm.request('attachHrpc', { connId: conn.connId });
|
||||
if (res.ok) {
|
||||
// Host now speaks hrpc on that connection (Protomux channel "bridgeswarm-hrpc")
|
||||
}
|
||||
```
|
||||
|
||||
- **Payload**: `{ connId }` — the connection ID from the `connection` event payload.
|
||||
- **Response**: `{ ok: true }` or `{ ok: false, error: '...' }`. On success, that connection is no longer forwarded to the browser; the host uses it for the hrpc channel.
|
||||
|
||||
## Protocol
|
||||
|
||||
- **Channel**: Protomux protocol name `bridgeswarm-hrpc`; one buffer-framed message type carries the RPC wire format (bare-rpc compatible).
|
||||
- **Stream**: The host creates a duplex stream over that channel and instantiates the generated HRPC class; the remote peer can speak the same protocol to call the defined commands.
|
||||
|
||||
## Commands
|
||||
|
||||
The following commands are defined in the spec and generated into `spec/hrpc/`. They are implemented by the host in [native-host/host.js](../native-host/host.js).
|
||||
|
||||
| Command | Mode | Request | Response |
|
||||
|---------|------|---------|----------|
|
||||
| `ping` | Unary | `{ value? }` (optional string) | `{ pong }` (string; echoes or `'pong'`) |
|
||||
| `streamSum` | Request-stream → single response | Client streams chunks `{ n, label }` | `{ sum, count }` (sum of `n`, number of chunks) |
|
||||
| `fetchStream` | Single request → response-stream | `{ count }` (number of chunks to stream) | Server streams `{ i, data }` chunks |
|
||||
| `duplex` | Duplex (request- and response-streams) | Client streams `{ x, y }` | Server streams `{ result, n }` (echo/transform) |
|
||||
| `notify` | Send-only | `{ event, payload }` | No response (host logs to stderr) |
|
||||
|
||||
Schema and command registration live in [scripts/build-hrpc.js](../scripts/build-hrpc.js); generated code is written to `spec/hyperschema/` and `spec/hrpc/` (index.js, messages.js, hrpc.json).
|
||||
|
||||
## Building the spec
|
||||
|
||||
From the repo root:
|
||||
|
||||
```bash
|
||||
npm run build:hrpc
|
||||
```
|
||||
|
||||
This writes `spec/hyperschema/` and `spec/hrpc/`. The installer runs this step automatically, so after `./scripts/install.sh` the spec is already built.
|
||||
|
||||
To change the API (add commands or message types), edit [scripts/build-hrpc.js](../scripts/build-hrpc.js) (Hyperschema namespace + HRPCBuilder registration), then run `npm run build:hrpc` again.
|
||||
|
||||
## Handlers
|
||||
|
||||
Handlers are implemented in [native-host/host.js](../native-host/host.js): ping returns pong, streamSum accumulates request stream and returns sum/count, fetchStream writes chunks to the response stream, duplex reads from the request stream and writes to the response stream, notify logs to stderr. The host loads the generated HRPC class from `spec/hrpc/` and registers these handlers when `attachHrpc` runs.
|
||||
|
||||
## If the spec is missing
|
||||
|
||||
If `spec/hrpc/` was not built or fails to load (e.g. missing dependencies), the host still starts. In that case `attachHrpc` returns an error such as `"hrpc not available: ..."` or `"hrpc spec not built (run: npm run build:hrpc)"`. Run `npm run build:hrpc` from the repo root (or re-run the installer), then restart the native host.
|
||||
|
||||
## See also
|
||||
|
||||
- [DATA-API.md](DATA-API.md) — Connection attachment table (attachReplication, attachHrpc).
|
||||
- [API-REFERENCE.md](API-REFERENCE.md) — Full list of host request types.
|
||||
- [ARCHITECTURE.md](ARCHITECTURE.md) — Message flow and components.
|
||||
+12
-6
@@ -4,8 +4,8 @@ BridgeSwarm injects a browser bundle of **Protomux**, **compact-encoding** (`c`)
|
||||
|
||||
## Setup
|
||||
|
||||
1. Install the extension and native host (see main [README](../README.md)).
|
||||
2. Ensure the Protomux bundle is built: from repo root run `npm run build:protomux` (output: `extension/protomux-bundle.js`).
|
||||
1. Install the extension and native host (see main [README](../README.md)). The installer runs `npm run build:protomux` so the Protomux bundle is built by default.
|
||||
2. To rebuild the bundle (e.g. after changing `extension/protomux-entry.cjs`), from repo root run `npm run build:protomux` (output: `extension/protomux-bundle.js`).
|
||||
3. The extension injects `api.js`, `framed-stream.js`, and `protomux-bundle.js` into the page in order. No extra script tags are needed.
|
||||
|
||||
## Globals
|
||||
@@ -111,16 +111,22 @@ Use these when encoding/decoding binary message payloads.
|
||||
</html>
|
||||
```
|
||||
|
||||
## Native host: Hypercore replication (advanced)
|
||||
## Native host: connection attachment (replication and HRPC)
|
||||
|
||||
The native host can attach **Hypercore replication** to a connection so that the host’s core replicates with the remote peer over that connection. When you do this, that connection is no longer forwarded to the browser (the host “takes over” it for the Hypercore protocol).
|
||||
The native host can attach **Hypercore replication** or **HRPC** to a connection. When you do this, that connection is no longer forwarded to the browser (the host “takes over” it).
|
||||
|
||||
From the browser you would need to send a message to the native host (the current extension API does not expose this; you’d extend the extension to send an `attachReplication` command). The host supports:
|
||||
The extension exposes both commands via `BridgeSwarm.request(type, payload)`:
|
||||
|
||||
- **attachReplication** — payload: `{ connId, coreKeyHex? }`. Uses the connection identified by `connId`. If `coreKeyHex` is provided, the host looks up that core from its corestore; otherwise it uses a default core (name `'default'`). The host creates a Protomux from the socket, stops forwarding that connection’s data to the browser, and runs `core.replicate(protomux)` so the remote peer can replicate that core.
|
||||
- **attachReplication** — `BridgeSwarm.request('attachReplication', { connId, coreKeyHex? })`. Uses the connection identified by `connId`. If `coreKeyHex` is provided, the host looks up that core from its corestore; otherwise it uses the default core (name `'default'`). The host creates a Protomux from the socket and runs `core.replicate(protomux)` so the remote peer can replicate that core.
|
||||
- **attachHrpc** — `BridgeSwarm.request('attachHrpc', { connId })`. Enables HRPC on that connection (Protomux channel `bridgeswarm-hrpc`). See [HRPC.md](HRPC.md).
|
||||
|
||||
Storage for the host’s corestore is under `BRIDGE_SWARM_STORAGE` or `./bridge-swarm-storage` relative to the host process.
|
||||
|
||||
## See also
|
||||
|
||||
- [HRPC.md](HRPC.md) — HRPC on the native host (attachHrpc).
|
||||
- [API-REFERENCE.md](API-REFERENCE.md) — Full list of host request types.
|
||||
|
||||
## Notes
|
||||
|
||||
- Each BridgeSwarm connection is already a **NoiseSecretStream** (framed, encrypted). The extension forwards one decrypted frame per chunk, so `wrapRawFrames(conn)` presents one chunk per frame to Protomux.
|
||||
|
||||
Reference in New Issue
Block a user