@fairfox/polly 0.38.2 → 0.40.0

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.
Files changed (42) hide show
  1. package/dist/cli/polly.js.map +1 -1
  2. package/dist/src/background/index.js +1 -2
  3. package/dist/src/background/index.js.map +6 -6
  4. package/dist/src/background/message-router.js +1 -2
  5. package/dist/src/background/message-router.js.map +6 -6
  6. package/dist/src/client/index.js +46 -27
  7. package/dist/src/client/index.js.map +5 -5
  8. package/dist/src/client/wrapper.d.ts +8 -0
  9. package/dist/src/elysia/index.js +10 -31
  10. package/dist/src/elysia/index.js.map +5 -5
  11. package/dist/src/elysia/route-match.d.ts +9 -0
  12. package/dist/src/elysia/types.d.ts +4 -5
  13. package/dist/src/index.js +1 -2
  14. package/dist/src/index.js.map +7 -7
  15. package/dist/src/mesh-node.js.map +1 -1
  16. package/dist/src/mesh.js.map +7 -7
  17. package/dist/src/peer.js.map +3 -3
  18. package/dist/src/polly-ui/index.js.map +3 -3
  19. package/dist/src/polly-ui/markdown.js +583 -517
  20. package/dist/src/polly-ui/markdown.js.map +6 -6
  21. package/dist/src/shared/adapters/index.js.map +3 -3
  22. package/dist/src/shared/lib/context-helpers.js +1 -2
  23. package/dist/src/shared/lib/context-helpers.js.map +6 -6
  24. package/dist/src/shared/lib/mesh-signaling-client.d.ts +1 -1
  25. package/dist/src/shared/lib/message-bus.js +1 -2
  26. package/dist/src/shared/lib/message-bus.js.map +6 -6
  27. package/dist/src/shared/lib/peer-relay-adapter.d.ts +3 -2
  28. package/dist/src/shared/lib/resource.js.map +3 -3
  29. package/dist/src/shared/lib/state.js.map +3 -3
  30. package/dist/src/shared/state/app-state.js.map +4 -4
  31. package/dist/src/shared/types/messages.d.ts +0 -9
  32. package/dist/src/shared/types/messages.js.map +1 -1
  33. package/dist/tools/test/src/adapters/index.js.map +1 -1
  34. package/dist/tools/test/src/index.js.map +1 -1
  35. package/dist/tools/test/src/visual/index.js +64 -38
  36. package/dist/tools/test/src/visual/index.js.map +4 -4
  37. package/dist/tools/verify/Dockerfile +1 -1
  38. package/dist/tools/verify/specs/Dockerfile +1 -1
  39. package/dist/tools/verify/src/cli.js.map +3 -3
  40. package/dist/tools/visualize/src/cli.js.map +3 -3
  41. package/package.json +33 -28
  42. package/dist/src/utils/function-serialization.d.ts +0 -14
@@ -507,28 +507,45 @@ function createLamportClock(contextId) {
507
507
  };
508
508
  }
509
509
 
