@fairfox/polly 0.25.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/elysia/index.js
CHANGED
|
@@ -73,11 +73,13 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
73
73
|
import { Elysia } from "elysia";
|
|
74
74
|
|
|
75
75
|
// src/shared/lib/peer-repo-server.ts
|
|
76
|
-
import { Repo } from "@automerge/automerge-repo/slim";
|
|
77
|
-
import { WebSocketServerAdapter } from "@automerge/automerge-repo-network-websocket";
|
|
78
|
-
import { NodeFSStorageAdapter } from "@automerge/automerge-repo-storage-nodefs";
|
|
79
|
-
import * as ws from "ws";
|
|
80
76
|
async function createPeerRepoServer(options) {
|
|
77
|
+
const [{ Repo }, { WebSocketServerAdapter }, { NodeFSStorageAdapter }, ws] = await Promise.all([
|
|
78
|
+
import("@automerge/automerge-repo/slim"),
|
|
79
|
+
import("@automerge/automerge-repo-network-websocket"),
|
|
80
|
+
import("@automerge/automerge-repo-storage-nodefs"),
|
|
81
|
+
import("ws")
|
|
82
|
+
]);
|
|
81
83
|
const wss = await (options.webSocketServer ? Promise.resolve(options.webSocketServer) : new Promise((resolve, reject) => {
|
|
82
84
|
const created = new ws.WebSocketServer({
|
|
83
85
|
port: options.port,
|
|
@@ -218,19 +220,19 @@ function findMatchingConfig(configs, method, path) {
|
|
|
218
220
|
|
|
219
221
|
class BroadcastManager {
|
|
220
222
|
connections = new Map;
|
|
221
|
-
register(clientId,
|
|
222
|
-
this.connections.set(clientId,
|
|
223
|
+
register(clientId, ws) {
|
|
224
|
+
this.connections.set(clientId, ws);
|
|
223
225
|
}
|
|
224
226
|
unregister(clientId) {
|
|
225
227
|
this.connections.delete(clientId);
|
|
226
228
|
}
|
|
227
229
|
broadcast(message, filter) {
|
|
228
230
|
const payload = JSON.stringify(message);
|
|
229
|
-
for (const [clientId,
|
|
231
|
+
for (const [clientId, ws] of this.connections.entries()) {
|
|
230
232
|
if (filter && !filter(clientId))
|
|
231
233
|
continue;
|
|
232
|
-
if (
|
|
233
|
-
|
|
234
|
+
if (ws.readyState === 1) {
|
|
235
|
+
ws.send(payload);
|
|
234
236
|
}
|
|
235
237
|
}
|
|
236
238
|
}
|
|
@@ -244,26 +246,26 @@ function polly(config = {}) {
|
|
|
244
246
|
client: config.state?.client || {},
|
|
245
247
|
server: config.state?.server || {}
|
|
246
248
|
}).decorate("pollyClock", clock).decorate("pollyBroadcast", broadcaster).ws(config.websocketPath || "/polly/ws", {
|
|
247
|
-
open(
|
|
248
|
-
const clientId =
|
|
249
|
-
broadcaster.register(clientId,
|
|
250
|
-
|
|
249
|
+
open(ws) {
|
|
250
|
+
const clientId = ws.data.headers?.["x-client-id"] || crypto.randomUUID();
|
|
251
|
+
broadcaster.register(clientId, ws.raw);
|
|
252
|
+
ws.send(JSON.stringify({
|
|
251
253
|
type: "state-sync",
|
|
252
254
|
state: config.state?.client || {},
|
|
253
255
|
clock: clock.now()
|
|
254
256
|
}));
|
|
255
257
|
},
|
|
256
|
-
close(
|
|
257
|
-
const clientId =
|
|
258
|
+
close(ws) {
|
|
259
|
+
const clientId = ws.data.headers?.["x-client-id"];
|
|
258
260
|
if (clientId) {
|
|
259
261
|
broadcaster.unregister(clientId);
|
|
260
262
|
clientStateByConnection.delete(clientId);
|
|
261
263
|
}
|
|
262
264
|
},
|
|
263
|
-
message(
|
|
265
|
+
message(ws, message) {
|
|
264
266
|
const data = JSON.parse(message);
|
|
265
267
|
if (data.type === "state-update") {
|
|
266
|
-
const clientId =
|
|
268
|
+
const clientId = ws.data.headers?.["x-client-id"];
|
|
267
269
|
if (clientId) {
|
|
268
270
|
clientStateByConnection.set(clientId, data.state);
|
|
269
271
|
}
|
|
@@ -339,13 +341,13 @@ function signalingServer(options = {}) {
|
|
|
339
341
|
return;
|
|
340
342
|
}
|
|
341
343
|
};
|
|
342
|
-
const handleJoin = (
|
|
343
|
-
peerSockets.set(peerId,
|
|
344
|
-
const wsWithData =
|
|
344
|
+
const handleJoin = (ws, peerId) => {
|
|
345
|
+
peerSockets.set(peerId, ws);
|
|
346
|
+
const wsWithData = ws;
|
|
345
347
|
wsWithData.data.peerId = peerId;
|
|
346
348
|
};
|
|
347
|
-
const sendUnknownTarget = (
|
|
348
|
-
|
|
349
|
+
const sendUnknownTarget = (ws, targetPeerId) => {
|
|
350
|
+
ws.send({
|
|
349
351
|
type: "error",
|
|
350
352
|
reason: "unknown-target",
|
|
351
353
|
targetPeerId
|
|
@@ -363,8 +365,8 @@ function signalingServer(options = {}) {
|
|
|
363
365
|
}
|
|
364
366
|
return target;
|
|
365
367
|
};
|
|
366
|
-
const handleSignal = (
|
|
367
|
-
const wsWithData =
|
|
368
|
+
const handleSignal = (ws, msg) => {
|
|
369
|
+
const wsWithData = ws;
|
|
368
370
|
const senderId = wsWithData.data.peerId;
|
|
369
371
|
if (!senderId) {
|
|
370
372
|
wsWithData.send({ type: "error", reason: "not-joined" });
|
|
@@ -372,7 +374,7 @@ function signalingServer(options = {}) {
|
|
|
372
374
|
}
|
|
373
375
|
const target = findOpenTarget(msg.targetPeerId);
|
|
374
376
|
if (!target) {
|
|
375
|
-
sendUnknownTarget(
|
|
377
|
+
sendUnknownTarget(ws, msg.targetPeerId);
|
|
376
378
|
return;
|
|
377
379
|
}
|
|
378
380
|
const relayed = {
|
|
@@ -385,30 +387,30 @@ function signalingServer(options = {}) {
|
|
|
385
387
|
target.send(relayed);
|
|
386
388
|
} catch {
|
|
387
389
|
peerSockets.delete(msg.targetPeerId);
|
|
388
|
-
sendUnknownTarget(
|
|
390
|
+
sendUnknownTarget(ws, msg.targetPeerId);
|
|
389
391
|
}
|
|
390
392
|
};
|
|
391
393
|
return new Elysia3().ws(path, {
|
|
392
|
-
message(
|
|
394
|
+
message(ws, raw) {
|
|
393
395
|
const msg = parseMessage(raw);
|
|
394
396
|
if (!msg) {
|
|
395
|
-
|
|
397
|
+
ws.send({ type: "error", reason: "malformed" });
|
|
396
398
|
return;
|
|
397
399
|
}
|
|
398
400
|
if (msg.type === "join") {
|
|
399
|
-
handleJoin(
|
|
401
|
+
handleJoin(ws, msg.peerId);
|
|
400
402
|
return;
|
|
401
403
|
}
|
|
402
404
|
if (msg.type === "signal") {
|
|
403
|
-
handleSignal(
|
|
405
|
+
handleSignal(ws, msg);
|
|
404
406
|
return;
|
|
405
407
|
}
|
|
406
|
-
|
|
408
|
+
ws.send({ type: "error", reason: "malformed" });
|
|
407
409
|
},
|
|
408
|
-
close(
|
|
409
|
-
const peerId =
|
|
410
|
+
close(ws) {
|
|
411
|
+
const peerId = ws.data.peerId;
|
|
410
412
|
if (peerId) {
|
|
411
|
-
if (peerSockets.get(peerId) ===
|
|
413
|
+
if (peerSockets.get(peerId) === ws) {
|
|
412
414
|
peerSockets.delete(peerId);
|
|
413
415
|
}
|
|
414
416
|
}
|
|
@@ -421,4 +423,4 @@ export {
|
|
|
421
423
|
peerRepo
|
|
422
424
|
};
|
|
423
425
|
|
|
424
|
-
//# debugId=
|
|
426
|
+
//# debugId=ABCACD6B736E00DA64756E2164756E21
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
"sources": ["../src/elysia/peer-repo-plugin.ts", "../src/shared/lib/peer-repo-server.ts", "../src/elysia/plugin.ts", "../src/core/clock.ts", "../src/utils/function-serialization.ts", "../src/elysia/signaling-server-plugin.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"// @ts-nocheck - Optional peer dependencies (elysia, @automerge/automerge-repo*)\n/**\n * peerRepo — Elysia plugin that runs a Polly peer-relay server alongside an\n * Elysia application and exposes the server's Repo on the Elysia context.\n *\n * The Phase 1 plan originally framed the relay server as an Elysia plugin\n * that registers a WebSocket route on Elysia's native socket layer. That\n * design does not work directly: Automerge's WebSocketServerAdapter requires\n * an `isomorphic-ws` WebSocketServer instance, and Elysia's WebSocket layer\n * is built on Bun's native WebSocket API, which is a different shape. The\n * realistic Phase 1 cut is therefore a *lifecycle* plugin: it runs\n * createPeerRepoServer on its own port during Elysia startup, decorates the\n * Elysia context so route handlers can reach the resulting Repo, and tears\n * the server down during Elysia shutdown. Authenticated WebSocket upgrades\n * via Elysia's hook system are a Phase 1.1 follow-up that requires either\n * a custom Bun-native NetworkAdapter or an upgrade-time auth bridge.\n *\n * @example\n * ```ts\n * import { Elysia } from \"elysia\";\n * import { peerRepo } from \"@fairfox/polly/elysia\";\n *\n * const app = new Elysia()\n * .use(peerRepo({ port: 3030, storagePath: \"./data/polly-peer\" }))\n * .get(\"/stats\", ({ pollyPeerRepo }) => {\n * return { peers: pollyPeerRepo.peers.length };\n * })\n * .listen(8080);\n * ```\n */\n\nimport { Elysia } from \"elysia\";\nimport {\n type CreatePeerRepoServerOptions,\n createPeerRepoServer,\n type PeerRepoServer,\n} from \"../shared/lib/peer-repo-server\";\n\nexport interface PeerRepoPluginOptions extends CreatePeerRepoServerOptions {\n /** Optional path for a health endpoint that returns peer count and storage\n * id. Set to false to skip the health route entirely. Defaults to\n * \"/polly/peer/health\". */\n healthPath?: string | false;\n}\n\n/**\n * Elysia plugin that boots a Polly peer-relay server alongside the host app\n * and decorates the context with `pollyPeerRepo` (the Repo) and\n * `pollyPeerServer` (the full {@link PeerRepoServer} for advanced use).\n *\n * The plugin starts the relay server during Elysia's onStart lifecycle and\n * shuts it down during onStop, so route handlers and cron jobs can use the\n * decorated Repo throughout the request lifetime without managing the\n * underlying transport themselves.\n */\nexport function peerRepo(options: PeerRepoPluginOptions) {\n // The plugin holds a single PeerRepoServer for the lifetime of the Elysia\n // app. It is created during onStart so the listening socket is bound and\n // ready before any request handler can reach it.\n let server: PeerRepoServer | undefined;\n\n const healthPath =\n options.healthPath === false ? null : (options.healthPath ?? \"/polly/peer/health\");\n\n let app = new Elysia({ name: \"polly-peer-repo\" })\n .decorate(\"pollyPeerRepo\", null as unknown as PeerRepoServer[\"repo\"] | null)\n .decorate(\"pollyPeerServer\", null as unknown as PeerRepoServer | null)\n .onStart(async () => {\n server = await createPeerRepoServer(options);\n // Decorate after construction so handlers see the live Repo. Elysia's\n // decorate is mutable in-place when called on the running instance.\n app.decorate(\"pollyPeerRepo\", server.repo);\n app.decorate(\"pollyPeerServer\", server);\n })\n .onStop(async () => {\n if (server) {\n await server.close();\n server = undefined;\n }\n });\n\n if (healthPath) {\n app = app.get(healthPath, () => {\n if (!server) {\n return { status: \"starting\", peers: 0 };\n }\n return {\n status: \"running\",\n peers: server.repo.peers.length,\n port: options.port,\n };\n });\n }\n\n return app;\n}\n",
|
|
6
|
-
"/**\n * peer-repo-server — Phase 1 server-side factory for the Polly peer-relay\n * transport. Constructs an Automerge-Repo `Repo` wired to a WebSocket server\n * and a NodeFS storage backend, ready to relay sync messages between\n * connected $peerState clients.\n *\n * The \"always-on peer\" role for $peerState lives here. The server holds a\n * full Automerge replica of every document, participates in the sync protocol\n * as an ordinary peer, and persists state to disk so the next process restart\n * picks up where the previous one left off. Server-side cron, HTTP handlers,\n * and other compute can open document handles on the returned Repo and mutate\n * them; mutations propagate to connected clients through the same sync\n * protocol that handles client-to-client traffic.\n *\n * The plan originally called this an \"Elysia plugin,\" but Automerge's\n * `WebSocketServerAdapter` requires an `isomorphic-ws` `WebSocketServer`\n * instance — not Elysia's native WebSocket — so the cleanest first cut is a\n * standalone factory that runs its own `ws` server. Elysia integration for\n * authenticated upgrades is a Phase 1.1 follow-up that wraps this factory.\n *\n * @example\n * ```ts\n * import { createPeerRepoServer } from \"@fairfox/polly\";\n *\n * const server = await createPeerRepoServer({\n * port: 3030,\n * storagePath: \"./data/polly-peer\",\n * });\n *\n * // Open a document handle on the server's Repo for cron or compute work.\n * const handle = server.repo.create({ counter: 0 });\n *\n * // On shutdown:\n * await server.close();\n * ```\n */\n\nimport { Repo } from \"@automerge/automerge-repo/slim\";\nimport { WebSocketServerAdapter } from \"@automerge/automerge-repo-network-websocket\";\nimport { NodeFSStorageAdapter } from \"@automerge/automerge-repo-storage-nodefs\";\nimport * as
|
|
6
|
+
"/**\n * peer-repo-server — Phase 1 server-side factory for the Polly peer-relay\n * transport. Constructs an Automerge-Repo `Repo` wired to a WebSocket server\n * and a NodeFS storage backend, ready to relay sync messages between\n * connected $peerState clients.\n *\n * The \"always-on peer\" role for $peerState lives here. The server holds a\n * full Automerge replica of every document, participates in the sync protocol\n * as an ordinary peer, and persists state to disk so the next process restart\n * picks up where the previous one left off. Server-side cron, HTTP handlers,\n * and other compute can open document handles on the returned Repo and mutate\n * them; mutations propagate to connected clients through the same sync\n * protocol that handles client-to-client traffic.\n *\n * The plan originally called this an \"Elysia plugin,\" but Automerge's\n * `WebSocketServerAdapter` requires an `isomorphic-ws` `WebSocketServer`\n * instance — not Elysia's native WebSocket — so the cleanest first cut is a\n * standalone factory that runs its own `ws` server. Elysia integration for\n * authenticated upgrades is a Phase 1.1 follow-up that wraps this factory.\n *\n * @example\n * ```ts\n * import { createPeerRepoServer } from \"@fairfox/polly\";\n *\n * const server = await createPeerRepoServer({\n * port: 3030,\n * storagePath: \"./data/polly-peer\",\n * });\n *\n * // Open a document handle on the server's Repo for cron or compute work.\n * const handle = server.repo.create({ counter: 0 });\n *\n * // On shutdown:\n * await server.close();\n * ```\n */\n\n// Heavy peer-relay dependencies (@automerge/automerge-repo, ws) are dynamic\n// imports loaded only when createPeerRepoServer is actually called. Static\n// imports at this file's top level were hoisted into @fairfox/polly/elysia's\n// module-init chain, breaking Elysia apps that don't use peer state and\n// don't install the automerge peer deps. Types come from the static package\n// references — TypeScript only reads them for shape, so no runtime cost is\n// incurred.\nimport type { Repo as RepoType } from \"@automerge/automerge-repo/slim\";\nimport type { WebSocketServerAdapter as WebSocketServerAdapterType } from \"@automerge/automerge-repo-network-websocket\";\nimport type { NodeFSStorageAdapter as NodeFSStorageAdapterType } from \"@automerge/automerge-repo-storage-nodefs\";\nimport type * as wsType from \"ws\";\n\n// `@types/ws` uses CJS `export = WebSocket` with WebSocketServer hanging off\n// the namespace. Under the project's bundler module resolution, the namespace\n// import gives us access to both the constructor and the type.\ntype WebSocketServer = wsType.WebSocketServer;\n\nexport interface CreatePeerRepoServerOptions {\n /** Port to listen on. The factory creates its own `WebSocketServer` and\n * binds to this port. */\n port: number;\n /** Filesystem directory for the NodeFS storage adapter. The directory is\n * created on demand. Defaults to `./automerge-repo-data` (Automerge's own\n * default). */\n storagePath?: string;\n /** Hostname interface to bind to. Defaults to all interfaces. */\n host?: string;\n /** Override the `WebSocketServer` instance entirely. When provided, `port`\n * and `host` are ignored and the caller is responsible for the lifecycle.\n * Useful for tests that want to bind to a random port. */\n webSocketServer?: WebSocketServer;\n}\n\nexport interface PeerRepoServer {\n /** A configured Repo participating as the always-on peer. Server-side\n * cron and HTTP handlers can open document handles on this directly. */\n repo: RepoType;\n /** The underlying WebSocket server. Exposed for advanced use such as\n * health checks or graceful shutdown coordination. */\n webSocketServer: WebSocketServer;\n /** The Automerge network adapter wrapping the WebSocket server. */\n adapter: WebSocketServerAdapterType;\n /** The NodeFS storage adapter writing to {@link CreatePeerRepoServerOptions.storagePath}. */\n storage: NodeFSStorageAdapterType;\n /** Tear down the server: disconnect peers, flush storage, close the\n * underlying WebSocket server. Returns a promise that resolves once the\n * tear-down is complete. */\n close: () => Promise<void>;\n}\n\n/**\n * Construct a Polly peer-relay server. Returns a Repo that participates as\n * the always-on peer, the underlying WebSocket server and storage adapter\n * for advanced use, and a close function for orderly shutdown.\n *\n * Applications typically call this once at startup, hold the returned\n * `repo` reference for cron and compute work, and wire the close function\n * into their process shutdown signal handlers.\n */\nexport async function createPeerRepoServer(\n options: CreatePeerRepoServerOptions\n): Promise<PeerRepoServer> {\n // Dynamic imports keep automerge-repo and ws out of the static module\n // graph. Apps that never call this function — which is most of them —\n // never pay the dependency cost and don't need the peer packages\n // installed at all.\n const [{ Repo }, { WebSocketServerAdapter }, { NodeFSStorageAdapter }, ws] = await Promise.all([\n import(\"@automerge/automerge-repo/slim\"),\n import(\"@automerge/automerge-repo-network-websocket\"),\n import(\"@automerge/automerge-repo-storage-nodefs\"),\n import(\"ws\"),\n ]);\n\n // Construct the WebSocket server first and wait until it is actually\n // listening before wiring up the Repo. Using the constructor callback\n // avoids the race where the 'listening' event fires before our listener\n // is attached (the callback form is reliable across Node and Bun).\n const wss = await (options.webSocketServer\n ? Promise.resolve(options.webSocketServer)\n : new Promise<WebSocketServer>((resolve, reject) => {\n const created: WebSocketServer = new ws.WebSocketServer(\n {\n port: options.port,\n ...(options.host !== undefined && { host: options.host }),\n },\n () => resolve(created)\n );\n created.once(\"error\", reject);\n }));\n\n // The cast bridges a @types/ws identity quirk: Automerge's adapter type\n // expects WebSocketServer with options.WebSocket typed via isomorphic-ws's\n // CJS-style namespace, and our direct `ws` import resolves through a\n // different path with the same runtime shape but a structurally distinct\n // TypeScript type. The runtime is identical, the cast names that fact.\n const adapter = new WebSocketServerAdapter(\n wss as unknown as ConstructorParameters<typeof WebSocketServerAdapter>[0]\n );\n const storage = new NodeFSStorageAdapter(options.storagePath);\n\n const repo = new Repo({\n network: [adapter],\n storage,\n });\n\n // Force the storage subsystem to finish initialising before returning. The\n // Repo constructor is synchronous, but its NetworkSubsystem holds back the\n // peer-metadata JOIN until storageSubsystem.id() resolves. If a client\n // connects before that resolution lands, the handshake stalls indefinitely.\n // Awaiting storageId() drains the relevant microtask chain and guarantees\n // the server is ready to accept peers when this factory returns.\n await repo.storageId();\n\n return {\n repo,\n webSocketServer: wss,\n adapter,\n storage,\n close: async () => {\n // Forcibly terminate any still-open client sockets before closing the\n // server, otherwise wss.close() can hang waiting for orderly drain when\n // a peer disappeared without a clean disconnect. We then fire the\n // server close without awaiting its callback — the underlying socket\n // is released immediately by terminate(), and waiting for the close\n // callback can hang under Bun even after every client is gone.\n for (const client of wss.clients) {\n try {\n client.terminate();\n } catch {\n // best effort\n }\n }\n try {\n await repo.shutdown();\n } catch {\n // best effort — automerge-repo's xstate DocHandle machine can\n // throw \"Cycle detected\" during teardown when sync messages are\n // still in flight.\n }\n try {\n wss.close();\n } catch {\n // best effort\n }\n },\n };\n}\n",
|
|
7
7
|
"// @ts-nocheck - Optional peer dependencies (elysia, @elysiajs/eden)\nimport type { Signal } from \"@preact/signals-core\";\nimport { Elysia } from \"elysia\";\nimport { createLamportClock } from \"../core/clock\";\nimport { serializeFunction } from \"../utils/function-serialization\";\nimport type { PollyConfig, PollyResponseMetadata } from \"./types\";\n\n/**\n * Broadcast message sent to connected clients\n */\ninterface BroadcastMessage {\n type: \"effect\";\n path: string;\n method: string;\n result: unknown;\n clock: { tick: number; contextId: string };\n}\n\n/**\n * Minimal WebSocket interface for broadcasting\n */\ninterface MinimalWebSocket {\n readyState: number;\n send(data: string): void;\n}\n\n/**\n * Route pattern matcher\n * Supports:\n * - Exact match: 'POST /todos'\n * - Param match: 'GET /todos/:id'\n * - Wildcard: '/todos/*'\n */\nfunction matchRoute(pattern: string, method: string, path: string): boolean {\n // Split pattern into method + path or just path\n const hasMethod = pattern.includes(\" \");\n const patternMethod = hasMethod ? pattern.split(\" \")[0] : null;\n const patternPath = hasMethod ? pattern.split(\" \")[1] : pattern;\n\n // Check method\n if (patternMethod && patternMethod !== method) {\n return false;\n }\n\n // Check path\n const patternSegments = patternPath.split(\"/\").filter(Boolean);\n const pathSegments = path.split(\"/\").filter(Boolean);\n\n if (patternSegments.length !== pathSegments.length && !patternPath.includes(\"*\")) {\n return false;\n }\n\n for (let i = 0; i < patternSegments.length; i++) {\n const patternSeg = patternSegments[i];\n const pathSeg = pathSegments[i];\n\n if (patternSeg === \"*\") return true;\n if (patternSeg.startsWith(\":\")) continue; // Param match\n if (patternSeg !== pathSeg) return false;\n }\n\n return true;\n}\n\n/**\n * Find matching config for a route\n */\nfunction findMatchingConfig<T>(\n configs: Record<string, T> | undefined,\n method: string,\n path: string\n): T | undefined {\n if (!configs) return undefined;\n\n for (const [pattern, config] of Object.entries(configs)) {\n if (matchRoute(pattern, method, path)) {\n return config;\n }\n }\n\n return undefined;\n}\n\n/**\n * WebSocket broadcast manager\n */\nclass BroadcastManager {\n private connections = new Map<string, MinimalWebSocket>();\n\n register(clientId: string, ws: MinimalWebSocket) {\n this.connections.set(clientId, ws);\n }\n\n unregister(clientId: string) {\n this.connections.delete(clientId);\n }\n\n broadcast(message: BroadcastMessage, filter?: (clientId: string) => boolean) {\n const payload = JSON.stringify(message);\n\n for (const [clientId, ws] of this.connections.entries()) {\n if (filter && !filter(clientId)) continue;\n if (ws.readyState === 1) {\n // WebSocket.OPEN = 1\n ws.send(payload);\n }\n }\n }\n}\n\n/**\n * Main Polly Elysia plugin\n */\nexport function polly(config: PollyConfig = {}) {\n const isDev = process.env.NODE_ENV !== \"production\";\n const clock = createLamportClock(\"server\");\n const broadcaster = new BroadcastManager();\n const clientStateByConnection = new Map<string, Record<string, Signal<unknown>>>();\n\n const app = new Elysia({ name: \"polly\" })\n // Add state to context\n .decorate(\"pollyState\", {\n client: config.state?.client || {},\n server: config.state?.server || {},\n })\n .decorate(\"pollyClock\", clock)\n .decorate(\"pollyBroadcast\", broadcaster)\n\n // WebSocket endpoint for real-time updates\n .ws(config.websocketPath || \"/polly/ws\", {\n // @ts-expect-error - Elysia WebSocket types from optional peer dependency\n open(ws) {\n const clientId = ws.data.headers?.[\"x-client-id\"] || crypto.randomUUID();\n broadcaster.register(clientId, ws.raw);\n\n // Send initial state sync\n ws.send(\n JSON.stringify({\n type: \"state-sync\",\n state: config.state?.client || {},\n clock: clock.now(),\n })\n );\n },\n // @ts-expect-error - Elysia WebSocket types from optional peer dependency\n close(ws) {\n const clientId = ws.data.headers?.[\"x-client-id\"];\n if (clientId) {\n broadcaster.unregister(clientId);\n clientStateByConnection.delete(clientId);\n }\n },\n // @ts-expect-error - Elysia WebSocket types from optional peer dependency\n message(ws, message) {\n // Handle client state updates\n const data = JSON.parse(message as unknown as string);\n\n if (data.type === \"state-update\") {\n const clientId = ws.data.headers?.[\"x-client-id\"];\n if (clientId) {\n clientStateByConnection.set(clientId, data.state);\n }\n }\n },\n })\n\n // Authorization hook (runs before handler)\n // @ts-expect-error - Elysia context types from optional peer dependency\n .onBeforeHandle(async ({ request, pollyState, body, params }) => {\n const method = request.method;\n const path = new URL(request.url).pathname;\n\n const authHandler = findMatchingConfig(config.authorization, method, path);\n\n if (authHandler) {\n const allowed = await authHandler({\n state: pollyState,\n body,\n params,\n headers: Object.fromEntries(request.headers.entries()),\n });\n\n if (!allowed) {\n return new Response(\"Unauthorized\", { status: 403 });\n }\n }\n })\n\n // Response hook (runs after handler)\n // @ts-expect-error - Elysia context types from optional peer dependency\n .onAfterHandle(\n async ({ request, response, _pollyState, pollyClock, pollyBroadcast, _body, _params }) => {\n const method = request.method;\n const path = new URL(request.url).pathname;\n\n // Find matching effect config\n const effectConfig = findMatchingConfig(config.effects, method, path);\n\n // Tick clock\n pollyClock.tick();\n\n // If broadcast enabled, send to all connected clients\n // This works in both dev and prod for real-time updates\n if (effectConfig?.broadcast) {\n const broadcastMessage = {\n type: \"effect\",\n path,\n method,\n result: response,\n clock: pollyClock.now(),\n };\n\n if (effectConfig.broadcastFilter) {\n pollyBroadcast.broadcast(broadcastMessage, (clientId) => {\n const clientState = clientStateByConnection.get(clientId) || {};\n return effectConfig.broadcastFilter?.(clientState) ?? false;\n });\n } else {\n pollyBroadcast.broadcast(broadcastMessage);\n }\n }\n\n // In production, skip expensive metadata operations\n if (!isDev) {\n return response;\n }\n\n // DEV ONLY: Add Polly metadata to response for debugging/hot-reload\n const offlineConfig = findMatchingConfig(config.offline, method, path);\n const metadata: PollyResponseMetadata = {\n clientEffect: effectConfig\n ? {\n handler: serializeFunction(effectConfig.client),\n broadcast: effectConfig.broadcast || false,\n }\n : undefined,\n offline: offlineConfig,\n clock: pollyClock.now(),\n };\n\n // Attach metadata as header\n return new Response(JSON.stringify(response), {\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Polly-Metadata\": JSON.stringify(metadata),\n },\n });\n }\n );\n\n return app;\n}\n",
|
|
8
8
|
"/**\n * Lamport Clock Implementation\n *\n * Provides logical timestamps for distributed systems to establish\n * causal ordering of events across different contexts (client/server).\n *\n * Key properties:\n * - Each event increments the local clock\n * - When receiving a message, clock = max(local, received) + 1\n * - If A happens before B, then timestamp(A) < timestamp(B)\n *\n * References:\n * - Lamport, L. (1978). \"Time, Clocks, and the Ordering of Events in a Distributed System\"\n * - https://lamport.azurewebsites.net/pubs/time-clocks.pdf\n */\n\n/**\n * Lamport clock state\n */\nexport interface LamportClock {\n tick: number;\n contextId: string;\n}\n\n/**\n * Lamport clock with operations\n */\nexport interface LamportClockOps {\n /**\n * Get current clock value\n */\n now(): LamportClock;\n\n /**\n * Increment the clock (before sending a message or performing an action)\n */\n tick(): number;\n\n /**\n * Update clock when receiving a message\n * Sets clock to max(local, received) + 1\n */\n update(receivedClock: LamportClock): void;\n}\n\n/**\n * Create a Lamport clock for a specific context\n *\n * @param contextId - Unique identifier for this context (e.g., \"client\", \"server\", \"worker-1\")\n * @returns Clock operations\n *\n * @example\n * ```typescript\n * const serverClock = createLamportClock(\"server\");\n *\n * // Before sending a message\n * serverClock.tick();\n * const timestamp = serverClock.now();\n * send({ data: \"...\", clock: timestamp });\n *\n * // When receiving a message\n * onReceive((message) => {\n * serverClock.update(message.clock);\n * // Process message with updated clock\n * });\n * ```\n */\nexport function createLamportClock(contextId: string): LamportClockOps {\n let tick = 0;\n\n return {\n now(): LamportClock {\n return { tick, contextId };\n },\n\n tick(): number {\n tick += 1;\n return tick;\n },\n\n update(receivedClock: LamportClock): void {\n tick = Math.max(tick, receivedClock.tick) + 1;\n },\n };\n}\n",
|
|
9
9
|
"import serialize from \"serialize-javascript\";\n\n/**\n * Check if we're in development mode\n */\nconst isDev = process.env.NODE_ENV !== \"production\";\n\n/**\n * Serialize a function to send to client\n *\n * DEV ONLY: Used for hot reloading and debugging\n * PROD: No-op - client effects are baked into bundle at build time\n */\n// biome-ignore lint/complexity/noBannedTypes: Generic function serialization requires Function type\nexport function serializeFunction(fn: Function): string {\n if (!isDev) {\n // In production, return empty string - this won't be used\n return \"\";\n }\n\n return serialize(fn, { space: 0 });\n}\n\n/**\n * Deserialize a function received from server\n *\n * DEV ONLY: Eval serialized function source\n * PROD: Should never be called - effects come from bundle\n */\n// biome-ignore lint/complexity/noBannedTypes: Generic function deserialization requires Function type\nexport function deserializeFunction(serialized: string): Function {\n if (!isDev) {\n throw new Error(\n \"[Polly] deserializeFunction should not be called in production. \" +\n \"Client effects should be imported from your bundle.\"\n );\n }\n\n if (!serialized) {\n throw new Error(\"[Polly] Cannot deserialize empty function\");\n }\n\n // biome-ignore lint/security/noGlobalEval: Required for dev-mode function deserialization\n return eval(`(${serialized})`);\n}\n",
|
|
10
10
|
"// @ts-nocheck - Optional peer dependencies (elysia, @elysiajs/eden)\n/**\n * signalingServer — Phase 2 Elysia plugin that exposes a stateless\n * WebSocket route for SDP/ICE relay between $meshState peers.\n *\n * The mesh transport is a star-of-data-channels: peers establish direct\n * WebRTC connections to each other and exchange document operations\n * peer-to-peer once those channels are open. WebRTC connection setup\n * needs an out-of-band channel for SDP offer/answer and ICE candidate\n * exchange, and that channel is what this plugin provides. The plugin\n * does not own any document state, does not hold any encryption keys,\n * and never inspects the contents of the messages it relays. It is a\n * pure pub-sub by peer id.\n *\n * Once two peers have completed the SDP exchange and opened a direct\n * data channel, the signalling server is no longer on the critical\n * path — the peers talk directly. The signalling server's role is\n * therefore intermittent: peers connect to it only during the brief\n * windows when they are establishing or re-establishing connections.\n *\n * Wire protocol:\n *\n * Client → server (join):\n * { type: \"join\", peerId: \"peer-alice\" }\n *\n * Client → server (signal to another peer):\n * { type: \"signal\", peerId: \"peer-alice\", targetPeerId: \"peer-bob\",\n * payload: { ... } }\n *\n * Server → client (delivered signal):\n * { type: \"signal\", peerId: \"peer-alice\", targetPeerId: \"peer-bob\",\n * payload: { ... } }\n *\n * Server → client (notification of unknown target):\n * { type: \"error\", reason: \"unknown-target\", targetPeerId: \"...\" }\n *\n * The `payload` is opaque to the signalling server — typically it\n * carries an SDP offer, SDP answer, or ICE candidate. Applications can\n * also use the relay for any other peer-to-peer message that needs an\n * intermediary, such as the initial handshake of a pairing flow.\n *\n * @example\n * ```ts\n * import { Elysia } from \"elysia\";\n * import { signalingServer } from \"@fairfox/polly/elysia\";\n *\n * const app = new Elysia()\n * .use(signalingServer({ path: \"/polly/signaling\" }))\n * .listen(8080);\n * ```\n */\n\nimport { Elysia } from \"elysia\";\n\n/** A signalling message. The `type` discriminates between join (peer\n * registration), signal (relayed message), and error (server response). */\nexport type SignalingMessage =\n | {\n type: \"join\";\n /** The peer registering itself with the signalling server. */\n peerId: string;\n }\n | {\n type: \"signal\";\n /** The peer sending the signal. */\n peerId: string;\n /** The peer the signal is being relayed to. */\n targetPeerId: string;\n /** Opaque payload, typically SDP or ICE. */\n payload: unknown;\n }\n | {\n type: \"error\";\n reason: \"unknown-target\" | \"not-joined\" | \"malformed\";\n targetPeerId?: string;\n };\n\nexport interface SignalingServerOptions {\n /** WebSocket route path. Defaults to \"/polly/signaling\". */\n path?: string;\n}\n\n/**\n * Construct the signalling-server Elysia plugin. The plugin keeps a\n * per-instance map of peer id → WebSocket connection so that incoming\n * \"signal\" messages can be routed to the right target socket. The map\n * is local to the plugin instance, not shared across processes; for\n * multi-instance deployments behind a load balancer, applications need\n * sticky connection routing or a shared backplane (Redis pub-sub or\n * similar). That is a follow-up.\n */\nexport function signalingServer(options: SignalingServerOptions = {}) {\n const path = options.path ?? \"/polly/signaling\";\n // Per-peer-id map of joined sockets. The inverse mapping is stored\n // directly on ws.data (a mutable property bag that Elysia preserves\n // across message callbacks for a given connection); the webrtc-p2p-chat\n // example in examples/ confirms this pattern is stable under Bun.\n const peerSockets = new Map<string, { send: (msg: unknown) => void }>();\n\n // Intentionally unnamed — Elysia deduplicates plugins by name, and each\n // signalingServer() call needs its own closure-captured peer map.\n const parseMessage = (raw: unknown): SignalingMessage | undefined => {\n try {\n return typeof raw === \"string\" ? JSON.parse(raw) : (raw as unknown as SignalingMessage);\n } catch {\n return undefined;\n }\n };\n\n const handleJoin = (ws: unknown, peerId: string): void => {\n peerSockets.set(peerId, ws as unknown as { send: (m: unknown) => void });\n const wsWithData = ws as unknown as { data: Record<string, unknown> };\n wsWithData.data.peerId = peerId;\n };\n\n const sendUnknownTarget = (ws: unknown, targetPeerId: string): void => {\n (ws as unknown as { send: (m: unknown) => void }).send({\n type: \"error\",\n reason: \"unknown-target\",\n targetPeerId,\n } as unknown as SignalingMessage);\n };\n\n /** Look up a target socket and confirm it is still open. */\n const findOpenTarget = (targetPeerId: string): { send: (msg: unknown) => void } | undefined => {\n const target = peerSockets.get(targetPeerId);\n if (!target) return undefined;\n const readyState = (target as unknown as { readyState?: number }).readyState;\n const OPEN = 1;\n if (readyState !== undefined && readyState !== OPEN) {\n peerSockets.delete(targetPeerId);\n return undefined;\n }\n return target;\n };\n\n const handleSignal = (ws: unknown, msg: Extract<SignalingMessage, { type: \"signal\" }>): void => {\n const wsWithData = ws as unknown as {\n data: Record<string, unknown>;\n send: (m: unknown) => void;\n };\n const senderId = wsWithData.data.peerId as unknown as string | undefined;\n if (!senderId) {\n wsWithData.send({ type: \"error\", reason: \"not-joined\" } as unknown as SignalingMessage);\n return;\n }\n const target = findOpenTarget(msg.targetPeerId);\n if (!target) {\n sendUnknownTarget(ws, msg.targetPeerId);\n return;\n }\n const relayed: SignalingMessage = {\n type: \"signal\",\n peerId: senderId,\n targetPeerId: msg.targetPeerId,\n payload: msg.payload,\n };\n try {\n target.send(relayed);\n } catch {\n peerSockets.delete(msg.targetPeerId);\n sendUnknownTarget(ws, msg.targetPeerId);\n }\n };\n\n return new Elysia().ws(path, {\n message(ws, raw) {\n const msg = parseMessage(raw);\n if (!msg) {\n ws.send({ type: \"error\", reason: \"malformed\" } as unknown as SignalingMessage);\n return;\n }\n if (msg.type === \"join\") {\n handleJoin(ws, msg.peerId);\n return;\n }\n if (msg.type === \"signal\") {\n handleSignal(ws, msg);\n return;\n }\n ws.send({ type: \"error\", reason: \"malformed\" } as unknown as SignalingMessage);\n },\n\n close(ws) {\n const peerId = (ws.data as unknown as Record<string, unknown>).peerId as unknown as\n | string\n | undefined;\n if (peerId) {\n // Only delete the entry if it still points at *this* socket, so a\n // stale close after a reconnect does not evict the new socket.\n if (peerSockets.get(peerId) === (ws as unknown as { send: (m: unknown) => void })) {\n peerSockets.delete(peerId);\n }\n }\n },\n });\n}\n"
|
|
11
11
|
],
|
|
12
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA;;;
|
|
13
|
-
"debugId": "
|
|
12
|
+
"mappings": "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",
|
|
13
|
+
"debugId": "ABCACD6B736E00DA64756E2164756E21",
|
|
14
14
|
"names": []
|
|
15
15
|
}
|
package/dist/src/peer.js
CHANGED
|
@@ -817,11 +817,13 @@ function createPeerStateClient(options) {
|
|
|
817
817
|
};
|
|
818
818
|
}
|
|
819
819
|
// src/shared/lib/peer-repo-server.ts
|
|
820
|
-
import { Repo as Repo2 } from "@automerge/automerge-repo/slim";
|
|
821
|
-
import { WebSocketServerAdapter } from "@automerge/automerge-repo-network-websocket";
|
|
822
|
-
import { NodeFSStorageAdapter } from "@automerge/automerge-repo-storage-nodefs";
|
|
823
|
-
import * as ws from "ws";
|
|
824
820
|
async function createPeerRepoServer(options) {
|
|
821
|
+
const [{ Repo: Repo2 }, { WebSocketServerAdapter }, { NodeFSStorageAdapter }, ws] = await Promise.all([
|
|
822
|
+
import("@automerge/automerge-repo/slim"),
|
|
823
|
+
import("@automerge/automerge-repo-network-websocket"),
|
|
824
|
+
import("@automerge/automerge-repo-storage-nodefs"),
|
|
825
|
+
import("ws")
|
|
826
|
+
]);
|
|
825
827
|
const wss = await (options.webSocketServer ? Promise.resolve(options.webSocketServer) : new Promise((resolve, reject) => {
|
|
826
828
|
const created = new ws.WebSocketServer({
|
|
827
829
|
port: options.port,
|
|
@@ -973,4 +975,4 @@ export {
|
|
|
973
975
|
$crdtCounter
|
|
974
976
|
};
|
|
975
977
|
|
|
976
|
-
//# debugId=
|
|
978
|
+
//# debugId=E758423470D8955364756E2164756E21
|
package/dist/src/peer.js.map
CHANGED
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"/**\n * peer-relay-adapter — Phase 1 client helper for connecting a Polly $peerState\n * application to an Automerge-Repo relay server over WebSocket.\n *\n * The Phase 0 base $crdtState and the Phase 1 $peerState wrapper both consume\n * a caller-supplied `Repo` via `configurePeerState`. This module provides the\n * one-call factory that builds a Repo wired to the relay transport: a\n * `WebSocketClientAdapter` from `@automerge/automerge-repo-network-websocket`\n * pointed at the server URL, an `IndexedDBStorageAdapter` for client-side\n * persistence, and a Polly-shaped connection-state signal that the application\n * can render as a diagnostic UI or feed into reconnection logic.\n *\n * The mirror server-side factory is in {@link peer-repo-server}.\n *\n * @example\n * ```ts\n * import { configurePeerState } from \"@fairfox/polly\";\n * import { createPeerStateClient } from \"@fairfox/polly\";\n *\n * const { repo, connectionState } = await createPeerStateClient({\n * url: \"wss://yourapp.example.com/polly/peer\",\n * });\n * configurePeerState(repo);\n *\n * // connectionState is a Signal<\"connecting\" | \"connected\" | \"disconnected\">\n * ```\n */\n\nimport { type NetworkAdapterInterface, Repo } from \"@automerge/automerge-repo/slim\";\nimport { WebSocketClientAdapter } from \"@automerge/automerge-repo-network-websocket\";\nimport { type Signal, signal } from \"@preact/signals\";\nimport { type MeshKeyring, MeshNetworkAdapter } from \"./mesh-network-adapter\";\n\nexport type PeerRelayConnectionState = \"connecting\" | \"connected\" | \"disconnected\";\n\nexport interface CreatePeerStateClientOptions {\n /** WebSocket URL of the Polly peer-relay server. Use `ws://` for local\n * development and `wss://` for any deployment that terminates TLS. */\n url: string;\n /** Reconnect interval in milliseconds. Defaults to Automerge-Repo's own\n * default (5 seconds at the time of writing). */\n retryInterval?: number;\n /** Optional storage adapter. Applications running in a browser typically\n * pass an `IndexedDBStorageAdapter`; tests pass nothing for a local-only\n * Repo. The default is no storage, which keeps the client purely in-memory. */\n storage?: ConstructorParameters<typeof Repo>[0] extends infer C\n ? C extends { storage?: infer S }\n ? S\n : never\n : never;\n /** Enable Ed25519 signing on every sync message. Adds Byzantine defence:\n * a compromised client cannot push unsigned writes through the relay.\n * Requires a keyring with the local peer's signing identity and the\n * public keys of peers whose ops should be accepted. The server can\n * still read and mutate document contents because the payload is\n * signed, not encrypted. */\n sign?: boolean;\n /** Keyring for the signing layer. Required when `sign` is true. */\n keyring?: MeshKeyring;\n}\n\nexport interface PeerStateClient {\n /** A configured Repo backed by the WebSocket relay. Pass to\n * {@link configurePeerState}. */\n repo: Repo;\n /** Reactive connection state. Updates as the underlying WebSocket opens,\n * closes, and reconnects. */\n connectionState: Signal<PeerRelayConnectionState>;\n /** The underlying network adapter, exposed for advanced use. */\n adapter: WebSocketClientAdapter;\n /** True if the client was constructed with `sign: true`. Used by\n * $peerState primitives to validate per-primitive sign options. */\n signEnabled: boolean;\n /** Disconnect from the relay and tear down the Repo. Awaiting the\n * returned promise drains the Repo's subsystems cleanly. */\n close: () => Promise<void>;\n}\n\n/**\n * Construct a Polly-flavoured client for the peer-relay transport.\n *\n * The returned object includes the Repo, a connection-state signal, the\n * underlying network adapter, and a close function. Production code typically\n * passes the Repo to {@link configurePeerState} and renders the connection\n * state somewhere visible.\n */\nexport function createPeerStateClient(options: CreatePeerStateClientOptions): PeerStateClient {\n if (options.sign && !options.keyring) {\n throw new Error(\n \"Polly createPeerStateClient: { sign: true } requires a keyring. Pass { keyring: { identity, knownPeers, documentKeys: new Map(), revokedPeers: new Set() } } to enable signing.\"\n );\n }\n\n const adapter = new WebSocketClientAdapter(options.url, options.retryInterval);\n const connectionState = signal<PeerRelayConnectionState>(\"connecting\");\n\n // The WebSocketClientAdapter is itself an EventEmitter (via Automerge's\n // NetworkAdapter base class) and emits 'peer-candidate' / 'peer-disconnected'\n // events. We track the simpler open/close lifecycle by listening to those.\n adapter.on(\"peer-candidate\", () => {\n connectionState.value = \"connected\";\n });\n adapter.on(\"peer-disconnected\", () => {\n connectionState.value = \"disconnected\";\n });\n adapter.on(\"close\", () => {\n connectionState.value = \"disconnected\";\n });\n\n // When signing is enabled, wrap the WebSocket adapter with a sign-only\n // MeshNetworkAdapter. This signs every outgoing message but does NOT\n // encrypt, so the relay server can still parse Automerge sync messages\n // and participate as a full peer (cron, HTTP handlers, etc.).\n const networkAdapter: NetworkAdapterInterface =\n options.sign && options.keyring\n ? new MeshNetworkAdapter({\n base: adapter,\n keyring: options.keyring,\n encryptionEnabled: false,\n })\n : adapter;\n\n const repo = new Repo({\n network: [networkAdapter],\n ...(options.storage !== undefined && { storage: options.storage }),\n });\n\n return {\n repo,\n connectionState,\n adapter,\n signEnabled: options.sign === true,\n close: async () => {\n await repo.shutdown();\n },\n };\n}\n",
|
|
13
13
|
"/**\n * mesh-network-adapter — Phase 2 wrapping NetworkAdapter that adds Polly's\n * mesh-transport semantics on top of any underlying Automerge NetworkAdapter.\n *\n * The mesh transport's job is to make every message between peers signed\n * and encrypted before it reaches the wire. Rather than reimplementing the\n * Automerge sync protocol, this adapter takes a base adapter (in production\n * a real WebRTC or WebSocket adapter; in tests an in-memory loopback) and\n * applies the crypto envelope to every message that flows through.\n *\n * Outgoing path (Repo → wire):\n * 1. The Repo's NetworkSubsystem calls send(message) on this adapter.\n * 2. We serialise the message to bytes, encrypt them under the local\n * keyring's document key, sign the resulting blob with the local\n * identity's secret key, and pack the pair into a MeshFrame.\n * 3. We hand the MeshFrame off to the base adapter, which puts it on\n * whatever wire it owns.\n *\n * Incoming path (wire → Repo):\n * 1. The base adapter emits a 'message' event with bytes from the wire.\n * 2. We unpack the MeshFrame, look up the sender's public key in the\n * keyring, verify the signature, look up the document key, decrypt\n * the payload, and deserialise it back to the original message.\n * 3. We re-emit the 'message' event upward to the Repo's NetworkSubsystem\n * with the decrypted message.\n *\n * The keyring is an injected dependency. In production it's backed by\n * persistent storage and populated through the pairing flow. For tests it\n * is just a Map of publicly-known fixtures that both sides share.\n *\n * Caveat for the Phase 2 first cut: Automerge sync messages don't have a\n * stable \"what document does this belong to\" field at the wire level (the\n * documentId is part of the message contents). The mesh adapter therefore\n * uses a single per-Repo encryption key for now rather than per-document\n * keys, and stores the key once in the keyring under the well-known id\n * \"polly-mesh-default\". The plan describes per-document keys as the right\n * end state; that requires either parsing the message to extract the\n * documentId before encrypting (peeking inside the binary protocol) or\n * threading the document context through the network subsystem (which\n * needs upstream support). A follow-up will address this.\n */\n\nimport {\n type Message,\n NetworkAdapter,\n type PeerId,\n type PeerMetadata,\n} from \"@automerge/automerge-repo/slim\";\nimport {\n decodeEncryptedEnvelope,\n encodeEncryptedEnvelope,\n openEnvelope as openEncryptedEnvelope,\n sealEnvelope as sealEncryptedEnvelope,\n} from \"./encryption\";\nimport {\n decodeSignedEnvelope,\n encodeSignedEnvelope,\n openEnvelope as openSignedEnvelope,\n type SigningKeyPair,\n signEnvelope,\n} from \"./signing\";\n\n/** The well-known document id used for the Phase 2 first-cut single-key\n * encryption mode. See the file-level comment for the per-document key\n * follow-up. */\nexport const DEFAULT_MESH_KEY_ID = \"polly-mesh-default\";\n\n/**\n * A mesh keyring holds the local peer's signing identity, the public keys\n * of every peer the local node will accept messages from, the symmetric\n * encryption keys for documents the local node has access to, and the set\n * of peers whose keys have been revoked.\n */\nexport interface MeshKeyring {\n /** The local peer's signing keypair. The secret never leaves this\n * keyring; the public key is gossiped through the access set. */\n identity: SigningKeyPair;\n /** Map from peer id (string) to that peer's signing public key. The\n * mesh adapter rejects messages from peers not present in this map. */\n knownPeers: Map<string, Uint8Array>;\n /** Map from document key id (typically the documentId, or the well-known\n * default for the single-key first cut) to the symmetric encryption key. */\n documentKeys: Map<string, Uint8Array>;\n /** Set of peer ids whose keys have been revoked. The mesh adapter drops\n * incoming messages from any peer in this set, even if the peer is still\n * present in {@link knownPeers}. Revocation is applied via the revocation\n * module; the set is kept separate from knownPeers so that an application\n * can audit who was once authorised without losing the revocation record. */\n revokedPeers: Set<string>;\n /** Optional set of peer ids authorised to issue revocations. When present\n * and non-empty, `decodeRevocation` accepts a signed record only if the\n * issuer is in this set. When undefined or empty, any signed revocation\n * from a known peer is accepted (the Phase 2 first-cut default). This\n * field layers a \"who can revoke whom\" check on top of the signature\n * layer without breaking existing callers. */\n revocationAuthority?: Set<string>;\n}\n\n/**\n * Constructor options for {@link MeshNetworkAdapter}.\n */\nexport interface MeshNetworkAdapterOptions {\n /** The underlying NetworkAdapter that puts crypto-wrapped bytes on the\n * wire. In production this is a WebRTC or WebSocket adapter; in tests\n * it's an in-memory loopback. */\n base: NetworkAdapter;\n /** The local node's keyring. The adapter signs every outgoing message\n * with `identity.secretKey` and verifies every incoming message against\n * the public keys in `knownPeers`. */\n keyring: MeshKeyring;\n /** When false, the adapter signs but does not encrypt. Outgoing messages\n * carry a signature envelope but the payload is plaintext; incoming\n * messages are verified against the sender's public key without a\n * decryption step. This mode is used by $peerState's `sign: true`\n * option, where the server must still be able to parse Automerge sync\n * messages. Defaults to true (encrypt + sign, the full $meshState\n * posture). */\n encryptionEnabled?: boolean;\n}\n\n/**\n * NetworkAdapter that wraps another adapter with Polly's mesh-transport\n * crypto envelope. Every outgoing message is encrypted then signed; every\n * incoming message is verified then decrypted before being forwarded to\n * the Repo's network subsystem.\n *\n * The adapter delegates lifecycle (connect, disconnect, isReady, peer\n * discovery) to the base adapter unchanged. Only the message body is\n * intercepted.\n */\nexport class MeshNetworkAdapter extends NetworkAdapter {\n readonly base: NetworkAdapter;\n readonly keyring: MeshKeyring;\n readonly encryptionEnabled: boolean;\n\n constructor(options: MeshNetworkAdapterOptions) {\n super();\n this.base = options.base;\n this.keyring = options.keyring;\n this.encryptionEnabled = options.encryptionEnabled ?? true;\n\n // Forward lifecycle and peer events from the base adapter.\n this.base.on(\"close\", () => this.emit(\"close\"));\n this.base.on(\"peer-candidate\", (payload) => this.emit(\"peer-candidate\", payload));\n this.base.on(\"peer-disconnected\", (payload) => this.emit(\"peer-disconnected\", payload));\n\n // Intercept incoming messages: the base adapter will surface them as\n // 'message' events with crypto-wrapped payloads. We unwrap and re-emit.\n this.base.on(\"message\", (rawMessage) => {\n const unwrapped = this.tryUnwrap(rawMessage);\n if (unwrapped) {\n this.emit(\"message\", unwrapped);\n }\n // Silently drop messages that fail verification or decryption. A\n // production adapter would surface this through a diagnostic channel\n // so the application could prompt the user; the Phase 2 first cut\n // logs through the standard \"drop unknown\" semantics of the network\n // subsystem.\n });\n }\n\n isReady(): boolean {\n return this.base.isReady();\n }\n\n whenReady(): Promise<void> {\n return this.base.whenReady();\n }\n\n connect(peerId: PeerId, peerMetadata?: PeerMetadata): void {\n this.peerId = peerId;\n if (peerMetadata !== undefined) {\n this.peerMetadata = peerMetadata;\n }\n this.base.connect(peerId, peerMetadata);\n }\n\n disconnect(): void {\n this.base.disconnect();\n }\n\n send(message: Message): void {\n const wrapped = this.wrap(message);\n this.base.send(wrapped);\n }\n\n /**\n * Wrap an outgoing Automerge message in an encrypt-then-sign envelope.\n * The wrapped payload is returned as a Message with the original sender\n * and target ids and the crypto blob in the `data` field.\n */\n private wrap(message: Message): Message {\n const serialised = serialiseMessage(message);\n\n let payloadToSign: Uint8Array;\n if (this.encryptionEnabled) {\n const docKey = this.keyring.documentKeys.get(DEFAULT_MESH_KEY_ID);\n if (!docKey) {\n throw new Error(\n `MeshNetworkAdapter: missing document encryption key under id \"${DEFAULT_MESH_KEY_ID}\". Provision the key in the keyring before sending.`\n );\n }\n const encrypted = sealEncryptedEnvelope(serialised, DEFAULT_MESH_KEY_ID, docKey);\n payloadToSign = encodeEncryptedEnvelope(encrypted);\n } else {\n payloadToSign = serialised;\n }\n\n const signed = signEnvelope(payloadToSign, message.senderId, this.keyring.identity.secretKey);\n const signedBytes = encodeSignedEnvelope(signed);\n\n return {\n type: message.type,\n senderId: message.senderId,\n targetId: message.targetId,\n data: signedBytes,\n } as unknown as Message;\n }\n\n /**\n * Try to unwrap an incoming crypto-wrapped message. Returns the original\n * Message on success, undefined on verification or decryption failure.\n */\n private tryUnwrap(message: Message): Message | undefined {\n if (!message.data) return undefined;\n\n let signed: ReturnType<typeof decodeSignedEnvelope>;\n try {\n signed = decodeSignedEnvelope(message.data);\n } catch {\n return undefined;\n }\n\n // Drop messages from peers whose keys have been revoked, even if the\n // public key is still present in knownPeers. The revocation set is the\n // authoritative \"this peer is no longer trusted\" marker.\n if (this.keyring.revokedPeers.has(signed.senderId)) {\n return undefined;\n }\n\n const senderKey = this.keyring.knownPeers.get(signed.senderId);\n if (!senderKey) {\n return undefined;\n }\n\n let verifiedPayload: Uint8Array;\n try {\n verifiedPayload = openSignedEnvelope(signed, senderKey);\n } catch {\n return undefined;\n }\n\n if (!this.encryptionEnabled) {\n // Sign-only mode: the verified payload IS the serialised message.\n return deserialiseMessage(verifiedPayload);\n }\n\n // Full encrypt+sign mode: unwrap the encryption envelope.\n let encrypted: ReturnType<typeof decodeEncryptedEnvelope>;\n try {\n encrypted = decodeEncryptedEnvelope(verifiedPayload);\n } catch {\n return undefined;\n }\n\n const docKey = this.keyring.documentKeys.get(encrypted.documentId);\n if (!docKey) {\n return undefined;\n }\n\n let plaintext: Uint8Array;\n try {\n plaintext = openEncryptedEnvelope(encrypted, docKey);\n } catch {\n return undefined;\n }\n\n return deserialiseMessage(plaintext);\n }\n}\n\n// ─── message serialisation ─────────────────────────────────────────────────\n\n/**\n * Serialise an Automerge sync message to a binary blob suitable for\n * encryption. The format is a length-prefixed JSON header (carrying the\n * non-binary fields) followed by the raw `data` bytes (which Automerge's\n * sync messages carry as Uint8Array). This avoids round-tripping the\n * binary payload through JSON, which would balloon its size.\n */\nfunction serialiseMessage(message: Message): Uint8Array {\n const headerObj: Record<string, unknown> = {\n type: message.type,\n senderId: message.senderId,\n targetId: message.targetId,\n };\n if (\"documentId\" in message && message.documentId !== undefined) {\n headerObj[\"documentId\"] = message.documentId;\n }\n if (\"count\" in message && message.count !== undefined) {\n headerObj[\"count\"] = message.count;\n }\n if (\"sessionId\" in message && message.sessionId !== undefined) {\n headerObj[\"sessionId\"] = message.sessionId;\n }\n const headerBytes = new TextEncoder().encode(JSON.stringify(headerObj));\n const dataBytes: Uint8Array =\n \"data\" in message && message.data instanceof Uint8Array ? message.data : new Uint8Array(0);\n\n const out = new Uint8Array(4 + headerBytes.length + dataBytes.length);\n const view = new DataView(out.buffer);\n view.setUint32(0, headerBytes.length, false);\n out.set(headerBytes, 4);\n out.set(dataBytes, 4 + headerBytes.length);\n return out;\n}\n\n/**\n * Inverse of {@link serialiseMessage}.\n */\nfunction deserialiseMessage(bytes: Uint8Array): Message {\n if (bytes.length < 4) {\n throw new Error(\"MeshNetworkAdapter: message too short to deserialise.\");\n }\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const headerLen = view.getUint32(0, false);\n if (bytes.length < 4 + headerLen) {\n throw new Error(\"MeshNetworkAdapter: message header truncated.\");\n }\n const header = JSON.parse(new TextDecoder().decode(bytes.subarray(4, 4 + headerLen)));\n const data = bytes.slice(4 + headerLen);\n return { ...header, data } as unknown as Message;\n}\n",
|
|
14
14
|
"/**\n * signing — Ed25519 signing and verification for Polly's $meshState\n * primitive (Phase 2). Wraps tweetnacl with a small Polly-flavoured API\n * so the rest of the codebase never imports tweetnacl directly.\n *\n * Every operation that flows through a $meshState transport is signed by\n * the originating peer's private key before transmission and verified by\n * every receiving peer against a known public-key set before being applied.\n * This is the Byzantine-tolerance mechanism: a peer whose private key is\n * compromised can be revoked through a further signed operation, after\n * which honest peers reject anything signed by the revoked key.\n *\n * tweetnacl uses the Ed25519 curve. Public keys and signatures are 32 and\n * 64 bytes respectively, which keeps the per-op overhead small enough that\n * signing every Automerge sync message is feasible even on mobile.\n *\n * The shape of the wrapper:\n *\n * - {@link generateSigningKeyPair} produces a new Ed25519 keypair. The\n * private key never leaves the device that generated it; the public\n * key is gossiped through the access set.\n *\n * - {@link sign} produces a 64-byte detached signature over a payload.\n *\n * - {@link verify} checks a payload against a signature and a public\n * key. Returns boolean rather than throwing so call sites can handle\n * verification failure as a normal control-flow case.\n *\n * - {@link signEnvelope} and {@link openEnvelope} package payload + sender\n * id + signature into a single binary envelope, which is what the mesh\n * network adapter actually puts on the wire.\n */\n\nimport nacl from \"tweetnacl\";\n\n/** Length in bytes of an Ed25519 public key. */\nexport const PUBLIC_KEY_BYTES = 32;\n/** Length in bytes of an Ed25519 secret (private) key. */\nexport const SECRET_KEY_BYTES = 64;\n/** Length in bytes of an Ed25519 detached signature. */\nexport const SIGNATURE_BYTES = 64;\n\n/**\n * An Ed25519 keypair. The {@link publicKey} is safe to share with peers;\n * the {@link secretKey} must never leave the device.\n */\nexport interface SigningKeyPair {\n publicKey: Uint8Array;\n secretKey: Uint8Array;\n}\n\n/**\n * A signed envelope. The wire format is the concatenation of the sender id\n * length, the sender id bytes, the signature, and the payload. Callers\n * shouldn't rely on the exact layout — use {@link signEnvelope} and\n * {@link openEnvelope} to round-trip.\n */\nexport interface SignedEnvelope {\n /** Stable sender peer identifier (UTF-8 string). The receiving side uses\n * this to look up the sender's public key in the document's access set. */\n senderId: string;\n /** The original payload bytes, untouched. */\n payload: Uint8Array;\n /** 64-byte Ed25519 signature over the payload. */\n signature: Uint8Array;\n}\n\n/** Errors thrown by the signing subsystem. */\nexport class SigningError extends Error {\n readonly code:\n | \"invalid-secret-key\"\n | \"invalid-public-key\"\n | \"invalid-signature-length\"\n | \"envelope-malformed\";\n\n constructor(message: string, code: SigningError[\"code\"]) {\n super(message);\n this.name = \"SigningError\";\n this.code = code;\n }\n}\n\n/**\n * Generate a fresh Ed25519 keypair. Calls into tweetnacl's CSPRNG.\n */\nexport function generateSigningKeyPair(): SigningKeyPair {\n const pair = nacl.sign.keyPair();\n return {\n publicKey: pair.publicKey,\n secretKey: pair.secretKey,\n };\n}\n\n/**\n * Reconstruct a keypair from an existing 64-byte secret key. Useful for\n * loading keys from persistent storage. Throws if the key is the wrong size.\n */\nexport function signingKeyPairFromSecret(secretKey: Uint8Array): SigningKeyPair {\n if (secretKey.length !== SECRET_KEY_BYTES) {\n throw new SigningError(\n `Ed25519 secret key must be ${SECRET_KEY_BYTES} bytes, got ${secretKey.length}.`,\n \"invalid-secret-key\"\n );\n }\n const pair = nacl.sign.keyPair.fromSecretKey(secretKey);\n return {\n publicKey: pair.publicKey,\n secretKey: pair.secretKey,\n };\n}\n\n/**\n * Produce a 64-byte detached signature over the given payload using the\n * supplied secret key.\n */\nexport function sign(payload: Uint8Array, secretKey: Uint8Array): Uint8Array {\n if (secretKey.length !== SECRET_KEY_BYTES) {\n throw new SigningError(\n `Ed25519 secret key must be ${SECRET_KEY_BYTES} bytes, got ${secretKey.length}.`,\n \"invalid-secret-key\"\n );\n }\n return nacl.sign.detached(payload, secretKey);\n}\n\n/**\n * Verify a detached signature against a payload and a public key. Returns\n * true if the signature is valid, false otherwise. Wrong-length keys or\n * signatures throw {@link SigningError} so callers can distinguish a bad\n * signature from a misshapen input.\n */\nexport function verify(payload: Uint8Array, signature: Uint8Array, publicKey: Uint8Array): boolean {\n if (publicKey.length !== PUBLIC_KEY_BYTES) {\n throw new SigningError(\n `Ed25519 public key must be ${PUBLIC_KEY_BYTES} bytes, got ${publicKey.length}.`,\n \"invalid-public-key\"\n );\n }\n if (signature.length !== SIGNATURE_BYTES) {\n throw new SigningError(\n `Ed25519 signature must be ${SIGNATURE_BYTES} bytes, got ${signature.length}.`,\n \"invalid-signature-length\"\n );\n }\n return nacl.sign.detached.verify(payload, signature, publicKey);\n}\n\n/**\n * Sign a payload and pack it into a {@link SignedEnvelope} along with the\n * sender id. The mesh network adapter calls this on every outgoing message\n * before handing it to the transport.\n */\nexport function signEnvelope(\n payload: Uint8Array,\n senderId: string,\n secretKey: Uint8Array\n): SignedEnvelope {\n const signature = sign(payload, secretKey);\n return { senderId, payload, signature };\n}\n\n/**\n * Verify a {@link SignedEnvelope} against the sender's known public key.\n * Returns the inner payload on success, throws on failure. The mesh\n * network adapter calls this on every incoming message before forwarding\n * the payload to the underlying Automerge sync subsystem.\n */\nexport function openEnvelope(envelope: SignedEnvelope, publicKey: Uint8Array): Uint8Array {\n const ok = verify(envelope.payload, envelope.signature, publicKey);\n if (!ok) {\n throw new SigningError(\n `Signature verification failed for envelope from ${envelope.senderId}.`,\n \"envelope-malformed\"\n );\n }\n return envelope.payload;\n}\n\n/**\n * Serialise a {@link SignedEnvelope} to a single binary blob suitable for\n * transmission over a network adapter. Wire format:\n *\n * [4 bytes BE: senderId byte length]\n * [N bytes: senderId UTF-8]\n * [64 bytes: signature]\n * [remaining: payload]\n *\n * Callers should not depend on the exact bytes — they should round-trip\n * through {@link encodeSignedEnvelope} / {@link decodeSignedEnvelope}.\n */\nexport function encodeSignedEnvelope(envelope: SignedEnvelope): Uint8Array {\n const senderBytes = new TextEncoder().encode(envelope.senderId);\n const total = 4 + senderBytes.length + SIGNATURE_BYTES + envelope.payload.length;\n const out = new Uint8Array(total);\n const view = new DataView(out.buffer);\n view.setUint32(0, senderBytes.length, false);\n out.set(senderBytes, 4);\n out.set(envelope.signature, 4 + senderBytes.length);\n out.set(envelope.payload, 4 + senderBytes.length + SIGNATURE_BYTES);\n return out;\n}\n\n/**\n * Deserialise a binary envelope produced by {@link encodeSignedEnvelope}.\n * Throws on malformed input.\n */\nexport function decodeSignedEnvelope(bytes: Uint8Array): SignedEnvelope {\n if (bytes.length < 4 + SIGNATURE_BYTES) {\n throw new SigningError(\n `Envelope too short: ${bytes.length} bytes, need at least ${4 + SIGNATURE_BYTES}.`,\n \"envelope-malformed\"\n );\n }\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const senderLen = view.getUint32(0, false);\n if (bytes.length < 4 + senderLen + SIGNATURE_BYTES) {\n throw new SigningError(\n `Envelope truncated: declared sender length ${senderLen}, total ${bytes.length}.`,\n \"envelope-malformed\"\n );\n }\n const senderId = new TextDecoder().decode(bytes.subarray(4, 4 + senderLen));\n const signature = bytes.slice(4 + senderLen, 4 + senderLen + SIGNATURE_BYTES);\n const payload = bytes.slice(4 + senderLen + SIGNATURE_BYTES);\n return { senderId, payload, signature };\n}\n",
|
|
15
|
-
"/**\n * peer-repo-server — Phase 1 server-side factory for the Polly peer-relay\n * transport. Constructs an Automerge-Repo `Repo` wired to a WebSocket server\n * and a NodeFS storage backend, ready to relay sync messages between\n * connected $peerState clients.\n *\n * The \"always-on peer\" role for $peerState lives here. The server holds a\n * full Automerge replica of every document, participates in the sync protocol\n * as an ordinary peer, and persists state to disk so the next process restart\n * picks up where the previous one left off. Server-side cron, HTTP handlers,\n * and other compute can open document handles on the returned Repo and mutate\n * them; mutations propagate to connected clients through the same sync\n * protocol that handles client-to-client traffic.\n *\n * The plan originally called this an \"Elysia plugin,\" but Automerge's\n * `WebSocketServerAdapter` requires an `isomorphic-ws` `WebSocketServer`\n * instance — not Elysia's native WebSocket — so the cleanest first cut is a\n * standalone factory that runs its own `ws` server. Elysia integration for\n * authenticated upgrades is a Phase 1.1 follow-up that wraps this factory.\n *\n * @example\n * ```ts\n * import { createPeerRepoServer } from \"@fairfox/polly\";\n *\n * const server = await createPeerRepoServer({\n * port: 3030,\n * storagePath: \"./data/polly-peer\",\n * });\n *\n * // Open a document handle on the server's Repo for cron or compute work.\n * const handle = server.repo.create({ counter: 0 });\n *\n * // On shutdown:\n * await server.close();\n * ```\n */\n\nimport { Repo } from \"@automerge/automerge-repo/slim\";\nimport { WebSocketServerAdapter } from \"@automerge/automerge-repo-network-websocket\";\nimport { NodeFSStorageAdapter } from \"@automerge/automerge-repo-storage-nodefs\";\nimport * as
|
|
15
|
+
"/**\n * peer-repo-server — Phase 1 server-side factory for the Polly peer-relay\n * transport. Constructs an Automerge-Repo `Repo` wired to a WebSocket server\n * and a NodeFS storage backend, ready to relay sync messages between\n * connected $peerState clients.\n *\n * The \"always-on peer\" role for $peerState lives here. The server holds a\n * full Automerge replica of every document, participates in the sync protocol\n * as an ordinary peer, and persists state to disk so the next process restart\n * picks up where the previous one left off. Server-side cron, HTTP handlers,\n * and other compute can open document handles on the returned Repo and mutate\n * them; mutations propagate to connected clients through the same sync\n * protocol that handles client-to-client traffic.\n *\n * The plan originally called this an \"Elysia plugin,\" but Automerge's\n * `WebSocketServerAdapter` requires an `isomorphic-ws` `WebSocketServer`\n * instance — not Elysia's native WebSocket — so the cleanest first cut is a\n * standalone factory that runs its own `ws` server. Elysia integration for\n * authenticated upgrades is a Phase 1.1 follow-up that wraps this factory.\n *\n * @example\n * ```ts\n * import { createPeerRepoServer } from \"@fairfox/polly\";\n *\n * const server = await createPeerRepoServer({\n * port: 3030,\n * storagePath: \"./data/polly-peer\",\n * });\n *\n * // Open a document handle on the server's Repo for cron or compute work.\n * const handle = server.repo.create({ counter: 0 });\n *\n * // On shutdown:\n * await server.close();\n * ```\n */\n\n// Heavy peer-relay dependencies (@automerge/automerge-repo, ws) are dynamic\n// imports loaded only when createPeerRepoServer is actually called. Static\n// imports at this file's top level were hoisted into @fairfox/polly/elysia's\n// module-init chain, breaking Elysia apps that don't use peer state and\n// don't install the automerge peer deps. Types come from the static package\n// references — TypeScript only reads them for shape, so no runtime cost is\n// incurred.\nimport type { Repo as RepoType } from \"@automerge/automerge-repo/slim\";\nimport type { WebSocketServerAdapter as WebSocketServerAdapterType } from \"@automerge/automerge-repo-network-websocket\";\nimport type { NodeFSStorageAdapter as NodeFSStorageAdapterType } from \"@automerge/automerge-repo-storage-nodefs\";\nimport type * as wsType from \"ws\";\n\n// `@types/ws` uses CJS `export = WebSocket` with WebSocketServer hanging off\n// the namespace. Under the project's bundler module resolution, the namespace\n// import gives us access to both the constructor and the type.\ntype WebSocketServer = wsType.WebSocketServer;\n\nexport interface CreatePeerRepoServerOptions {\n /** Port to listen on. The factory creates its own `WebSocketServer` and\n * binds to this port. */\n port: number;\n /** Filesystem directory for the NodeFS storage adapter. The directory is\n * created on demand. Defaults to `./automerge-repo-data` (Automerge's own\n * default). */\n storagePath?: string;\n /** Hostname interface to bind to. Defaults to all interfaces. */\n host?: string;\n /** Override the `WebSocketServer` instance entirely. When provided, `port`\n * and `host` are ignored and the caller is responsible for the lifecycle.\n * Useful for tests that want to bind to a random port. */\n webSocketServer?: WebSocketServer;\n}\n\nexport interface PeerRepoServer {\n /** A configured Repo participating as the always-on peer. Server-side\n * cron and HTTP handlers can open document handles on this directly. */\n repo: RepoType;\n /** The underlying WebSocket server. Exposed for advanced use such as\n * health checks or graceful shutdown coordination. */\n webSocketServer: WebSocketServer;\n /** The Automerge network adapter wrapping the WebSocket server. */\n adapter: WebSocketServerAdapterType;\n /** The NodeFS storage adapter writing to {@link CreatePeerRepoServerOptions.storagePath}. */\n storage: NodeFSStorageAdapterType;\n /** Tear down the server: disconnect peers, flush storage, close the\n * underlying WebSocket server. Returns a promise that resolves once the\n * tear-down is complete. */\n close: () => Promise<void>;\n}\n\n/**\n * Construct a Polly peer-relay server. Returns a Repo that participates as\n * the always-on peer, the underlying WebSocket server and storage adapter\n * for advanced use, and a close function for orderly shutdown.\n *\n * Applications typically call this once at startup, hold the returned\n * `repo` reference for cron and compute work, and wire the close function\n * into their process shutdown signal handlers.\n */\nexport async function createPeerRepoServer(\n options: CreatePeerRepoServerOptions\n): Promise<PeerRepoServer> {\n // Dynamic imports keep automerge-repo and ws out of the static module\n // graph. Apps that never call this function — which is most of them —\n // never pay the dependency cost and don't need the peer packages\n // installed at all.\n const [{ Repo }, { WebSocketServerAdapter }, { NodeFSStorageAdapter }, ws] = await Promise.all([\n import(\"@automerge/automerge-repo/slim\"),\n import(\"@automerge/automerge-repo-network-websocket\"),\n import(\"@automerge/automerge-repo-storage-nodefs\"),\n import(\"ws\"),\n ]);\n\n // Construct the WebSocket server first and wait until it is actually\n // listening before wiring up the Repo. Using the constructor callback\n // avoids the race where the 'listening' event fires before our listener\n // is attached (the callback form is reliable across Node and Bun).\n const wss = await (options.webSocketServer\n ? Promise.resolve(options.webSocketServer)\n : new Promise<WebSocketServer>((resolve, reject) => {\n const created: WebSocketServer = new ws.WebSocketServer(\n {\n port: options.port,\n ...(options.host !== undefined && { host: options.host }),\n },\n () => resolve(created)\n );\n created.once(\"error\", reject);\n }));\n\n // The cast bridges a @types/ws identity quirk: Automerge's adapter type\n // expects WebSocketServer with options.WebSocket typed via isomorphic-ws's\n // CJS-style namespace, and our direct `ws` import resolves through a\n // different path with the same runtime shape but a structurally distinct\n // TypeScript type. The runtime is identical, the cast names that fact.\n const adapter = new WebSocketServerAdapter(\n wss as unknown as ConstructorParameters<typeof WebSocketServerAdapter>[0]\n );\n const storage = new NodeFSStorageAdapter(options.storagePath);\n\n const repo = new Repo({\n network: [adapter],\n storage,\n });\n\n // Force the storage subsystem to finish initialising before returning. The\n // Repo constructor is synchronous, but its NetworkSubsystem holds back the\n // peer-metadata JOIN until storageSubsystem.id() resolves. If a client\n // connects before that resolution lands, the handshake stalls indefinitely.\n // Awaiting storageId() drains the relevant microtask chain and guarantees\n // the server is ready to accept peers when this factory returns.\n await repo.storageId();\n\n return {\n repo,\n webSocketServer: wss,\n adapter,\n storage,\n close: async () => {\n // Forcibly terminate any still-open client sockets before closing the\n // server, otherwise wss.close() can hang waiting for orderly drain when\n // a peer disappeared without a clean disconnect. We then fire the\n // server close without awaiting its callback — the underlying socket\n // is released immediately by terminate(), and waiting for the close\n // callback can hang under Bun even after every client is gone.\n for (const client of wss.clients) {\n try {\n client.terminate();\n } catch {\n // best effort\n }\n }\n try {\n await repo.shutdown();\n } catch {\n // best effort — automerge-repo's xstate DocHandle machine can\n // throw \"Cycle detected\" during teardown when sync messages are\n // still in flight.\n }\n try {\n wss.close();\n } catch {\n // best effort\n }\n },\n };\n}\n",
|
|
16
16
|
"/**\n * peer-state — Phase 1 wrappers exposing $peerState, $peerText, $peerCounter,\n * and $peerList. These are the application-facing constructors for the middle\n * resilience tier in RFC-041: every device is a full Automerge replica, the\n * server included, and server-side code can read and mutate document contents\n * because the server participates in the data plane as an ordinary peer.\n *\n * Each primitive wraps the corresponding Phase 0 base ($crdtState, $crdtText,\n * $crdtCounter, $crdtList) with three additions:\n *\n * 1. The `primitive` label is hard-coded to \"peerState\" so the\n * primitive-registry collision detection knows which family the key\n * belongs to.\n *\n * 2. A handle factory that resolves the application's logical key to an\n * Automerge DocumentId via a per-Repo key map. The first time a key is\n * registered, the factory creates a new document on the configured Repo\n * and records the mapping. On subsequent constructions of the same key,\n * the factory looks up the existing DocumentId and finds the handle.\n *\n * 3. The `sign` option field validates that the configured Repo was\n * created with signing enabled (via createPeerStateClient with\n * `sign: true`). Signing adds Byzantine defence at the transport\n * level without preventing the server from reading document\n * contents. Encryption is not offered on $peerState because it\n * would prevent the server from participating as an Automerge\n * peer; applications that want encrypted state should use $meshState.\n *\n * The Repo itself is supplied by the application via {@link configurePeerState}\n * or per-call via the `repo` option. There is no transport in this Phase 1\n * cut — applications use a local-only Repo and document operations stay\n * inside the calling process. Phase 1's WebSocket relay adapter will plug in\n * via the same configuration path; Phase 2's mesh adapter does the same for\n * $meshState.\n */\n\nimport type { DocHandle, DocumentId, Repo } from \"@automerge/automerge-repo/slim\";\nimport type { Access } from \"./access\";\nimport {\n $crdtCounter,\n $crdtList,\n $crdtText,\n type CounterDoc,\n type ListDoc,\n type SpecialisedPrimitive,\n type TextDoc,\n} from \"./crdt-specialised\";\nimport { $crdtState, type CrdtPrimitive } from \"./crdt-state\";\nimport type { Migrations, VersionedDoc } from \"./schema-version\";\n\n/** Common option shape across all four $peer* primitives. */\nexport interface PeerStateOptions<T> {\n /** Override the default Repo for this primitive. Useful for tests and for\n * applications that maintain multiple Repos (rare). */\n repo?: Repo;\n /** Request per-op Ed25519 signing for this primitive. Signing is a\n * transport-level concern: pass `sign: true` to `createPeerStateClient`\n * to enable it for all primitives on that Repo. Passing `sign: true`\n * here validates that the configured Repo was created with signing\n * enabled and throws if it was not. */\n sign?: boolean;\n /** Schema version target for the application. Migrations run on load. */\n schemaVersion?: number;\n /** Migration table keyed by target version. Required if schemaVersion is set. */\n migrations?: Migrations;\n /** Declarative read/write access. Compiled into a server share policy\n * once the relay transport is wired in. */\n access?: Access;\n /** Initial value used when this primitive's key has not been registered\n * before. Phase 0 callers passed this positionally; Phase 1 application\n * code does the same. */\n initialValue?: T;\n}\n\n/** Internal: per-Repo key → DocumentId map. Cleared by configurePeerState. */\nconst keyMapsByRepo = new WeakMap<Repo, Map<string, DocumentId>>();\n/** Internal: set of Repos configured with signing enabled. */\nconst signingEnabledRepos = new WeakSet<Repo>();\nlet defaultRepo: Repo | undefined;\n\n/**\n * Set the default Repo that the $peer* primitives use when no `repo` option\n * is supplied. Calling this with a new Repo clears the per-Repo key map so\n * that tests start each scenario with a fresh document space.\n *\n * Production code typically calls this once at application startup with a\n * Repo configured for the relay transport. Tests call it before each scenario\n * with an in-memory Repo.\n */\nexport function configurePeerState(repo: Repo, options?: { signEnabled?: boolean }): void {\n defaultRepo = repo;\n keyMapsByRepo.set(repo, new Map());\n if (options?.signEnabled) {\n signingEnabledRepos.add(repo);\n }\n}\n\n/**\n * Reset the peer-state subsystem to its initial unconfigured state. Intended\n * for tests; production code should not call this.\n */\nexport function resetPeerState(): void {\n defaultRepo = undefined;\n}\n\nfunction resolveRepo(option: Repo | undefined): Repo {\n const repo = option ?? defaultRepo;\n if (!repo) {\n throw new Error(\n \"Polly $peerState: no Repo configured. Call configurePeerState(repo) at startup or pass { repo } in the primitive options.\"\n );\n }\n return repo;\n}\n\nfunction getKeyMap(repo: Repo): Map<string, DocumentId> {\n let map = keyMapsByRepo.get(repo);\n if (!map) {\n map = new Map();\n keyMapsByRepo.set(repo, map);\n }\n return map;\n}\n\nfunction validateSignOption(options: PeerStateOptions<unknown>, repo: Repo): void {\n if (!options.sign) return;\n if (!signingEnabledRepos.has(repo)) {\n throw new Error(\n \"Polly $peerState: { sign: true } was passed to the primitive but the configured Repo does not have signing enabled. \" +\n \"Pass { sign: true, keyring: ... } to createPeerStateClient to enable signing at the transport level, \" +\n \"then call configurePeerState(client.repo, { signEnabled: true }).\"\n );\n }\n}\n\n/**\n * Build a getHandle factory that resolves a logical key to a DocHandle on\n * the supplied Repo. The first call creates a new document seeded with the\n * given initial value and records the (key → DocumentId) mapping; subsequent\n * calls look up the existing DocumentId and find the handle.\n */\nfunction buildHandleFactory<D>(\n repo: Repo,\n key: string,\n initialDoc: D\n): () => Promise<DocHandle<D>> {\n return async () => {\n const map = getKeyMap(repo);\n const existingId = map.get(key);\n if (existingId !== undefined) {\n return repo.find<D>(existingId);\n }\n const handle = repo.create<D>(initialDoc);\n map.set(key, handle.documentId);\n return handle;\n };\n}\n\n// ─── $peerState ─────────────────────────────────────────────────────────────\n\n/**\n * Create a peer-replicated state primitive backed by Automerge. Every device\n * holds a full replica; the server, when one is configured via the relay\n * transport, holds one too and participates in the sync protocol as an\n * ordinary peer. Server-side code can read and mutate document contents.\n *\n * @example\n * ```ts\n * const settings = $peerState<Settings>(\"settings\", { theme: \"dark\" });\n * await settings.loaded;\n * settings.value = { theme: \"light\" };\n * ```\n */\nexport function $peerState<T extends VersionedDoc>(\n key: string,\n initialValue: T,\n options: PeerStateOptions<T> = {}\n): CrdtPrimitive<T> {\n const repo = resolveRepo(options.repo);\n validateSignOption(options, repo);\n return $crdtState<T>({\n key,\n primitive: \"peerState\",\n initialValue,\n getHandle: buildHandleFactory<T>(repo, key, initialValue),\n schemaVersion: options.schemaVersion,\n migrations: options.migrations,\n access: options.access,\n });\n}\n\n// ─── $peerText ──────────────────────────────────────────────────────────────\n\nexport interface PeerTextOptions extends Omit<PeerStateOptions<unknown>, \"initialValue\"> {}\n\n/**\n * Create a peer-replicated text primitive. Concurrent character-level edits\n * from peers merge cleanly via Automerge's updateText splicing.\n */\nexport function $peerText(\n key: string,\n initialValue: string,\n options: PeerTextOptions = {}\n): SpecialisedPrimitive<string> {\n const repo = resolveRepo(options.repo);\n validateSignOption(options, repo);\n return $crdtText(key, initialValue, {\n primitive: \"peerState\",\n getHandle: buildHandleFactory<TextDoc>(repo, key, { text: initialValue }),\n schemaVersion: options.schemaVersion,\n migrations: options.migrations,\n access: options.access,\n });\n}\n\n// ─── $peerCounter ───────────────────────────────────────────────────────────\n\nexport interface PeerCounterOptions extends Omit<PeerStateOptions<unknown>, \"initialValue\"> {}\n\n/**\n * Create a peer-replicated counter primitive. Concurrent increments from\n * peers commute, so two clients each adding 1 to a counter at 5 produce a\n * counter at 7 after merging.\n */\nexport function $peerCounter(\n key: string,\n initialValue: number,\n options: PeerCounterOptions = {}\n): SpecialisedPrimitive<number> {\n const repo = resolveRepo(options.repo);\n validateSignOption(options, repo);\n return $crdtCounter(key, initialValue, {\n primitive: \"peerState\",\n getHandle: buildHandleFactory<CounterDoc>(repo, key, {}),\n schemaVersion: options.schemaVersion,\n migrations: options.migrations,\n access: options.access,\n });\n}\n\n// ─── $peerList ──────────────────────────────────────────────────────────────\n\nexport interface PeerListOptions extends Omit<PeerStateOptions<unknown>, \"initialValue\"> {}\n\n/**\n * Create a peer-replicated list primitive. The Phase 0 base uses naive\n * whole-array replacement; Phase 1.1 will refine the write path with\n * structural diff-to-splice for concurrent insert/remove preservation.\n */\nexport function $peerList<T>(\n key: string,\n initialValue: T[],\n options: PeerListOptions = {}\n): SpecialisedPrimitive<T[]> {\n const repo = resolveRepo(options.repo);\n validateSignOption(options, repo);\n return $crdtList<T>(key, initialValue, {\n primitive: \"peerState\",\n getHandle: buildHandleFactory<ListDoc<T>>(repo, key, { items: initialValue }),\n schemaVersion: options.schemaVersion,\n migrations: options.migrations,\n access: options.access,\n });\n}\n"
|
|
17
17
|
],
|
|
18
|
-
"mappings": "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",
|
|
19
|
-
"debugId": "
|
|
18
|
+
"mappings": "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",
|
|
19
|
+
"debugId": "E758423470D8955364756E2164756E21",
|
|
20
20
|
"names": []
|
|
21
21
|
}
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
* await server.close();
|
|
35
35
|
* ```
|
|
36
36
|
*/
|
|
37
|
-
import { Repo } from "@automerge/automerge-repo/slim";
|
|
38
|
-
import { WebSocketServerAdapter } from "@automerge/automerge-repo-network-websocket";
|
|
39
|
-
import { NodeFSStorageAdapter } from "@automerge/automerge-repo-storage-nodefs";
|
|
40
|
-
import * as
|
|
41
|
-
type WebSocketServer =
|
|
37
|
+
import type { Repo as RepoType } from "@automerge/automerge-repo/slim";
|
|
38
|
+
import type { WebSocketServerAdapter as WebSocketServerAdapterType } from "@automerge/automerge-repo-network-websocket";
|
|
39
|
+
import type { NodeFSStorageAdapter as NodeFSStorageAdapterType } from "@automerge/automerge-repo-storage-nodefs";
|
|
40
|
+
import type * as wsType from "ws";
|
|
41
|
+
type WebSocketServer = wsType.WebSocketServer;
|
|
42
42
|
export interface CreatePeerRepoServerOptions {
|
|
43
43
|
/** Port to listen on. The factory creates its own `WebSocketServer` and
|
|
44
44
|
* binds to this port. */
|
|
@@ -57,14 +57,14 @@ export interface CreatePeerRepoServerOptions {
|
|
|
57
57
|
export interface PeerRepoServer {
|
|
58
58
|
/** A configured Repo participating as the always-on peer. Server-side
|
|
59
59
|
* cron and HTTP handlers can open document handles on this directly. */
|
|
60
|
-
repo:
|
|
60
|
+
repo: RepoType;
|
|
61
61
|
/** The underlying WebSocket server. Exposed for advanced use such as
|
|
62
62
|
* health checks or graceful shutdown coordination. */
|
|
63
63
|
webSocketServer: WebSocketServer;
|
|
64
64
|
/** The Automerge network adapter wrapping the WebSocket server. */
|
|
65
|
-
adapter:
|
|
65
|
+
adapter: WebSocketServerAdapterType;
|
|
66
66
|
/** The NodeFS storage adapter writing to {@link CreatePeerRepoServerOptions.storagePath}. */
|
|
67
|
-
storage:
|
|
67
|
+
storage: NodeFSStorageAdapterType;
|
|
68
68
|
/** Tear down the server: disconnect peers, flush storage, close the
|
|
69
69
|
* underlying WebSocket server. Returns a promise that resolves once the
|
|
70
70
|
* tear-down is complete. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fairfox/polly",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Multi-execution-context framework with reactive state and cross-context messaging for Chrome extensions, PWAs, and worker-based applications",
|