510
- // src/utils/function-serialization.ts
511
- import serialize from "serialize-javascript";
512
- var isDev = true;
513
- function serializeFunction(fn) {
514
- if (!isDev) {
515
- return "";
510
+ // src/elysia/route-match.ts
511
+ function matchRoute(pattern, method, path) {
512
+ const spaceIdx = pattern.indexOf(" ");
513
+ const patternMethod = spaceIdx === -1 ? null : pattern.slice(0, spaceIdx);
514
+ const patternPath = spaceIdx === -1 ? pattern : pattern.slice(spaceIdx + 1);
515
+ if (patternMethod && patternMethod !== method) {
516
+ return false;
516
517
  }
517
- return serialize(fn, { space: 0 });
518
- }
519
- function deserializeFunction(serialized) {
520
- if (!isDev) {
521
- throw new Error("[Polly] deserializeFunction should not be called in production. " + "Client effects should be imported from your bundle.");
518
+ const patternSegments = patternPath.split("/").filter(Boolean);
519
+ const pathSegments = path.split("/").filter(Boolean);
520
+ if (patternSegments.length !== pathSegments.length && !patternPath.includes("*")) {
521
+ return false;
522
+ }
523
+ for (let i2 = 0;i2 < patternSegments.length; i2++) {
524
+ const patternSeg = patternSegments[i2];
525
+ const pathSeg = pathSegments[i2];
526
+ if (patternSeg === "*")
527
+ return true;
528
+ if (patternSeg?.startsWith(":"))
529
+ continue;
530
+ if (patternSeg !== pathSeg)
531
+ return false;
522
532
  }
523
- if (!serialized) {
524
- throw new Error("[Polly] Cannot deserialize empty function");
533
+ return true;
534
+ }
535
+ function findMatchingConfig(configs, method, path) {
536
+ if (!configs)
537
+ return;
538
+ for (const [pattern, config] of Object.entries(configs)) {
539
+ if (matchRoute(pattern, method, path)) {
540
+ return config;
541
+ }
525
542
  }
526
- return eval(`(${serialized})`);
543
+ return;
527
544
  }
528
545
 
529
546
  // src/client/wrapper.ts
530
547
  function createPollyClient(url, options = {}) {
531
- const isDev2 = true;
548
+ const isDev = true;
532
549
  const baseClient = treaty(url);
533
550
  const clock = createLamportClock("client");
534
551
  const clientState = {
@@ -537,7 +554,7 @@ function createPollyClient(url, options = {}) {
537
554
  queuedRequests: y([])
538
555
  };
539
556
  let ws = null;
540
- const shouldUseWebSocket = options.websocket === undefined ? isDev2 : options.websocket;
557
+ const shouldUseWebSocket = options.websocket === undefined ? isDev : options.websocket;
541
558
  if (shouldUseWebSocket && typeof WebSocket !== "undefined") {
542
559
  const wsPath = options.websocketPath || "/polly/ws";
543
560
  const wsUrl = url.replace(/^http/, "ws") + wsPath;
@@ -586,7 +603,7 @@ function createPollyClient(url, options = {}) {
586
603
  body: JSON.stringify(req.body)
587
604
  });
588
605
  const result = await response.json();
589
- if (isDev2) {
606
+ if (isDev) {
590
607
  const metadataHeader = response.headers.get("X-Polly-Metadata");
591
608
  if (metadataHeader) {
592
609
  const metadata = JSON.parse(metadataHeader);
@@ -594,15 +611,17 @@ function createPollyClient(url, options = {}) {
594
611
  const mergeStrategy = metadata.offline.merge;
595
612
  if (mergeStrategy === "replace") {} else if (typeof mergeStrategy === "function") {}
596
613
  }
597
- if (metadata.clientEffect) {
598
- const handler = deserializeFunction(metadata.clientEffect.handler);
599
- handler({
600
- result,
601
- body: req.body,
602
- state: { client: options.state || {}, server: {} },
603
- params: {},
604
- clock: metadata.clock
605
- });
614
+ if (metadata.hasClientEffect) {
615
+ const handler = findMatchingConfig(options.clientEffects, req.method, req.path);
616
+ if (handler) {
617
+ handler({
618
+ result,
619
+ body: req.body,
620
+ state: { client: options.state || {}, server: {} },
621
+ params: {},
622
+ clock: metadata.clock
623
+ });
624
+ }
606
625
  }
607
626
  }
608
627
  }
@@ -627,4 +646,4 @@ export {
627
646
  createPollyClient
628
647
  };
629
648
 
630
- //# debugId=24BF66824F21DF9964756E2164756E21
649
+ //# debugId=C526745C58C5156E64756E2164756E21
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/client/wrapper.ts", "../node_modules/@preact/signals-core/dist/signals-core.module.js", "../src/core/clock.ts", "../src/utils/function-serialization.ts"],
3
+ "sources": ["../src/client/wrapper.ts", "../node_modules/@preact/signals-core/dist/signals-core.module.js", "../src/core/clock.ts", "../src/elysia/route-match.ts"],
4
4
  "sourcesContent": [
5
- "// @ts-nocheck - Optional peer dependencies (elysia, @elysiajs/eden)\nimport { treaty } from \"@elysiajs/eden\";\nimport { type Signal, signal } from \"@preact/signals-core\";\nimport { createLamportClock } from \"../core/clock\";\nimport type { PollyResponseMetadata } from \"../elysia/types\";\nimport { deserializeFunction } from \"../utils/function-serialization\";\n\n/**\n * Offline queue entry\n */\ninterface QueuedRequest {\n id: string;\n method: string;\n path: string;\n body: unknown;\n optimisticResult?: unknown;\n timestamp: number;\n}\n\n/**\n * Client-side state management\n */\ninterface ClientState {\n isOnline: Signal<boolean>;\n isSyncing: Signal<boolean>;\n queuedRequests: Signal<QueuedRequest[]>;\n}\n\n/**\n * Polly client options\n */\nexport interface PollyClientOptions {\n /**\n * Client state signals that should be synced\n */\n state?: Record<string, Signal<unknown>>;\n\n /**\n * Callback when online/offline status changes\n */\n onOfflineChange?: (isOnline: boolean) => void;\n\n /**\n * Enable WebSocket for real-time updates (default: true in dev, false in prod)\n */\n websocket?: boolean;\n\n /**\n * WebSocket path (default: '/polly/ws')\n */\n websocketPath?: string;\n}\n\n/**\n * Create a Polly-enhanced Eden client\n *\n * In DEV mode:\n * - Processes server metadata for hot reloading\n * - Executes client effects from server\n * - Handles offline queueing\n * - Connects WebSocket for real-time updates\n *\n * In PROD mode:\n * - Minimal wrapper (client effects are bundled)\n * - Optional WebSocket for real-time features\n * - Offline queueing still works\n *\n * Example:\n * ```typescript\n * import { createPollyClient } from '@fairfox/polly/client';\n * import { $syncedState } from '@fairfox/polly';\n * import type { app } from './server';\n *\n * const clientState = {\n * todos: $syncedState('todos', []),\n * user: $syncedState('user', null),\n * };\n *\n * export const api = createPollyClient<typeof app>('http://localhost:3000', {\n * state: clientState,\n * websocket: true,\n * });\n * ```\n */\nexport function createPollyClient<T extends Record<string, unknown>>(\n url: string,\n options: PollyClientOptions = {}\n) {\n const isDev = process.env.NODE_ENV !== \"production\";\n const baseClient = treaty<T>(url);\n const clock = createLamportClock(\"client\");\n\n // Client state\n const clientState: ClientState = {\n isOnline: signal(typeof navigator === \"undefined\" ? true : navigator.onLine),\n isSyncing: signal(false),\n queuedRequests: signal<QueuedRequest[]>([]),\n };\n\n // WebSocket connection for real-time updates (opt-in in prod)\n let ws: WebSocket | null = null;\n const shouldUseWebSocket = options.websocket === undefined ? isDev : options.websocket;\n\n if (shouldUseWebSocket && typeof WebSocket !== \"undefined\") {\n const wsPath = options.websocketPath || \"/polly/ws\";\n const wsUrl = url.replace(/^http/, \"ws\") + wsPath;\n\n try {\n ws = new WebSocket(wsUrl);\n\n ws.addEventListener(\"open\", () => {\n console.log(\"[Polly] WebSocket connected\");\n });\n\n ws.addEventListener(\"message\", (event) => {\n const message = JSON.parse(event.data);\n\n if (message.type === \"state-sync\") {\n // Initial state sync\n Object.assign(options.state || {}, message.state);\n } else if (message.type === \"effect\") {\n // Remote effect triggered by another client (broadcast)\n console.log(\"[Polly] Received broadcast effect:\", message);\n // In production, handle this via your bundled effects\n // In dev, the effect handler comes from metadata\n }\n });\n\n ws.addEventListener(\"error\", (error) => {\n // biome-ignore lint/suspicious/noConsole: Error logging is intentional\n console.error(\"[Polly] WebSocket error:\", error);\n });\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Error logging is intentional\n console.error(\"[Polly] Failed to create WebSocket:\", error);\n }\n }\n\n // Online/offline listeners (browser only)\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"online\", () => {\n clientState.isOnline.value = true;\n options.onOfflineChange?.(true);\n processQueue();\n });\n\n window.addEventListener(\"offline\", () => {\n clientState.isOnline.value = false;\n options.onOfflineChange?.(false);\n });\n }\n\n /**\n * Process queued requests when back online\n */\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Queue processing requires complex branching logic\n async function processQueue() {\n if (clientState.queuedRequests.value.length === 0) return;\n\n clientState.isSyncing.value = true;\n\n const queue = [...clientState.queuedRequests.value];\n clientState.queuedRequests.value = [];\n\n for (const req of queue) {\n try {\n // Replay request\n const response = await fetch(url + req.path, {\n method: req.method,\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(req.body),\n });\n\n const result = await response.json();\n\n // In dev mode, process metadata\n if (isDev) {\n const metadataHeader = response.headers.get(\"X-Polly-Metadata\");\n if (metadataHeader) {\n const metadata: PollyResponseMetadata = JSON.parse(metadataHeader);\n\n // Handle merge if optimistic update was used\n if (req.optimisticResult && metadata.offline?.merge) {\n const mergeStrategy = metadata.offline.merge;\n\n if (mergeStrategy === \"replace\") {\n // Replace optimistic with server result (default)\n // The client effect will handle this\n } else if (typeof mergeStrategy === \"function\") {\n // TODO: Update local state with merged result\n // const merged = mergeStrategy(req.optimisticResult, result);\n // Apply merged state to local signals\n }\n }\n\n // Execute client effect\n if (metadata.clientEffect) {\n const handler = deserializeFunction(metadata.clientEffect.handler);\n handler({\n result,\n body: req.body,\n state: { client: options.state || {}, server: {} },\n params: {},\n clock: metadata.clock,\n });\n }\n }\n }\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Error logging is intentional\n console.error(\"[Polly] Failed to replay request:\", req, error);\n // Re-queue on failure\n clientState.queuedRequests.value.push(req);\n }\n }\n\n clientState.isSyncing.value = false;\n }\n\n // Return the base client with additional Polly features\n return {\n ...baseClient,\n $polly: {\n state: clientState,\n clock,\n ws,\n /**\n * Manually process queued requests\n */\n sync: processQueue,\n },\n };\n}\n",
5
+ "// @ts-nocheck - Optional peer dependencies (elysia, @elysiajs/eden)\nimport { treaty } from \"@elysiajs/eden\";\nimport { type Signal, signal } from \"@preact/signals-core\";\nimport { createLamportClock } from \"../core/clock\";\nimport { findMatchingConfig } from \"../elysia/route-match\";\nimport type { ClientEffectConfig, PollyResponseMetadata, RoutePattern } from \"../elysia/types\";\n\n/**\n * Offline queue entry\n */\ninterface QueuedRequest {\n id: string;\n method: string;\n path: string;\n body: unknown;\n optimisticResult?: unknown;\n timestamp: number;\n}\n\n/**\n * Client-side state management\n */\ninterface ClientState {\n isOnline: Signal<boolean>;\n isSyncing: Signal<boolean>;\n queuedRequests: Signal<QueuedRequest[]>;\n}\n\n/**\n * Polly client options\n */\nexport interface PollyClientOptions {\n /**\n * Client state signals that should be synced\n */\n state?: Record<string, Signal<unknown>>;\n\n /**\n * Client-side effect handlers, keyed by the same route pattern used in the\n * server config (e.g. `'POST /todos'`). The wrapper looks up handlers here\n * after a successful request — handlers are imported, never shipped from\n * the server.\n */\n clientEffects?: Record<RoutePattern, ClientEffectConfig[\"client\"]>;\n\n /**\n * Callback when online/offline status changes\n */\n onOfflineChange?: (isOnline: boolean) => void;\n\n /**\n * Enable WebSocket for real-time updates (default: true in dev, false in prod)\n */\n websocket?: boolean;\n\n /**\n * WebSocket path (default: '/polly/ws')\n */\n websocketPath?: string;\n}\n\n/**\n * Create a Polly-enhanced Eden client\n *\n * In DEV mode:\n * - Processes server metadata for hot reloading\n * - Executes client effects from server\n * - Handles offline queueing\n * - Connects WebSocket for real-time updates\n *\n * In PROD mode:\n * - Minimal wrapper (client effects are bundled)\n * - Optional WebSocket for real-time features\n * - Offline queueing still works\n *\n * Example:\n * ```typescript\n * import { createPollyClient } from '@fairfox/polly/client';\n * import { $syncedState } from '@fairfox/polly';\n * import type { app } from './server';\n *\n * const clientState = {\n * todos: $syncedState('todos', []),\n * user: $syncedState('user', null),\n * };\n *\n * export const api = createPollyClient<typeof app>('http://localhost:3000', {\n * state: clientState,\n * websocket: true,\n * });\n * ```\n */\nexport function createPollyClient<T extends Record<string, unknown>>(\n url: string,\n options: PollyClientOptions = {}\n) {\n const isDev = process.env.NODE_ENV !== \"production\";\n const baseClient = treaty<T>(url);\n const clock = createLamportClock(\"client\");\n\n // Client state\n const clientState: ClientState = {\n isOnline: signal(typeof navigator === \"undefined\" ? true : navigator.onLine),\n isSyncing: signal(false),\n queuedRequests: signal<QueuedRequest[]>([]),\n };\n\n // WebSocket connection for real-time updates (opt-in in prod)\n let ws: WebSocket | null = null;\n const shouldUseWebSocket = options.websocket === undefined ? isDev : options.websocket;\n\n if (shouldUseWebSocket && typeof WebSocket !== \"undefined\") {\n const wsPath = options.websocketPath || \"/polly/ws\";\n const wsUrl = url.replace(/^http/, \"ws\") + wsPath;\n\n try {\n ws = new WebSocket(wsUrl);\n\n ws.addEventListener(\"open\", () => {\n console.log(\"[Polly] WebSocket connected\");\n });\n\n ws.addEventListener(\"message\", (event) => {\n const message = JSON.parse(event.data);\n\n if (message.type === \"state-sync\") {\n // Initial state sync\n // nosemgrep: javascript.lang.security.insecure-object-assign.insecure-object-assign — `message.state` is already typed wire data delivered by the polly server; the trust boundary is the WebSocket auth, not Object.assign.\n Object.assign(options.state || {}, message.state);\n } else if (message.type === \"effect\") {\n // Remote effect triggered by another client (broadcast)\n console.log(\"[Polly] Received broadcast effect:\", message);\n // In production, handle this via your bundled effects\n // In dev, the effect handler comes from metadata\n }\n });\n\n ws.addEventListener(\"error\", (error) => {\n // biome-ignore lint/suspicious/noConsole: Error logging is intentional\n console.error(\"[Polly] WebSocket error:\", error);\n });\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Error logging is intentional\n console.error(\"[Polly] Failed to create WebSocket:\", error);\n }\n }\n\n // Online/offline listeners (browser only)\n if (typeof window !== \"undefined\") {\n window.addEventListener(\"online\", () => {\n clientState.isOnline.value = true;\n options.onOfflineChange?.(true);\n processQueue();\n });\n\n window.addEventListener(\"offline\", () => {\n clientState.isOnline.value = false;\n options.onOfflineChange?.(false);\n });\n }\n\n /**\n * Process queued requests when back online\n */\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Queue processing requires complex branching logic\n async function processQueue() {\n if (clientState.queuedRequests.value.length === 0) return;\n\n clientState.isSyncing.value = true;\n\n const queue = [...clientState.queuedRequests.value];\n clientState.queuedRequests.value = [];\n\n for (const req of queue) {\n try {\n // Replay request\n const response = await fetch(url + req.path, {\n method: req.method,\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(req.body),\n });\n\n const result = await response.json();\n\n // In dev mode, process metadata\n if (isDev) {\n const metadataHeader = response.headers.get(\"X-Polly-Metadata\");\n if (metadataHeader) {\n const metadata: PollyResponseMetadata = JSON.parse(metadataHeader);\n\n // Handle merge if optimistic update was used\n if (req.optimisticResult && metadata.offline?.merge) {\n const mergeStrategy = metadata.offline.merge;\n\n if (mergeStrategy === \"replace\") {\n // Replace optimistic with server result (default)\n // The client effect will handle this\n } else if (typeof mergeStrategy === \"function\") {\n // TODO: Update local state with merged result\n // const merged = mergeStrategy(req.optimisticResult, result);\n // Apply merged state to local signals\n }\n }\n\n // Execute client effect — looked up locally by route, never deserialised from the wire\n if (metadata.hasClientEffect) {\n const handler = findMatchingConfig(options.clientEffects, req.method, req.path);\n if (handler) {\n handler({\n result,\n body: req.body,\n state: { client: options.state || {}, server: {} },\n params: {},\n clock: metadata.clock,\n });\n }\n }\n }\n }\n } catch (error) {\n // biome-ignore lint/suspicious/noConsole: Error logging is intentional\n console.error(\"[Polly] Failed to replay request:\", req, error);\n // Re-queue on failure\n clientState.queuedRequests.value.push(req);\n }\n }\n\n clientState.isSyncing.value = false;\n }\n\n // Return the base client with additional Polly features\n return {\n ...baseClient,\n $polly: {\n state: clientState,\n clock,\n ws,\n /**\n * Manually process queued requests\n */\n sync: processQueue,\n },\n };\n}\n",
6
6
  "var i=Symbol.for(\"preact-signals\");function t(){if(!(s>1)){var i,t=!1;!function(){var i=d;d=void 0;while(void 0!==i){if(i.S.v===i.v)i.S.i=i.i;i=i.o}}();while(void 0!==h){var n=h;h=void 0;v++;while(void 0!==n){var r=n.u;n.u=void 0;n.f&=-3;if(!(8&n.f)&&w(n))try{n.c()}catch(n){if(!t){i=n;t=!0}}n=r}}v=0;s--;if(t)throw i}else s--}function n(i){if(s>0)return i();e=++u;s++;try{return i()}finally{t()}}var r=void 0;function o(i){var t=r;r=void 0;try{return i()}finally{r=t}}var f,h=void 0,s=0,v=0,u=0,e=0,d=void 0,c=0;function a(i){if(void 0!==r){var t=i.n;if(void 0===t||t.t!==r){t={i:0,S:i,p:r.s,n:void 0,t:r,e:void 0,x:void 0,r:t};if(void 0!==r.s)r.s.n=t;r.s=t;i.n=t;if(32&r.f)i.S(t);return t}else if(-1===t.i){t.i=0;if(void 0!==t.n){t.n.p=t.p;if(void 0!==t.p)t.p.n=t.n;t.p=r.s;t.n=void 0;r.s.n=t;r.s=t}return t}}}function l(i,t){this.v=i;this.i=0;this.n=void 0;this.t=void 0;this.l=0;this.W=null==t?void 0:t.watched;this.Z=null==t?void 0:t.unwatched;this.name=null==t?void 0:t.name}l.prototype.brand=i;l.prototype.h=function(){return!0};l.prototype.S=function(i){var t=this,n=this.t;if(n!==i&&void 0===i.e){i.x=n;this.t=i;if(void 0!==n)n.e=i;else o(function(){var i;null==(i=t.W)||i.call(t)})}};l.prototype.U=function(i){var t=this;if(void 0!==this.t){var n=i.e,r=i.x;if(void 0!==n){n.x=r;i.e=void 0}if(void 0!==r){r.e=n;i.x=void 0}if(i===this.t){this.t=r;if(void 0===r)o(function(){var i;null==(i=t.Z)||i.call(t)})}}};l.prototype.subscribe=function(i){var t=this;return C(function(){var n=t.value,o=r;r=void 0;try{i(n)}finally{r=o}},{name:\"sub\"})};l.prototype.valueOf=function(){return this.value};l.prototype.toString=function(){return this.value+\"\"};l.prototype.toJSON=function(){return this.value};l.prototype.peek=function(){var i=r;r=void 0;try{return this.value}finally{r=i}};Object.defineProperty(l.prototype,\"value\",{get:function(){var i=a(this);if(void 0!==i)i.i=this.i;return this.v},set:function(i){if(i!==this.v){if(v>100)throw new Error(\"Cycle detected\");!function(i){if(0!==s&&0===v)if(i.l!==e){i.l=e;d={S:i,v:i.v,i:i.i,o:d}}}(this);this.v=i;this.i++;c++;s++;try{for(var n=this.t;void 0!==n;n=n.x)n.t.N()}finally{t()}}}});function y(i,t){return new l(i,t)}function w(i){for(var t=i.s;void 0!==t;t=t.n)if(t.S.i!==t.i||!t.S.h()||t.S.i!==t.i)return!0;return!1}function _(i){for(var t=i.s;void 0!==t;t=t.n){var n=t.S.n;if(void 0!==n)t.r=n;t.S.n=t;t.i=-1;if(void 0===t.n){i.s=t;break}}}function b(i){var t=i.s,n=void 0;while(void 0!==t){var r=t.p;if(-1===t.i){t.S.U(t);if(void 0!==r)r.n=t.n;if(void 0!==t.n)t.n.p=r}else n=t;t.S.n=t.r;if(void 0!==t.r)t.r=void 0;t=r}i.s=n}function p(i,t){l.call(this,void 0);this.x=i;this.s=void 0;this.g=c-1;this.f=4;this.W=null==t?void 0:t.watched;this.Z=null==t?void 0:t.unwatched;this.name=null==t?void 0:t.name}p.prototype=new l;p.prototype.h=function(){this.f&=-3;if(1&this.f)return!1;if(32==(36&this.f))return!0;this.f&=-5;if(this.g===c)return!0;this.g=c;this.f|=1;if(this.i>0&&!w(this)){this.f&=-2;return!0}var i=r;try{_(this);r=this;var t=this.x();if(16&this.f||this.v!==t||0===this.i){this.v=t;this.f&=-17;this.i++}}catch(i){this.v=i;this.f|=16;this.i++}r=i;b(this);this.f&=-2;return!0};p.prototype.S=function(i){if(void 0===this.t){this.f|=36;for(var t=this.s;void 0!==t;t=t.n)t.S.S(t)}l.prototype.S.call(this,i)};p.prototype.U=function(i){if(void 0!==this.t){l.prototype.U.call(this,i);if(void 0===this.t){this.f&=-33;for(var t=this.s;void 0!==t;t=t.n)t.S.U(t)}}};p.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var i=this.t;void 0!==i;i=i.x)i.t.N()}};Object.defineProperty(p.prototype,\"value\",{get:function(){if(1&this.f)throw new Error(\"Cycle detected\");var i=a(this);this.h();if(void 0!==i)i.i=this.i;if(16&this.f)throw this.v;return this.v}});function g(i,t){return new p(i,t)}function S(i){var n=i.m;i.m=void 0;if(\"function\"==typeof n){s++;var o=r;r=void 0;try{n()}catch(t){i.f&=-2;i.f|=8;m(i);throw t}finally{r=o;t()}}}function m(i){for(var t=i.s;void 0!==t;t=t.n)t.S.U(t);i.x=void 0;i.s=void 0;S(i)}function x(i){if(r!==this)throw new Error(\"Out-of-order effect\");b(this);r=i;this.f&=-2;if(8&this.f)m(this);t()}function E(i,t){this.x=i;this.m=void 0;this.s=void 0;this.u=void 0;this.f=32;this.name=null==t?void 0:t.name;if(f)f.push(this)}E.prototype.c=function(){var i=this.S();try{if(8&this.f)return;if(void 0===this.x)return;var t=this.x();if(\"function\"==typeof t)this.m=t}finally{i()}};E.prototype.S=function(){if(1&this.f)throw new Error(\"Cycle detected\");this.f|=1;this.f&=-9;S(this);_(this);s++;var i=r;r=this;return x.bind(this,i)};E.prototype.N=function(){if(!(2&this.f)){this.f|=2;this.u=h;h=this}};E.prototype.d=function(){this.f|=8;if(!(1&this.f))m(this)};E.prototype.dispose=function(){this.d()};function C(i,t){var n=new E(i,t);try{n.c()}catch(i){n.d();throw i}var r=n.d.bind(n);r[Symbol.dispose]=r;return r}function O(i){return function(){var t=arguments,r=this;return n(function(){return o(function(){return i.apply(r,[].slice.call(t))})})}}function j(){var i=f;f=[];return function(){var t=f;if(f&&i)i=i.concat(f);f=i;return t}}function k(i){return function(){var t,n,r=j();try{n=i.apply(void 0,[].slice.call(arguments))}catch(i){f=void 0;throw i}finally{t=r()}for(var o in n)if(\"function\"==typeof n[o])n[o]=O(n[o]);n[Symbol.dispose]=O(function(){if(t)for(var i=0;i<t.length;i++)t[i].dispose();t=void 0});return n}}export{p as Computed,E as Effect,l as Signal,O as action,n as batch,g as computed,k as createModel,C as effect,y as signal,o as untracked};//# sourceMappingURL=signals-core.module.js.map\n",
7
7
  "/**\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",
8
- "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"
8
+ "/**\n * Route pattern matcher\n * Supports:\n * - Exact match: 'POST /todos'\n * - Param match: 'GET /todos/:id'\n * - Wildcard: '/todos/*'\n */\nexport function matchRoute(pattern: string, method: string, path: string): boolean {\n const spaceIdx = pattern.indexOf(\" \");\n const patternMethod = spaceIdx === -1 ? null : pattern.slice(0, spaceIdx);\n const patternPath = spaceIdx === -1 ? pattern : pattern.slice(spaceIdx + 1);\n\n if (patternMethod && patternMethod !== method) {\n return false;\n }\n\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;\n if (patternSeg !== pathSeg) return false;\n }\n\n return true;\n}\n\nexport function 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"
9
9
  ],
10
- "mappings": "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",
11
- "debugId": "24BF66824F21DF9964756E2164756E21",
10
+ "mappings": "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",
11
+ "debugId": "C526745C58C5156E64756E2164756E21",
12
12
  "names": []
13
13
  }
@@ -1,4 +1,5 @@
1
1
  import { type Signal } from "@preact/signals-core";
2
+ import type { ClientEffectConfig, RoutePattern } from "../elysia/types";
2
3
  /**
3
4
  * Polly client options
4
5
  */
@@ -7,6 +8,13 @@ export interface PollyClientOptions {
7
8
  * Client state signals that should be synced
8
9
  */
9
10
  state?: Record<string, Signal<unknown>>;
11
+ /**
12
+ * Client-side effect handlers, keyed by the same route pattern used in the
13
+ * server config (e.g. `'POST /todos'`). The wrapper looks up handlers here
14
+ * after a successful request — handlers are imported, never shipped from
15
+ * the server.
16
+ */
17
+ clientEffects?: Record<RoutePattern, ClientEffectConfig["client"]>;
10
18
  /**
11
19
  * Callback when online/offline status changes
12
20
  */
@@ -163,30 +163,11 @@ function createLamportClock(contextId) {
163
163
  };
164
164
  }
165
165
 
166
- // src/utils/function-serialization.ts
167
- import serialize from "serialize-javascript";
168
- var isDev = true;
169
- function serializeFunction(fn) {
170
- if (!isDev) {
171
- return "";
172
- }
173
- return serialize(fn, { space: 0 });
174
- }
175
- function deserializeFunction(serialized) {
176
- if (!isDev) {
177
- throw new Error("[Polly] deserializeFunction should not be called in production. " + "Client effects should be imported from your bundle.");
178
- }
179
- if (!serialized) {
180
- throw new Error("[Polly] Cannot deserialize empty function");
181
- }
182
- return eval(`(${serialized})`);
183
- }
184
-
185
- // src/elysia/plugin.ts
166
+ // src/elysia/route-match.ts
186
167
  function matchRoute(pattern, method, path) {
187
- const hasMethod = pattern.includes(" ");
188
- const patternMethod = hasMethod ? pattern.split(" ")[0] : null;
189
- const patternPath = hasMethod ? pattern.split(" ")[1] : pattern;
168
+ const spaceIdx = pattern.indexOf(" ");
169
+ const patternMethod = spaceIdx === -1 ? null : pattern.slice(0, spaceIdx);
170
+ const patternPath = spaceIdx === -1 ? pattern : pattern.slice(spaceIdx + 1);
190
171
  if (patternMethod && patternMethod !== method) {
191
172
  return false;
192
173
  }
@@ -200,7 +181,7 @@ function matchRoute(pattern, method, path) {
200
181
  const pathSeg = pathSegments[i];
201
182
  if (patternSeg === "*")
202
183
  return true;
203
- if (patternSeg.startsWith(":"))
184
+ if (patternSeg?.startsWith(":"))
204
185
  continue;
205
186
  if (patternSeg !== pathSeg)
206
187
  return false;
@@ -218,6 +199,7 @@ function findMatchingConfig(configs, method, path) {
218
199
  return;
219
200
  }
220
201
 
202
+ // src/elysia/plugin.ts
221
203
  class BroadcastManager {
222
204
  connections = new Map;
223
205
  register(clientId, ws) {
@@ -238,7 +220,7 @@ class BroadcastManager {
238
220
  }
239
221
  }
240
222
  function polly(config = {}) {
241
- const isDev2 = true;
223
+ const isDev = true;
242
224
  const clock = createLamportClock("server");
243
225
  const broadcaster = new BroadcastManager;
244
226
  const clientStateByConnection = new Map;
@@ -308,15 +290,12 @@ function polly(config = {}) {
308
290
  pollyBroadcast.broadcast(broadcastMessage);
309
291
  }
310
292
  }
311
- if (!isDev2) {
293
+ if (!isDev) {
312
294
  return response;
313
295
  }
314
296
  const offlineConfig = findMatchingConfig(config.offline, method, path);
315
297
  const metadata = {
316
- clientEffect: effectConfig ? {
317
- handler: serializeFunction(effectConfig.client),
318
- broadcast: effectConfig.broadcast || false
319
- } : undefined,
298
+ hasClientEffect: !!effectConfig,
320
299
  offline: offlineConfig,
321
300
  clock: pollyClock.now()
322
301
  };
@@ -457,4 +436,4 @@ export {
457
436
  peerRepo
458
437
  };
459
438
 
460
- //# debugId=2084E79965BF116064756E2164756E21
439
+ //# debugId=EDAD4E57925183E464756E2164756E21
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "version": 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"],
3
+ "sources": ["../src/elysia/peer-repo-plugin.ts", "../src/shared/lib/peer-repo-server.ts", "../src/elysia/plugin.ts", "../src/core/clock.ts", "../src/elysia/route-match.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
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
- "// @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",
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 { findMatchingConfig } from \"./route-match\";\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 * 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 hasClientEffect: !!effectConfig,\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
- "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",
9
+ "/**\n * Route pattern matcher\n * Supports:\n * - Exact match: 'POST /todos'\n * - Param match: 'GET /todos/:id'\n * - Wildcard: '/todos/*'\n */\nexport function matchRoute(pattern: string, method: string, path: string): boolean {\n const spaceIdx = pattern.indexOf(\" \");\n const patternMethod = spaceIdx === -1 ? null : pattern.slice(0, spaceIdx);\n const patternPath = spaceIdx === -1 ? pattern : pattern.slice(spaceIdx + 1);\n\n if (patternMethod && patternMethod !== method) {\n return false;\n }\n\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;\n if (patternSeg !== pathSeg) return false;\n }\n\n return true;\n}\n\nexport function 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",
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 client-to-server\n * requests (join, signal), the error envelope, and the server-to-client\n * discovery frames (peers-present, peer-joined, peer-left) that let\n * peers learn about each other without polling. */\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 | {\n /** Sent to a newcomer immediately after it joins, listing every\n * peer that was already joined at that moment. Empty for a lone\n * newcomer. */\n type: \"peers-present\";\n peerIds: string[];\n }\n | {\n /** Broadcast to every incumbent when a new peer joins. */\n type: \"peer-joined\";\n peerId: string;\n }\n | {\n /** Broadcast to every remaining incumbent when a joined peer\n * closes its socket. Never emitted for a connection that never\n * sent a join frame. */\n type: \"peer-left\";\n peerId: string;\n };\n\n/** A frame whose `type` is outside the built-in signalling vocabulary.\n * Consumers who pass an {@link SignalingServerOptions.onCustomFrame}\n * handler receive these on the server side; everything else — including\n * routing them to a specific peer, storing a session, or rejecting the\n * frame — is the consumer's call. Polly does not touch the body. */\nexport interface CustomSignalingFrame {\n type: string;\n [key: string]: unknown;\n}\n\n/** Minimal surface the custom-frame handler receives in place of the\n * Elysia-specific `ws` object so the plugin stays portable. Exposes the\n * `data` bag (used to stash the authenticated peerId under the existing\n * join handshake) and a `send` method. */\nexport interface CustomFrameSocket {\n data: Record<string, unknown>;\n send: (msg: unknown) => void;\n}\n\nexport interface SignalingServerOptions {\n /** WebSocket route path. Defaults to \"/polly/signaling\". */\n path?: string;\n /** Optional hook for frames whose `type` is outside the built-in\n * vocabulary. The plugin invokes it in place of returning a\n * `malformed` error, so consumers can layer their own application\n * protocol (pairing return tokens, presence pings, etc.) on the\n * existing socket. The `peerId` argument is the sender's\n * authenticated peer id from their prior `join` frame, or\n * `undefined` if they haven't joined yet. */\n onCustomFrame?: (\n socket: CustomFrameSocket,\n frame: CustomSignalingFrame,\n peerId: string | undefined\n ) => void;\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 const onCustomFrame = options.onCustomFrame;\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 const newcomer = ws as unknown as { send: (m: unknown) => void };\n // Collect the peers that were already joined so we can (a) tell the\n // newcomer who is present and (b) tell each of them about the\n // newcomer. A rejoin with the same peerId replaces the prior entry\n // but is otherwise treated as a fresh arrival.\n const incumbents: Array<{ peerId: string; socket: { send: (m: unknown) => void } }> = [];\n for (const [existingPeerId, existingSocket] of peerSockets) {\n if (existingPeerId === peerId) continue;\n incumbents.push({ peerId: existingPeerId, socket: existingSocket });\n }\n peerSockets.set(peerId, newcomer);\n const wsWithData = ws as unknown as { data: Record<string, unknown> };\n wsWithData.data.peerId = peerId;\n\n newcomer.send({\n type: \"peers-present\",\n peerIds: incumbents.map((i) => i.peerId),\n } as unknown as SignalingMessage);\n\n for (const incumbent of incumbents) {\n try {\n incumbent.socket.send({ type: \"peer-joined\", peerId } as unknown as SignalingMessage);\n } catch {\n // If a send fails we leave the stale socket to its own close\n // handler to evict. Dropping here would open a window where\n // the next signal to this peer still thinks it's alive.\n }\n }\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 // Unknown types route to the consumer's custom-frame hook when\n // one is configured. Without a hook they still fall through to\n // the `malformed` error — same behaviour as before this branch\n // existed.\n if (onCustomFrame !== undefined) {\n const wsWithData = ws as unknown as CustomFrameSocket;\n const senderId = wsWithData.data[\"peerId\"];\n const peerId = typeof senderId === \"string\" ? senderId : undefined;\n onCustomFrame(wsWithData, msg as unknown as CustomSignalingFrame, peerId);\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 // Connection that never sent a join — nothing to broadcast and\n // nothing to evict. A bystander coming and going leaves no trace.\n return;\n }\n // Only evict if the map still points at *this* socket. A stale\n // close after the same peerId rejoined on a new socket should not\n // take the fresh entry with it. The comparison uses the `data` bag\n // Elysia attaches to each connection because it is preserved across\n // message and close callbacks, unlike the `ws` wrapper object which\n // Elysia may or may not reuse.\n const mapped = peerSockets.get(peerId);\n const wsData = (ws as unknown as { data: Record<string, unknown> }).data;\n const mappedData = (mapped as unknown as { data?: Record<string, unknown> } | undefined)\n ?.data;\n if (mapped === undefined || mappedData !== wsData) {\n return;\n }\n peerSockets.delete(peerId);\n for (const [_incumbentId, incumbentSocket] of peerSockets) {\n try {\n incumbentSocket.send({ type: \"peer-left\", peerId } as unknown as SignalingMessage);\n } catch {\n // Incumbent socket is gone; its own close handler will tidy.\n }\n }\n },\n });\n}\n"
11
11
  ],
12
- "mappings": "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",
13
- "debugId": "2084E79965BF116064756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "EDAD4E57925183E464756E2164756E21",
14
14
  "names": []
15
15
  }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Route pattern matcher
3
+ * Supports:
4
+ * - Exact match: 'POST /todos'
5
+ * - Param match: 'GET /todos/:id'
6
+ * - Wildcard: '/todos/*'
7
+ */
8
+ export declare function matchRoute(pattern: string, method: string, path: string): boolean;
9
+ export declare function findMatchingConfig<T>(configs: Record<string, T> | undefined, method: string, path: string): T | undefined;
@@ -117,12 +117,11 @@ export interface PollyConfig {
117
117
  */
118
118
  export interface PollyResponseMetadata {
119
119
  /**
120
- * Client effect to execute
120
+ * Whether this route has a client effect registered on the server.
121
+ * The client looks the actual handler up in its own `clientEffects` registry
122
+ * keyed by route pattern — handlers are never shipped over the wire.
121
123
  */
122
- clientEffect?: {
123
- handler: string;
124
- broadcast: boolean;
125
- };
124
+ hasClientEffect?: boolean;
126
125
  /**
127
126
  * Offline configuration for this route
128
127
  */
package/dist/src/index.js CHANGED
@@ -1497,7 +1497,6 @@ class MessageBus {
1497
1497
  DOM_UPDATE: "content",
1498
1498
  DOM_INSERT: "content",
1499
1499
  DOM_REMOVE: "content",
1500
- PAGE_EVAL: "page",
1501
1500
  PAGE_GET_VAR: "page",
1502
1501
  PAGE_CALL_FN: "page",
1503
1502
  PAGE_SET_VAR: "page",
@@ -2182,4 +2181,4 @@ export {
2182
2181
  $persistedState
2183
2182
  };
2184
2183
 
2185
- //# debugId=276DC22510F5638664756E2164756E21
2184
+ //# debugId=527D318A2E77CA6964756E2164756E21