@firtoz/socka 2.0.0 → 3.0.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 (67) hide show
  1. package/README.md +195 -42
  2. package/dist/SockaWebSocketSession-B1w7RAid.d.ts +209 -0
  3. package/dist/bun/index.d.ts +30 -5
  4. package/dist/bun/index.js +28 -5
  5. package/dist/bun/index.js.map +1 -1
  6. package/dist/{chunk-MZCQHJXY.js → chunk-IFIGKR3W.js} +45 -8
  7. package/dist/chunk-IFIGKR3W.js.map +1 -0
  8. package/dist/{chunk-45D4T232.js → chunk-LVVCHLNW.js} +74 -9
  9. package/dist/chunk-LVVCHLNW.js.map +1 -0
  10. package/dist/{chunk-AM7PB26G.js → chunk-P3JEEOJL.js} +192 -10
  11. package/dist/chunk-P3JEEOJL.js.map +1 -0
  12. package/dist/chunk-QGURL3DJ.js +8 -0
  13. package/dist/chunk-QGURL3DJ.js.map +1 -0
  14. package/dist/client/index.d.ts +59 -3
  15. package/dist/client/index.js +2 -2
  16. package/dist/core/index.d.ts +2 -21
  17. package/dist/core/index.js +1 -1
  18. package/dist/core/index.js.map +1 -1
  19. package/dist/do/index.d.ts +20 -2
  20. package/dist/do/index.js +36 -2
  21. package/dist/do/index.js.map +1 -1
  22. package/dist/hono/cloudflare-workers.d.ts +4 -4
  23. package/dist/hono/cloudflare-workers.js +4 -3
  24. package/dist/hono/cloudflare-workers.js.map +1 -1
  25. package/dist/hono/index.d.ts +22 -6
  26. package/dist/hono/index.js +5 -3
  27. package/dist/hono/index.js.map +1 -1
  28. package/dist/react/index.d.ts +43 -4
  29. package/dist/react/index.js +103 -9
  30. package/dist/react/index.js.map +1 -1
  31. package/dist/server/index.d.ts +18 -5
  32. package/dist/server/index.js +24 -4
  33. package/dist/server/index.js.map +1 -1
  34. package/dist/{socka-report-error-DzFI2Tr7.d.ts → socka-report-error-CXwpAUgl.d.ts} +80 -8
  35. package/dist/test/index.d.ts +11 -0
  36. package/dist/test/index.js +84 -0
  37. package/dist/test/index.js.map +1 -0
  38. package/docs/README.md +16 -7
  39. package/docs/auth.md +27 -0
  40. package/docs/backpressure.md +16 -0
  41. package/docs/client.md +48 -3
  42. package/docs/comparison.md +2 -2
  43. package/docs/durable-objects.md +3 -3
  44. package/docs/getting-started.md +143 -84
  45. package/docs/history.md +26 -0
  46. package/docs/internals.md +56 -0
  47. package/docs/lifecycle.md +3 -3
  48. package/docs/multi-room.md +10 -8
  49. package/docs/peers.md +11 -7
  50. package/docs/presence.md +43 -0
  51. package/docs/{events.md → pushes.md} +1 -1
  52. package/docs/recipes.md +77 -0
  53. package/docs/reconnection.md +44 -0
  54. package/docs/reference.md +27 -32
  55. package/docs/server.md +19 -3
  56. package/docs/testing.md +20 -0
  57. package/docs/wire-format.md +29 -0
  58. package/examples/minimal-socka.ts +56 -3
  59. package/package.json +14 -10
  60. package/roadmap.md +2 -2
  61. package/skills/socka/core-rpc/SKILL.md +2 -2
  62. package/skills/socka/do-session/SKILL.md +2 -2
  63. package/skills/socka/standard-schema/SKILL.md +1 -1
  64. package/dist/SockaWebSocketSession-Bru8yFcK.d.ts +0 -107
  65. package/dist/chunk-45D4T232.js.map +0 -1
  66. package/dist/chunk-AM7PB26G.js.map +0 -1
  67. package/dist/chunk-MZCQHJXY.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bun/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ServerWebSocket } from \"bun\";\nimport type { SockaContract, SockaContractConfig } from \"../core/contract\";\nimport { reportSockaError } from \"../core/socka-report-error\";\nimport type { SockaWireFormat } from \"../core/wire-codec\";\nimport { dispatchSockaInboundMessage } from \"../server/dispatchSockaInboundMessage\";\nimport {\n\tSockaWebSocketSession,\n\trunSockaSessionOnAttached,\n\ttype SockaWebSocketSessionConfig,\n} from \"../server/SockaWebSocketSession\";\n\nexport type SockaBunResolveScope<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData = undefined,\n> = (ws: ServerWebSocket<TWsData>) => {\n\tsessionMap: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\tconfig: SockaWebSocketSessionConfig<TContract, TData>;\n};\n\nexport type SockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData = undefined,\n> = {\n\tsessionMap: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t/** Pass into `Bun.serve({ ..., websocket })`. */\n\twebsocket: {\n\t\topen: (ws: ServerWebSocket<TWsData>) => void;\n\t\tmessage: (\n\t\t\tws: ServerWebSocket<TWsData>,\n\t\t\tmessage: unknown,\n\t\t) => void | Promise<void>;\n\t\tclose: (ws: ServerWebSocket<TWsData>) => void | Promise<void>;\n\t};\n\twireFormat: SockaWireFormat;\n};\n\nfunction bunHandlersFromResolveScope<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData,\n>(\n\tresolveScope: SockaBunResolveScope<TContract, TData, TWsData>,\n): SockaBunWebSocketHandlers<TContract, TData, TWsData> {\n\tconst websocket: SockaBunWebSocketHandlers<\n\t\tTContract,\n\t\tTData,\n\t\tTWsData\n\t>[\"websocket\"] = {\n\t\topen(ws: ServerWebSocket<TWsData>) {\n\t\t\tconst { sessionMap, config } = resolveScope(ws);\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = new SockaWebSocketSession(domWs, sessionMap, config);\n\t\t\tsessionMap.set(domWs, session);\n\t\t\trunSockaSessionOnAttached(config, session);\n\t\t},\n\t\tasync message(ws: ServerWebSocket<TWsData>, message: unknown) {\n\t\t\tconst { sessionMap, config } = resolveScope(ws);\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\tif (!session) return;\n\t\t\tconst wireFormat = config.wireFormat ?? \"json\";\n\t\t\ttry {\n\t\t\t\tawait dispatchSockaInboundMessage(\n\t\t\t\t\tsession,\n\t\t\t\t\twireFormat,\n\t\t\t\t\tmessage as MessageEvent[\"data\"],\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverInboundMessage\",\n\t\t\t\t\tadapter: \"bun\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tasync close(ws: ServerWebSocket<TWsData>) {\n\t\t\tconst { sessionMap, config } = resolveScope(ws);\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\ttry {\n\t\t\t\tif (session) {\n\t\t\t\t\tawait session.invokeHandleClose();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverHandleClose\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tsessionMap.delete(domWs);\n\t\t\t}\n\t\t},\n\t};\n\n\treturn {\n\t\tsessionMap: new Map(),\n\t\twebsocket,\n\t\twireFormat: \"json\",\n\t};\n}\n\nfunction bunHandlersFromConfig<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfig<TContract, TData>,\n\tmaybeOptions?: {\n\t\tsessionMap?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t},\n): SockaBunWebSocketHandlers<TContract, TData, undefined> {\n\tconst sessionMap =\n\t\tmaybeOptions?.sessionMap ??\n\t\tnew Map<WebSocket, SockaWebSocketSession<TContract, TData>>();\n\tconst wireFormat = config.wireFormat ?? \"json\";\n\n\tconst websocket: SockaBunWebSocketHandlers<\n\t\tTContract,\n\t\tTData,\n\t\tundefined\n\t>[\"websocket\"] = {\n\t\topen(ws: ServerWebSocket<undefined>) {\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = new SockaWebSocketSession(domWs, sessionMap, config);\n\t\t\tsessionMap.set(domWs, session);\n\t\t\trunSockaSessionOnAttached(config, session);\n\t\t},\n\t\tasync message(ws: ServerWebSocket<undefined>, message: unknown) {\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\tif (!session) return;\n\t\t\ttry {\n\t\t\t\tawait dispatchSockaInboundMessage(\n\t\t\t\t\tsession,\n\t\t\t\t\twireFormat,\n\t\t\t\t\tmessage as MessageEvent[\"data\"],\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverInboundMessage\",\n\t\t\t\t\tadapter: \"bun\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tasync close(ws: ServerWebSocket<undefined>) {\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\ttry {\n\t\t\t\tif (session) {\n\t\t\t\t\tawait session.invokeHandleClose();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverHandleClose\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tsessionMap.delete(domWs);\n\t\t\t}\n\t\t},\n\t};\n\n\treturn { sessionMap, websocket, wireFormat };\n}\n\n/**\n * WebSocket handlers for `Bun.serve` when using `ServerWebSocket` (no\n * `addEventListener`). Inbound frames are dispatched with the same logic as\n * `attachSockaWebSocket`.\n *\n * **Single-room:** pass a {@link SockaWebSocketSessionConfig} and optional shared `sessionMap`.\n *\n * **Multi-room:** pass `{ resolveScope }` where `resolveScope(ws)` returns the\n * `sessionMap` and `config` for that socket’s scope (e.g. from `ws.data.roomId`).\n * The returned `sessionMap` is an empty placeholder; real maps come from `resolveScope`.\n */\nexport function createSockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfig<TContract, TData>,\n\toptions?: {\n\t\tsessionMap?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t},\n): SockaBunWebSocketHandlers<TContract, TData, undefined>;\n\nexport function createSockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData,\n>(options: {\n\tresolveScope: SockaBunResolveScope<TContract, TData, TWsData>;\n}): SockaBunWebSocketHandlers<TContract, TData, TWsData>;\n\nexport function createSockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfigOrOptions:\n\t\t| SockaWebSocketSessionConfig<TContract, TData>\n\t\t| { resolveScope: SockaBunResolveScope<TContract, TData, unknown> },\n\tmaybeOptions?: {\n\t\tsessionMap?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t},\n):\n\t| SockaBunWebSocketHandlers<TContract, TData, undefined>\n\t| SockaBunWebSocketHandlers<TContract, TData, unknown> {\n\tconst isResolveScope =\n\t\ttypeof configOrOptions === \"object\" &&\n\t\tconfigOrOptions !== null &&\n\t\t\"resolveScope\" in configOrOptions &&\n\t\ttypeof (configOrOptions as { resolveScope: unknown }).resolveScope ===\n\t\t\t\"function\";\n\n\tif (isResolveScope) {\n\t\treturn bunHandlersFromResolveScope(\n\t\t\t(\n\t\t\t\tconfigOrOptions as {\n\t\t\t\t\tresolveScope: SockaBunResolveScope<TContract, TData, unknown>;\n\t\t\t\t}\n\t\t\t).resolveScope,\n\t\t);\n\t}\n\treturn bunHandlersFromConfig(\n\t\tconfigOrOptions as SockaWebSocketSessionConfig<TContract, TData>,\n\t\tmaybeOptions,\n\t);\n}\n"]}
1
+ {"version":3,"sources":["../../src/bun/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ServerWebSocket } from \"bun\";\nimport type { SockaContract, SockaContractConfig } from \"../core/contract\";\nimport { reportSockaError } from \"../core/socka-report-error\";\nimport type { SockaWireFormat } from \"../core/wire-codec\";\nimport { dispatchSockaInboundMessage } from \"../server/dispatchSockaInboundMessage\";\nimport {\n\tSockaWebSocketSession,\n\trunSockaSessionOnAttached,\n\ttype SockaStrictWebSocketInit,\n\ttype SockaWebSocketSessionConfigUnion,\n} from \"../server/SockaWebSocketSession\";\n\n/**\n * Reads the upgrade {@link Request} from Bun **`ServerWebSocket.data`** when your\n * **`fetch`** handler stored it there (e.g. **`server.upgrade(req, { data: { roomId, request: req } })`**).\n *\n * Pair with the default strict upgrade on {@link SockaWebSocketSessionConfig} so\n * **`createData`** is typed with {@link SockaStrictWebSocketInit} and **`init.request`**\n * is always defined. If **`request`** is missing from **`data`**, this returns **`undefined`**\n * and the session constructor will throw — that usually means you forgot\n * to pass **`request`** on upgrade (or set **`strictUpgradeRequest: false`**).\n */\nexport function sockaBunInitFromWsData(\n\tws: ServerWebSocket<unknown>,\n): SockaStrictWebSocketInit | undefined {\n\tconst d = ws.data as Record<string, unknown> | undefined;\n\tif (d && \"request\" in d && d.request instanceof Request) {\n\t\treturn { request: d.request };\n\t}\n\treturn undefined;\n}\n\n/** `ServerWebSocket.data` shape after {@link sockaBunUpgrade}. */\nexport type SockaBunUpgradeData<TExtra> = TExtra & { request: Request };\n\n/**\n * Calls {@link Bun.Server.upgrade} with **`request: req`** merged into **`data`**, so\n * {@link sockaBunInitFromWsData} and the default strict upgrade always see the HTTP\n * upgrade request (query params, cookies path).\n */\nexport function sockaBunUpgrade<TExtra extends Record<string, unknown>>(\n\tserver: {\n\t\tupgrade: (\n\t\t\treq: Request,\n\t\t\topts: { data: SockaBunUpgradeData<TExtra> },\n\t\t) => boolean;\n\t},\n\treq: Request,\n\tdata?: TExtra,\n): boolean {\n\tconst extra = (data ?? ({} as TExtra)) as TExtra;\n\treturn server.upgrade(req, { data: { ...extra, request: req } });\n}\n\nexport type SockaBunResolveScope<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData = undefined,\n> = (ws: ServerWebSocket<TWsData>) => {\n\tsessionMap: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\tconfig: SockaWebSocketSessionConfigUnion<TContract, TData>;\n};\n\nexport type SockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData = undefined,\n> = {\n\tsessionMap: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t/** Pass into `Bun.serve({ ..., websocket })`. */\n\twebsocket: {\n\t\topen: (ws: ServerWebSocket<TWsData>) => void;\n\t\tmessage: (\n\t\t\tws: ServerWebSocket<TWsData>,\n\t\t\tmessage: unknown,\n\t\t) => void | Promise<void>;\n\t\tclose: (ws: ServerWebSocket<TWsData>) => void | Promise<void>;\n\t};\n\twireFormat: SockaWireFormat;\n};\n\nfunction bunHandlersFromResolveScope<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData,\n>(\n\tresolveScope: SockaBunResolveScope<TContract, TData, TWsData>,\n): SockaBunWebSocketHandlers<TContract, TData, TWsData> {\n\tconst websocket: SockaBunWebSocketHandlers<\n\t\tTContract,\n\t\tTData,\n\t\tTWsData\n\t>[\"websocket\"] = {\n\t\topen(ws: ServerWebSocket<TWsData>) {\n\t\t\tconst { sessionMap, config } = resolveScope(ws);\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst init = sockaBunInitFromWsData(ws);\n\t\t\tconst session = new SockaWebSocketSession(\n\t\t\t\tdomWs,\n\t\t\t\tsessionMap,\n\t\t\t\tconfig,\n\t\t\t\tinit,\n\t\t\t);\n\t\t\tsessionMap.set(domWs, session);\n\t\t\trunSockaSessionOnAttached(config, session);\n\t\t},\n\t\tasync message(ws: ServerWebSocket<TWsData>, message: unknown) {\n\t\t\tconst { sessionMap, config } = resolveScope(ws);\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\tif (!session) return;\n\t\t\tconst wireFormat = config.wireFormat ?? \"json\";\n\t\t\ttry {\n\t\t\t\tawait dispatchSockaInboundMessage(\n\t\t\t\t\tsession,\n\t\t\t\t\twireFormat,\n\t\t\t\t\tmessage as MessageEvent[\"data\"],\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverInboundMessage\",\n\t\t\t\t\tadapter: \"bun\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tasync close(ws: ServerWebSocket<TWsData>) {\n\t\t\tconst { sessionMap, config } = resolveScope(ws);\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\ttry {\n\t\t\t\tif (session) {\n\t\t\t\t\tawait session.invokeHandleClose();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverHandleClose\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tsessionMap.delete(domWs);\n\t\t\t}\n\t\t},\n\t};\n\n\treturn {\n\t\tsessionMap: new Map(),\n\t\twebsocket,\n\t\twireFormat: \"json\",\n\t};\n}\n\nfunction bunHandlersFromConfig<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfigUnion<TContract, TData>,\n\tmaybeOptions?: {\n\t\tsessionMap?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t},\n): SockaBunWebSocketHandlers<TContract, TData, undefined> {\n\tconst sessionMap =\n\t\tmaybeOptions?.sessionMap ??\n\t\tnew Map<WebSocket, SockaWebSocketSession<TContract, TData>>();\n\tconst wireFormat = config.wireFormat ?? \"json\";\n\n\tconst websocket: SockaBunWebSocketHandlers<\n\t\tTContract,\n\t\tTData,\n\t\tundefined\n\t>[\"websocket\"] = {\n\t\topen(ws: ServerWebSocket<undefined>) {\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst init = sockaBunInitFromWsData(ws);\n\t\t\tconst session = new SockaWebSocketSession(\n\t\t\t\tdomWs,\n\t\t\t\tsessionMap,\n\t\t\t\tconfig,\n\t\t\t\tinit,\n\t\t\t);\n\t\t\tsessionMap.set(domWs, session);\n\t\t\trunSockaSessionOnAttached(config, session);\n\t\t},\n\t\tasync message(ws: ServerWebSocket<undefined>, message: unknown) {\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\tif (!session) return;\n\t\t\ttry {\n\t\t\t\tawait dispatchSockaInboundMessage(\n\t\t\t\t\tsession,\n\t\t\t\t\twireFormat,\n\t\t\t\t\tmessage as MessageEvent[\"data\"],\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverInboundMessage\",\n\t\t\t\t\tadapter: \"bun\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t}\n\t\t},\n\t\tasync close(ws: ServerWebSocket<undefined>) {\n\t\t\tconst domWs = ws as unknown as WebSocket;\n\t\t\tconst session = sessionMap.get(domWs);\n\t\t\ttry {\n\t\t\t\tif (session) {\n\t\t\t\t\tawait session.invokeHandleClose();\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\treportSockaError(config.reportError, {\n\t\t\t\t\tkind: \"serverHandleClose\",\n\t\t\t\t\terror,\n\t\t\t\t});\n\t\t\t} finally {\n\t\t\t\tsessionMap.delete(domWs);\n\t\t\t}\n\t\t},\n\t};\n\n\treturn { sessionMap, websocket, wireFormat };\n}\n\n/**\n * WebSocket handlers for `Bun.serve` when using `ServerWebSocket` (no\n * `addEventListener`). Inbound frames are dispatched with the same logic as\n * `attachSockaWebSocket`.\n *\n * **Single-room:** pass a {@link SockaWebSocketSessionConfig} and optional shared `sessionMap`.\n *\n * **Multi-room:** pass `{ resolveScope }` where `resolveScope(ws)` returns the\n * `sessionMap` and `config` for that socket’s scope (e.g. from `ws.data.roomId`).\n * The returned `sessionMap` is an empty placeholder; real maps come from `resolveScope`.\n */\nexport function createSockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfigUnion<TContract, TData>,\n\toptions?: {\n\t\tsessionMap?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t},\n): SockaBunWebSocketHandlers<TContract, TData, undefined>;\n\nexport function createSockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n\tTWsData,\n>(options: {\n\tresolveScope: SockaBunResolveScope<TContract, TData, TWsData>;\n}): SockaBunWebSocketHandlers<TContract, TData, TWsData>;\n\nexport function createSockaBunWebSocketHandlers<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfigOrOptions:\n\t\t| SockaWebSocketSessionConfigUnion<TContract, TData>\n\t\t| { resolveScope: SockaBunResolveScope<TContract, TData, unknown> },\n\tmaybeOptions?: {\n\t\tsessionMap?: Map<WebSocket, SockaWebSocketSession<TContract, TData>>;\n\t},\n):\n\t| SockaBunWebSocketHandlers<TContract, TData, undefined>\n\t| SockaBunWebSocketHandlers<TContract, TData, unknown> {\n\tconst isResolveScope =\n\t\ttypeof configOrOptions === \"object\" &&\n\t\tconfigOrOptions !== null &&\n\t\t\"resolveScope\" in configOrOptions &&\n\t\ttypeof (configOrOptions as { resolveScope: unknown }).resolveScope ===\n\t\t\t\"function\";\n\n\tif (isResolveScope) {\n\t\treturn bunHandlersFromResolveScope(\n\t\t\t(\n\t\t\t\tconfigOrOptions as {\n\t\t\t\t\tresolveScope: SockaBunResolveScope<TContract, TData, unknown>;\n\t\t\t\t}\n\t\t\t).resolveScope,\n\t\t);\n\t}\n\treturn bunHandlersFromConfig(\n\t\tconfigOrOptions as SockaWebSocketSessionConfigUnion<TContract, TData>,\n\t\tmaybeOptions,\n\t);\n}\n"]}
@@ -17,7 +17,9 @@ var SockaError = class _SockaError extends Error {
17
17
  super(message);
18
18
  this.name = "SockaError";
19
19
  this.requestId = options?.requestId;
20
+ this.rpc = options?.rpc;
20
21
  this.code = options?.code;
22
+ this.data = options?.data;
21
23
  if (options?.cause !== void 0) {
22
24
  Object.defineProperty(this, "cause", {
23
25
  value: options.cause,
@@ -30,7 +32,12 @@ var SockaError = class _SockaError extends Error {
30
32
  }
31
33
  /** Builds a {@link SockaError} from a standard RPC error envelope. */
32
34
  static fromWire(msg) {
33
- return new _SockaError(msg.error, { requestId: msg.id });
35
+ return new _SockaError(msg.error, {
36
+ requestId: msg.id,
37
+ rpc: msg.rpc,
38
+ code: msg.code,
39
+ data: msg.data
40
+ });
34
41
  }
35
42
  };
36
43
 
@@ -69,10 +76,19 @@ function decodeSockaWire(parsed) {
69
76
  };
70
77
  }
71
78
  if (socka === "serverError" && typeof parsed.id === "string" && typeof parsed.error === "string") {
72
- return {
73
- kind: "serverError",
74
- frame: parsed
79
+ const code = "code" in parsed && typeof parsed.code === "string" ? parsed.code : void 0;
80
+ const data = "data" in parsed ? parsed.data : void 0;
81
+ const rpc = "rpc" in parsed && typeof parsed.rpc === "string" ? parsed.rpc : void 0;
82
+ const frame = {
83
+ socka: "serverError",
84
+ v: SOCKA_WIRE_VERSION,
85
+ id: parsed.id,
86
+ error: parsed.error,
87
+ ...rpc !== void 0 ? { rpc } : {},
88
+ ...code !== void 0 ? { code } : {},
89
+ ...data !== void 0 ? { data } : {}
75
90
  };
91
+ return { kind: "serverError", frame };
76
92
  }
77
93
  if (socka === "serverEvent" && typeof parsed.event === "string") {
78
94
  return {
@@ -90,8 +106,16 @@ function encodeClientRequest(id, rpc, body) {
90
106
  function encodeServerResponse(id, rpc, body) {
91
107
  return { socka: "serverResponse", v: SOCKA_WIRE_VERSION, id, rpc, body };
92
108
  }
93
- function encodeServerError(id, error) {
94
- return { socka: "serverError", v: SOCKA_WIRE_VERSION, id, error };
109
+ function encodeServerError(id, error, extra) {
110
+ return {
111
+ socka: "serverError",
112
+ v: SOCKA_WIRE_VERSION,
113
+ id,
114
+ error,
115
+ ...extra?.rpc !== void 0 ? { rpc: extra.rpc } : {},
116
+ ...extra?.code !== void 0 ? { code: extra.code } : {},
117
+ ...extra?.data !== void 0 ? { data: extra.data } : {}
118
+ };
95
119
  }
96
120
  function encodeServerEvent(event, body) {
97
121
  return { socka: "serverEvent", v: SOCKA_WIRE_VERSION, event, body };
@@ -125,6 +149,19 @@ function defaultReportError(event) {
125
149
  case "clientEventValidation":
126
150
  console.error("socka: event validation error", event.error);
127
151
  return;
152
+ case "clientFireAndForgetRpcError":
153
+ console.error("socka: fire-and-forget RPC error", event.error);
154
+ return;
155
+ case "clientOrphanServerError":
156
+ console.error("socka: orphan serverError (no pending RPC)", event.error);
157
+ return;
158
+ case "clientUnexpectedServerResponse":
159
+ console.error(
160
+ "socka: unexpected serverResponse for fire-and-forget RPC",
161
+ event.rpc,
162
+ event.requestId
163
+ );
164
+ return;
128
165
  case "serverOnAttached":
129
166
  console.error("socka: onAttached error:", event.error);
130
167
  return;
@@ -154,5 +191,5 @@ function reportSockaError(reportError, event) {
154
191
  }
155
192
 
156
193
  export { SOCKA_WIRE_VERSION, SockaError, SockaWireError, decodeSockaWire, defaultReportError, encodeClientRequest, encodeServerError, encodeServerEvent, encodeServerResponse, encodeSockaWire, parseStandardSchema, parseWirePayload, reportSockaError };
157
- //# sourceMappingURL=chunk-MZCQHJXY.js.map
158
- //# sourceMappingURL=chunk-MZCQHJXY.js.map
194
+ //# sourceMappingURL=chunk-IFIGKR3W.js.map
195
+ //# sourceMappingURL=chunk-IFIGKR3W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/validate.ts","../src/core/socka-error.ts","../src/core/envelope.ts","../src/core/wire-codec.ts","../src/core/socka-report-error.ts"],"names":[],"mappings":"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","file":"chunk-IFIGKR3W.js","sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * Validates {@link value} with a Standard Schema v1 schema and returns the output,\n * or throws an {@link Error} whose message aggregates issue messages.\n */\nexport async function parseStandardSchema<T>(\n\tschema: StandardSchemaV1<unknown, T>,\n\tvalue: unknown,\n): Promise<T> {\n\tconst result = await schema[\"~standard\"].validate(value);\n\tif (result.issues) {\n\t\tconst messages = result.issues.map((issue) => issue.message).join(\"; \");\n\t\tthrow new Error(messages || \"Validation failed\");\n\t}\n\treturn result.value;\n}\n","/**\n * Thrown on the server and surfaced on the client when the wire uses a shared\n * `{ type: \"error\", id, error }` envelope for correlated RPC failures.\n */\nexport class SockaError extends Error {\n\treadonly requestId?: string;\n\t/** Procedure name when provided on the wire (`serverError.rpc`). */\n\treadonly rpc?: string;\n\treadonly code?: string;\n\treadonly data?: unknown;\n\n\tconstructor(\n\t\tmessage: string,\n\t\toptions?: {\n\t\t\trequestId?: string;\n\t\t\trpc?: string;\n\t\t\tcode?: string;\n\t\t\tdata?: unknown;\n\t\t\tcause?: unknown;\n\t\t},\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"SockaError\";\n\t\tthis.requestId = options?.requestId;\n\t\tthis.rpc = options?.rpc;\n\t\tthis.code = options?.code;\n\t\tthis.data = options?.data;\n\t\tif (options?.cause !== undefined) {\n\t\t\tObject.defineProperty(this, \"cause\", {\n\t\t\t\tvalue: options.cause,\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: false,\n\t\t\t\twritable: true,\n\t\t\t});\n\t\t}\n\t\tObject.setPrototypeOf(this, SockaError.prototype);\n\t}\n\n\t/** Builds a {@link SockaError} from a standard RPC error envelope. */\n\tstatic fromWire(msg: {\n\t\tid: string;\n\t\terror: string;\n\t\trpc?: string;\n\t\tcode?: string;\n\t\tdata?: unknown;\n\t}): SockaError {\n\t\treturn new SockaError(msg.error, {\n\t\t\trequestId: msg.id,\n\t\t\trpc: msg.rpc,\n\t\t\tcode: msg.code,\n\t\t\tdata: msg.data,\n\t\t});\n\t}\n}\n","/**\n * Versioned socka wire framing. After JSON parse or msgpack unpack, every frame\n * must satisfy {@link decodeSockaWire}; procedure bodies are validated with Standard Schema on each side.\n */\n\nexport const SOCKA_WIRE_VERSION = 1 as const;\n\nexport class SockaWireError extends Error {\n\toverride readonly name = \"SockaWireError\";\n}\n\nexport type SockaClientRequestFrame = {\n\treadonly socka: \"clientRequest\";\n\treadonly v: typeof SOCKA_WIRE_VERSION;\n\treadonly id: string;\n\treadonly rpc: string;\n\treadonly body: Record<string, unknown>;\n};\n\nexport type SockaServerResponseFrame = {\n\treadonly socka: \"serverResponse\";\n\treadonly v: typeof SOCKA_WIRE_VERSION;\n\treadonly id: string;\n\treadonly rpc: string;\n\treadonly body: unknown;\n};\n\nexport type SockaServerErrorFrame = {\n\treadonly socka: \"serverError\";\n\treadonly v: typeof SOCKA_WIRE_VERSION;\n\treadonly id: string;\n\treadonly error: string;\n\t/** Procedure name when the error relates to a client RPC (helps clients without a pending entry). */\n\treadonly rpc?: string;\n\t/** Optional machine-readable code (e.g. `FORBIDDEN`). */\n\treadonly code?: string;\n\t/** Optional structured detail for clients; keep small and JSON-serializable. */\n\treadonly data?: unknown;\n};\n\nexport type SockaServerEventFrame = {\n\treadonly socka: \"serverEvent\";\n\treadonly v: typeof SOCKA_WIRE_VERSION;\n\treadonly event: string;\n\treadonly body: unknown;\n};\n\nexport type SockaWireFrame =\n\t| SockaClientRequestFrame\n\t| SockaServerResponseFrame\n\t| SockaServerErrorFrame\n\t| SockaServerEventFrame;\n\nexport type DecodedSockaWire =\n\t| { readonly kind: \"clientRequest\"; readonly frame: SockaClientRequestFrame }\n\t| {\n\t\t\treadonly kind: \"serverResponse\";\n\t\t\treadonly frame: SockaServerResponseFrame;\n\t }\n\t| { readonly kind: \"serverError\"; readonly frame: SockaServerErrorFrame }\n\t| { readonly kind: \"serverEvent\"; readonly frame: SockaServerEventFrame };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Decodes a parsed wire object (from JSON or msgpack). Throws {@link SockaWireError}\n * if the payload is not a valid socka v1 frame.\n */\nexport function decodeSockaWire(parsed: unknown): DecodedSockaWire {\n\tif (!isRecord(parsed)) {\n\t\tthrow new SockaWireError(\"socka: expected a JSON object\");\n\t}\n\tif (parsed.socka === undefined) {\n\t\tthrow new SockaWireError('socka: missing \"socka\" discriminator');\n\t}\n\tif (parsed.v !== SOCKA_WIRE_VERSION) {\n\t\tthrow new SockaWireError(\"socka: unsupported wire version\");\n\t}\n\tconst socka = parsed.socka;\n\tif (\n\t\tsocka === \"clientRequest\" &&\n\t\ttypeof parsed.id === \"string\" &&\n\t\ttypeof parsed.rpc === \"string\" &&\n\t\tisRecord(parsed.body)\n\t) {\n\t\treturn {\n\t\t\tkind: \"clientRequest\",\n\t\t\tframe: parsed as SockaClientRequestFrame,\n\t\t};\n\t}\n\tif (\n\t\tsocka === \"serverResponse\" &&\n\t\ttypeof parsed.id === \"string\" &&\n\t\ttypeof parsed.rpc === \"string\"\n\t) {\n\t\treturn {\n\t\t\tkind: \"serverResponse\",\n\t\t\tframe: parsed as SockaServerResponseFrame,\n\t\t};\n\t}\n\tif (\n\t\tsocka === \"serverError\" &&\n\t\ttypeof parsed.id === \"string\" &&\n\t\ttypeof parsed.error === \"string\"\n\t) {\n\t\tconst code =\n\t\t\t\"code\" in parsed && typeof parsed.code === \"string\"\n\t\t\t\t? parsed.code\n\t\t\t\t: undefined;\n\t\tconst data = \"data\" in parsed ? parsed.data : undefined;\n\t\tconst rpc =\n\t\t\t\"rpc\" in parsed && typeof parsed.rpc === \"string\"\n\t\t\t\t? parsed.rpc\n\t\t\t\t: undefined;\n\t\tconst frame: SockaServerErrorFrame = {\n\t\t\tsocka: \"serverError\",\n\t\t\tv: SOCKA_WIRE_VERSION,\n\t\t\tid: parsed.id,\n\t\t\terror: parsed.error,\n\t\t\t...(rpc !== undefined ? { rpc } : {}),\n\t\t\t...(code !== undefined ? { code } : {}),\n\t\t\t...(data !== undefined ? { data } : {}),\n\t\t};\n\t\treturn { kind: \"serverError\", frame };\n\t}\n\tif (socka === \"serverEvent\" && typeof parsed.event === \"string\") {\n\t\treturn {\n\t\t\tkind: \"serverEvent\",\n\t\t\tframe: parsed as SockaServerEventFrame,\n\t\t};\n\t}\n\tthrow new SockaWireError(\n\t\t`socka: unknown or invalid frame kind ${String(socka)}`,\n\t);\n}\n\n/** Builds a socka v1 client request frame. */\nexport function encodeClientRequest(\n\tid: string,\n\trpc: string,\n\tbody: Record<string, unknown>,\n): SockaClientRequestFrame {\n\treturn { socka: \"clientRequest\", v: SOCKA_WIRE_VERSION, id, rpc, body };\n}\n\n/** Builds a socka v1 server response frame. */\nexport function encodeServerResponse(\n\tid: string,\n\trpc: string,\n\tbody: unknown,\n): SockaServerResponseFrame {\n\treturn { socka: \"serverResponse\", v: SOCKA_WIRE_VERSION, id, rpc, body };\n}\n\n/** Builds a socka v1 server error frame. */\nexport function encodeServerError(\n\tid: string,\n\terror: string,\n\textra?: {\n\t\treadonly code?: string;\n\t\treadonly data?: unknown;\n\t\treadonly rpc?: string;\n\t},\n): SockaServerErrorFrame {\n\treturn {\n\t\tsocka: \"serverError\",\n\t\tv: SOCKA_WIRE_VERSION,\n\t\tid,\n\t\terror,\n\t\t...(extra?.rpc !== undefined ? { rpc: extra.rpc } : {}),\n\t\t...(extra?.code !== undefined ? { code: extra.code } : {}),\n\t\t...(extra?.data !== undefined ? { data: extra.data } : {}),\n\t};\n}\n\n/** Builds a socka v1 server event frame. */\nexport function encodeServerEvent(\n\tevent: string,\n\tbody: unknown,\n): SockaServerEventFrame {\n\treturn { socka: \"serverEvent\", v: SOCKA_WIRE_VERSION, event, body };\n}\n","/**\n * JSON text frames vs msgpack binary frames for the same socka v1 object graph.\n * Matches {@link decodeSockaWire} after parse/unpack.\n */\n\nimport { pack, unpack } from \"msgpackr\";\nimport type { SockaWireFrame } from \"./envelope\";\n\n/** Wire encoding: UTF-8 JSON strings (default) or msgpack `ArrayBuffer` frames. */\nexport type SockaWireFormat = \"json\" | \"msgpack\";\n\n/**\n * Encodes a socka frame for the wire. JSON returns a string; msgpack returns bytes\n * suitable for `WebSocket.send`.\n */\nexport function encodeSockaWire(\n\tframe: SockaWireFrame,\n\tformat: SockaWireFormat,\n\tserializeJson: (value: unknown) => string = JSON.stringify,\n): string | Uint8Array {\n\tif (format === \"json\") {\n\t\treturn serializeJson(frame);\n\t}\n\treturn pack(frame) as Uint8Array;\n}\n\n/**\n * Decodes a wire payload to a plain object before {@link decodeSockaWire}.\n * Msgpack mode accepts `ArrayBuffer` or `Uint8Array` (e.g. from `msgpackr` / `WebSocket`).\n */\nexport function parseWirePayload(\n\tdata: string | ArrayBuffer | Uint8Array,\n\tformat: SockaWireFormat,\n\tdeserializeJson: (raw: string) => unknown = JSON.parse,\n): unknown {\n\tif (format === \"json\") {\n\t\tif (typeof data !== \"string\") {\n\t\t\tthrow new Error(\"socka: expected a JSON text frame\");\n\t\t}\n\t\treturn deserializeJson(data);\n\t}\n\tif (data instanceof Uint8Array) {\n\t\treturn unpack(data);\n\t}\n\tif (data instanceof ArrayBuffer) {\n\t\treturn unpack(new Uint8Array(data));\n\t}\n\tthrow new Error(\"socka: expected an ArrayBuffer or Uint8Array msgpack frame\");\n}\n","import { exhaustiveGuard } from \"@firtoz/maybe-error\";\nimport type { SockaError } from \"./socka-error\";\n\n/**\n * Single discriminated union for optional `reportError` on session config and\n * `SockaSession` options: `kind` narrows context; `error` is what was thrown or rejected.\n */\nexport type SockaReportError =\n\t| { kind: \"clientEventListener\"; eventName: string; error: unknown }\n\t| { kind: \"clientEventValidation\"; eventName: string; error: unknown }\n\t/**\n\t * `serverError` for a fire-and-forget call (no pending client promise). Prefer\n\t * setting `reportError` on the session when using output-less procedures.\n\t */\n\t| { kind: \"clientFireAndForgetRpcError\"; error: SockaError }\n\t/**\n\t * `serverError` with no matching pending entry for a call that expects a response\n\t * (e.g. stale id after reconnect or duplicate frame).\n\t */\n\t| { kind: \"clientOrphanServerError\"; error: SockaError }\n\t/**\n\t * Server sent `serverResponse` for a procedure with no `output` (misbehaving server).\n\t */\n\t| {\n\t\t\tkind: \"clientUnexpectedServerResponse\";\n\t\t\trpc: string;\n\t\t\trequestId: string;\n\t }\n\t| { kind: \"serverOnAttached\"; error: unknown }\n\t| {\n\t\t\tkind: \"serverInboundMessage\";\n\t\t\t/** `hono` uses the same log line as the Hono adapters; others use attach-style. */\n\t\t\tadapter: \"attach\" | \"hono\" | \"bun\";\n\t\t\terror: unknown;\n\t }\n\t| { kind: \"serverHandleClose\"; error: unknown }\n\t| {\n\t\t\tkind: \"serverShutdown\";\n\t\t\tadapter: \"attach\" | \"hono\";\n\t\t\terror: unknown;\n\t };\n\n/** Default `console.error` behavior; same messages as pre–`reportError` socka. */\nexport function defaultReportError(event: SockaReportError): void {\n\tswitch (event.kind) {\n\t\tcase \"clientEventListener\":\n\t\t\tconsole.error(\"socka: event listener error\", event.error);\n\t\t\treturn;\n\t\tcase \"clientEventValidation\":\n\t\t\tconsole.error(\"socka: event validation error\", event.error);\n\t\t\treturn;\n\t\tcase \"clientFireAndForgetRpcError\":\n\t\t\tconsole.error(\"socka: fire-and-forget RPC error\", event.error);\n\t\t\treturn;\n\t\tcase \"clientOrphanServerError\":\n\t\t\tconsole.error(\"socka: orphan serverError (no pending RPC)\", event.error);\n\t\t\treturn;\n\t\tcase \"clientUnexpectedServerResponse\":\n\t\t\tconsole.error(\n\t\t\t\t\"socka: unexpected serverResponse for fire-and-forget RPC\",\n\t\t\t\tevent.rpc,\n\t\t\t\tevent.requestId,\n\t\t\t);\n\t\t\treturn;\n\t\tcase \"serverOnAttached\":\n\t\t\tconsole.error(\"socka: onAttached error:\", event.error);\n\t\t\treturn;\n\t\tcase \"serverInboundMessage\":\n\t\t\tif (event.adapter === \"hono\") {\n\t\t\t\tconsole.error(\"socka: onMessage error:\", event.error);\n\t\t\t} else {\n\t\t\t\tconsole.error(\"socka: message handler error:\", event.error);\n\t\t\t}\n\t\t\treturn;\n\t\tcase \"serverHandleClose\":\n\t\t\tconsole.error(\"socka: handleClose error:\", event.error);\n\t\t\treturn;\n\t\tcase \"serverShutdown\":\n\t\t\tif (event.adapter === \"hono\") {\n\t\t\t\tconsole.error(\"socka: onClose error:\", event.error);\n\t\t\t} else {\n\t\t\t\tconsole.error(\"socka: shutdown error:\", event.error);\n\t\t\t}\n\t\t\treturn;\n\t\tdefault:\n\t\t\texhaustiveGuard(event);\n\t}\n}\n\n/** Invokes the optional `reportError` callback when provided, otherwise `defaultReportError`. */\nexport function reportSockaError(\n\treportError: ((event: SockaReportError) => void) | undefined,\n\tevent: SockaReportError,\n): void {\n\t(reportError ?? defaultReportError)(event);\n}\n"]}
@@ -1,6 +1,9 @@
1
- import { parseWirePayload, decodeSockaWire, SockaWireError, encodeServerError, parseStandardSchema, SockaError, encodeServerResponse, encodeSockaWire, encodeServerEvent, reportSockaError } from './chunk-MZCQHJXY.js';
1
+ import { parseWirePayload, decodeSockaWire, SockaWireError, encodeServerError, parseStandardSchema, SockaError, encodeServerResponse, encodeSockaWire, encodeServerEvent, reportSockaError } from './chunk-IFIGKR3W.js';
2
2
  import { exhaustiveGuard } from '@firtoz/maybe-error';
3
3
 
4
+ function isLooseUpgradeConfig(config) {
5
+ return "strictUpgradeRequest" in config && config.strictUpgradeRequest === false;
6
+ }
4
7
  function broadcastSockaEventToPeers(sessions, self, event, body, excludeSelf = false) {
5
8
  for (const [ws, session] of sessions) {
6
9
  if (excludeSelf && ws === self.websocket) continue;
@@ -13,12 +16,64 @@ var SockaWebSocketSession = class {
13
16
  this.sessions = sessions;
14
17
  this.config = config;
15
18
  this.wireFormat = config.wireFormat ?? "json";
16
- const create = config.createData ?? ((_i) => ({}));
17
- this._data = create(init ?? {});
19
+ if (isLooseUpgradeConfig(config)) {
20
+ const createData = config.createData;
21
+ const create = createData ?? ((_i) => ({}));
22
+ this._data = create(init ?? {});
23
+ } else {
24
+ if (!init?.request) {
25
+ throw new Error(
26
+ "socka: strict upgrade (default) requires a Request on the upgrade init (e.g. Bun upgrade with `data: { \u2026, request: req }`, or Hono default sockaInit), or use SockaWebSocketSessionConfigLoose with strictUpgradeRequest: false"
27
+ );
28
+ }
29
+ const strictInit = { request: init.request };
30
+ if (config.createData) {
31
+ this._data = config.createData(strictInit);
32
+ } else {
33
+ this._data = {};
34
+ }
35
+ }
18
36
  }
19
37
  get data() {
20
38
  return this._data;
21
39
  }
40
+ /**
41
+ * Session data for every connection in the same {@link sessions} map (same room),
42
+ * optionally excluding this socket.
43
+ */
44
+ listPeers(options) {
45
+ const out = [];
46
+ for (const [ws, s] of this.sessions) {
47
+ if (options?.excludeSelf && ws === this.websocket) continue;
48
+ out.push(s.data);
49
+ }
50
+ return out;
51
+ }
52
+ /**
53
+ * Like {@link listPeers} but maps each peer {@link SockaWebSocketSession}
54
+ * (e.g. when you need more than {@link #data}).
55
+ */
56
+ listPeersWith(map, options) {
57
+ const out = [];
58
+ for (const [ws, s] of this.sessions) {
59
+ if (options?.excludeSelf && ws === this.websocket) continue;
60
+ out.push(map(s));
61
+ }
62
+ return out;
63
+ }
64
+ /** Count of sessions in this room (same {@link sessions} map), optionally excluding self. */
65
+ peerCount(options) {
66
+ let n = 0;
67
+ for (const [ws] of this.sessions) {
68
+ if (options?.excludeSelf && ws === this.websocket) continue;
69
+ n += 1;
70
+ }
71
+ return n;
72
+ }
73
+ /** Whether any peer sessions exist (optionally excluding self). */
74
+ hasPeers(options) {
75
+ return this.peerCount(options) > 0;
76
+ }
22
77
  /**
23
78
  * Invokes the user {@link typeof SockaWebSocketSessionConfig.handleClose} callback.
24
79
  * Server adapters should call this when the WebSocket closes, **before** deleting
@@ -101,7 +156,8 @@ var SockaWebSocketSession = class {
101
156
  if (!procedure) {
102
157
  const errorFrame = encodeServerError(
103
158
  frame.id,
104
- `Unknown call: ${rpcName}`
159
+ `Unknown call: ${rpcName}`,
160
+ { rpc: rpcName }
105
161
  );
106
162
  this.sendWireFrame(errorFrame);
107
163
  return;
@@ -112,7 +168,9 @@ var SockaWebSocketSession = class {
112
168
  validatedInput = await parseStandardSchema(procedure.input, frame.body);
113
169
  } catch (err) {
114
170
  const msg = err instanceof Error ? err.message : "Input validation failed";
115
- const errorFrame = encodeServerError(frame.id, msg);
171
+ const errorFrame = encodeServerError(frame.id, msg, {
172
+ rpc: rpcName
173
+ });
116
174
  this.sendWireFrame(errorFrame);
117
175
  return;
118
176
  }
@@ -131,16 +189,23 @@ var SockaWebSocketSession = class {
131
189
  const sockaErr = err instanceof SockaError ? err : new SockaError(
132
190
  err instanceof Error ? err.message : "Handler failed"
133
191
  );
134
- const errorFrame = encodeServerError(frame.id, sockaErr.message);
192
+ const errorFrame = encodeServerError(frame.id, sockaErr.message, {
193
+ rpc: rpcName,
194
+ code: sockaErr.code,
195
+ data: sockaErr.data
196
+ });
135
197
  this.sendWireFrame(errorFrame);
136
198
  return;
137
199
  }
200
+ if (procedure.output === void 0) {
201
+ return;
202
+ }
138
203
  let validatedOutput;
139
204
  try {
140
205
  validatedOutput = await parseStandardSchema(procedure.output, result);
141
206
  } catch (err) {
142
207
  const msg = err instanceof Error ? err.message : "Output validation failed";
143
- const errorFrame = encodeServerError(frame.id, msg);
208
+ const errorFrame = encodeServerError(frame.id, msg, { rpc: rpcName });
144
209
  this.sendWireFrame(errorFrame);
145
210
  return;
146
211
  }
@@ -232,5 +297,5 @@ function runSockaSessionOnAttached(config, session) {
232
297
  }
233
298
 
234
299
  export { SockaWebSocketSession, broadcastSockaEventToPeers, runSockaSessionOnAttached };
235
- //# sourceMappingURL=chunk-45D4T232.js.map
236
- //# sourceMappingURL=chunk-45D4T232.js.map
300
+ //# sourceMappingURL=chunk-LVVCHLNW.js.map
301
+ //# sourceMappingURL=chunk-LVVCHLNW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server/SockaWebSocketSession.ts"],"names":[],"mappings":"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","file":"chunk-LVVCHLNW.js","sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { exhaustiveGuard } from \"@firtoz/maybe-error\";\nimport type {\n\tInferSockaPushPayload,\n\tSockaContract,\n\tSockaContractConfig,\n} from \"../core/contract\";\nimport {\n\tSockaWireError,\n\tdecodeSockaWire,\n\tencodeServerResponse,\n\tencodeServerError,\n\tencodeServerEvent,\n\ttype SockaClientRequestFrame,\n\ttype SockaWireFrame,\n} from \"../core/envelope\";\nimport {\n\tencodeSockaWire,\n\tparseWirePayload,\n\ttype SockaWireFormat,\n} from \"../core/wire-codec\";\nimport { reportSockaError } from \"../core/socka-report-error\";\nimport { parseStandardSchema } from \"../core/validate\";\nimport { SockaError } from \"../core/socka-error\";\nimport type {\n\tSockaStrictWebSocketInit,\n\tSockaWebSocketInit,\n\tSockaWebSocketSessionConfig,\n\tSockaWebSocketSessionConfigLoose,\n\tSockaWebSocketSessionConfigUnion,\n} from \"./SockaWebSocketSessionConfig\";\n\n/** Session data with no fields — `createData` may be omitted (defaults to `{}`). */\ntype EmptySockaSessionData = Record<string, never>;\n\nexport type {\n\tSockaStrictWebSocketInit,\n\tSockaWebSocketInit,\n\tSockaWebSocketSessionConfig,\n\tSockaWebSocketSessionConfigLoose,\n\tSockaWebSocketSessionConfigUnion,\n};\n\nfunction isLooseUpgradeConfig<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfigUnion<TContract, TData>,\n): config is SockaWebSocketSessionConfigLoose<TContract, TData> {\n\treturn (\n\t\t\"strictUpgradeRequest\" in config && config.strictUpgradeRequest === false\n\t);\n}\n\n/** Session that can send a wire-level server event (already validated). */\nexport type SockaEmitCapable = {\n\temitWireEvent(event: string, body: unknown): void;\n};\n\n/**\n * Contract-typed session surface for handlers that push to clients.\n */\nexport interface SockaPushSession<\n\tTContract extends SockaContract<SockaContractConfig>,\n> {\n\temitPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t): Promise<void>;\n\tbroadcastPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t\texcludeSelf?: boolean,\n\t): Promise<void>;\n}\n\n/**\n * Broadcast a socka server event to every session in the map (optionally\n * excluding the caller). Payload must already be contract-validated.\n *\n * Exclusion uses the **WebSocket** identity (`self.websocket`), not the session\n * object reference, so the same `sessions` map can hold `SockaDoSession` while\n * `broadcastPush` runs on `this.socka` (inner {@link SockaWebSocketSession}).\n */\nexport function broadcastSockaEventToPeers(\n\tsessions: Map<WebSocket, SockaEmitCapable>,\n\tself: SockaEmitCapable & { readonly websocket: WebSocket },\n\tevent: string,\n\tbody: unknown,\n\texcludeSelf = false,\n): void {\n\tfor (const [ws, session] of sessions) {\n\t\tif (excludeSelf && ws === self.websocket) continue;\n\t\tsession.emitWireEvent(event, body);\n\t}\n}\n\n/**\n * Runtime-agnostic socka server session: standard {@link WebSocket} wire\n * dispatch without Cloudflare Durable Object APIs.\n */\nexport class SockaWebSocketSession<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData = EmptySockaSessionData,\n> implements SockaPushSession<TContract>\n{\n\tprivate readonly config: SockaWebSocketSessionConfigUnion<TContract, TData>;\n\tprivate readonly wireFormat: SockaWireFormat;\n\tprivate _data!: TData;\n\n\tpublic constructor(\n\t\tpublic readonly websocket: WebSocket,\n\t\tprotected readonly sessions: Map<\n\t\t\tWebSocket,\n\t\t\tSockaWebSocketSession<TContract, TData>\n\t\t>,\n\t\tconfig: SockaWebSocketSessionConfigUnion<TContract, TData>,\n\t\tinit?: SockaWebSocketInit,\n\t) {\n\t\tthis.config = config;\n\t\tthis.wireFormat = config.wireFormat ?? \"json\";\n\t\tif (isLooseUpgradeConfig(config)) {\n\t\t\tconst createData = config.createData as\n\t\t\t\t| ((init: SockaWebSocketInit) => TData)\n\t\t\t\t| undefined;\n\t\t\tconst create = createData ?? ((_i: SockaWebSocketInit) => ({}) as TData);\n\t\t\tthis._data = create(init ?? {});\n\t\t} else {\n\t\t\tif (!init?.request) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"socka: strict upgrade (default) requires a Request on the upgrade init (e.g. Bun upgrade with `data: { …, request: req }`, or Hono default sockaInit), or use SockaWebSocketSessionConfigLoose with strictUpgradeRequest: false\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst strictInit: SockaStrictWebSocketInit = { request: init.request };\n\t\t\tif (config.createData) {\n\t\t\t\tthis._data = config.createData(strictInit);\n\t\t\t} else {\n\t\t\t\tthis._data = {} as TData;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic get data(): TData {\n\t\treturn this._data;\n\t}\n\n\t/**\n\t * Session data for every connection in the same {@link sessions} map (same room),\n\t * optionally excluding this socket.\n\t */\n\tpublic listPeers(options?: { excludeSelf?: boolean }): TData[] {\n\t\tconst out: TData[] = [];\n\t\tfor (const [ws, s] of this.sessions) {\n\t\t\tif (options?.excludeSelf && ws === this.websocket) continue;\n\t\t\tout.push(s.data);\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * Like {@link listPeers} but maps each peer {@link SockaWebSocketSession}\n\t * (e.g. when you need more than {@link #data}).\n\t */\n\tpublic listPeersWith<R>(\n\t\tmap: (session: SockaWebSocketSession<TContract, TData>) => R,\n\t\toptions?: { excludeSelf?: boolean },\n\t): R[] {\n\t\tconst out: R[] = [];\n\t\tfor (const [ws, s] of this.sessions) {\n\t\t\tif (options?.excludeSelf && ws === this.websocket) continue;\n\t\t\tout.push(map(s));\n\t\t}\n\t\treturn out;\n\t}\n\n\t/** Count of sessions in this room (same {@link sessions} map), optionally excluding self. */\n\tpublic peerCount(options?: { excludeSelf?: boolean }): number {\n\t\tlet n = 0;\n\t\tfor (const [ws] of this.sessions) {\n\t\t\tif (options?.excludeSelf && ws === this.websocket) continue;\n\t\t\tn += 1;\n\t\t}\n\t\treturn n;\n\t}\n\n\t/** Whether any peer sessions exist (optionally excluding self). */\n\tpublic hasPeers(options?: { excludeSelf?: boolean }): boolean {\n\t\treturn this.peerCount(options) > 0;\n\t}\n\n\t/**\n\t * Invokes the user {@link typeof SockaWebSocketSessionConfig.handleClose} callback.\n\t * Server adapters should call this when the WebSocket closes, **before** deleting\n\t * this session from the shared `sessions` map.\n\t */\n\tpublic async invokeHandleClose(): Promise<void> {\n\t\tawait this.config.handleClose(this);\n\t}\n\n\tpublic async handleRawMessage(rawMessage: string): Promise<void> {\n\t\tif (this.wireFormat !== \"json\") {\n\t\t\tawait this.reportValidationError(\n\t\t\t\tnew Error(\"socka: unexpected JSON frame in msgpack mode\"),\n\t\t\t\trawMessage,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tconst deserialize = this.config.deserializeJson ?? JSON.parse;\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = deserialize(rawMessage);\n\t\t} catch {\n\t\t\tawait this.reportValidationError(\n\t\t\t\tnew Error(\"socka: invalid JSON\"),\n\t\t\t\trawMessage,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tawait this.dispatchAfterParsed(parsed, rawMessage);\n\t}\n\n\tpublic async handleBinaryMessage(buffer: ArrayBuffer): Promise<void> {\n\t\tif (this.wireFormat !== \"msgpack\") {\n\t\t\tawait this.reportValidationError(\n\t\t\t\tnew Error(\"socka: unexpected binary frame in JSON mode\"),\n\t\t\t\tbuffer,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = parseWirePayload(buffer, \"msgpack\");\n\t\t} catch (err) {\n\t\t\tawait this.reportValidationError(\n\t\t\t\terr instanceof Error ? err : new Error(\"socka: msgpack decode failed\"),\n\t\t\t\tbuffer,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tawait this.dispatchAfterParsed(parsed, buffer);\n\t}\n\n\tprivate async dispatchAfterParsed(\n\t\tparsed: unknown,\n\t\toriginalWire: unknown,\n\t): Promise<void> {\n\t\tlet decoded: ReturnType<typeof decodeSockaWire>;\n\t\ttry {\n\t\t\tdecoded = decodeSockaWire(parsed);\n\t\t} catch (err) {\n\t\t\tif (err instanceof SockaWireError) {\n\t\t\t\tawait this.reportValidationError(err, originalWire);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\tswitch (decoded.kind) {\n\t\t\tcase \"clientRequest\":\n\t\t\t\tawait this.dispatchClientRequest(decoded.frame, originalWire);\n\t\t\t\treturn;\n\t\t\tcase \"serverResponse\":\n\t\t\tcase \"serverError\":\n\t\t\tcase \"serverEvent\":\n\t\t\t\tawait this.reportValidationError(\n\t\t\t\t\tnew Error(\"socka: unexpected server-originated frame from client\"),\n\t\t\t\t\tparsed,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\tdefault:\n\t\t\t\texhaustiveGuard(decoded);\n\t\t}\n\t}\n\n\tprivate async dispatchClientRequest(\n\t\tframe: SockaClientRequestFrame,\n\t\t_originalWire: unknown,\n\t): Promise<void> {\n\t\tconst rpcName = frame.rpc;\n\t\tconst procedure = this.config.contract.calls[rpcName];\n\n\t\tif (!procedure) {\n\t\t\tconst errorFrame = encodeServerError(\n\t\t\t\tframe.id,\n\t\t\t\t`Unknown call: ${rpcName}`,\n\t\t\t\t{ rpc: rpcName },\n\t\t\t);\n\t\t\tthis.sendWireFrame(errorFrame);\n\t\t\treturn;\n\t\t}\n\n\t\tlet validatedInput: unknown;\n\t\tif (procedure.input) {\n\t\t\ttry {\n\t\t\t\tvalidatedInput = await parseStandardSchema(procedure.input, frame.body);\n\t\t\t} catch (err) {\n\t\t\t\tconst msg =\n\t\t\t\t\terr instanceof Error ? err.message : \"Input validation failed\";\n\t\t\t\tconst errorFrame = encodeServerError(frame.id, msg, {\n\t\t\t\t\trpc: rpcName,\n\t\t\t\t});\n\t\t\t\tthis.sendWireFrame(errorFrame);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tlet result: unknown;\n\t\ttry {\n\t\t\tif (procedure.input) {\n\t\t\t\tconst handler = this.config.handlers[rpcName] as (\n\t\t\t\t\tinput: unknown,\n\t\t\t\t\ts: SockaWebSocketSession<TContract, TData>,\n\t\t\t\t) => unknown | Promise<unknown>;\n\t\t\t\tresult = await handler(validatedInput, this);\n\t\t\t} else {\n\t\t\t\tconst handler = this.config.handlers[rpcName] as (\n\t\t\t\t\ts: SockaWebSocketSession<TContract, TData>,\n\t\t\t\t) => unknown | Promise<unknown>;\n\t\t\t\tresult = await handler(this);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.config.onHandlerError?.(err, rpcName, validatedInput, this);\n\t\t\tconst sockaErr =\n\t\t\t\terr instanceof SockaError\n\t\t\t\t\t? err\n\t\t\t\t\t: new SockaError(\n\t\t\t\t\t\t\terr instanceof Error ? err.message : \"Handler failed\",\n\t\t\t\t\t\t);\n\t\t\tconst errorFrame = encodeServerError(frame.id, sockaErr.message, {\n\t\t\t\trpc: rpcName,\n\t\t\t\tcode: sockaErr.code,\n\t\t\t\tdata: sockaErr.data,\n\t\t\t});\n\t\t\tthis.sendWireFrame(errorFrame);\n\t\t\treturn;\n\t\t}\n\n\t\tif (procedure.output === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet validatedOutput: unknown;\n\t\ttry {\n\t\t\tvalidatedOutput = await parseStandardSchema(procedure.output, result);\n\t\t} catch (err) {\n\t\t\tconst msg =\n\t\t\t\terr instanceof Error ? err.message : \"Output validation failed\";\n\t\t\tconst errorFrame = encodeServerError(frame.id, msg, { rpc: rpcName });\n\t\t\tthis.sendWireFrame(errorFrame);\n\t\t\treturn;\n\t\t}\n\n\t\tconst responseFrame = encodeServerResponse(\n\t\t\tframe.id,\n\t\t\trpcName,\n\t\t\tvalidatedOutput,\n\t\t);\n\t\tthis.sendWireFrame(responseFrame);\n\t}\n\n\tprivate encodeOutgoing(frame: SockaWireFrame): string | Uint8Array {\n\t\treturn encodeSockaWire(\n\t\t\tframe,\n\t\t\tthis.wireFormat,\n\t\t\tthis.config.serializeJson ?? JSON.stringify,\n\t\t);\n\t}\n\n\tprivate sendWireFrame(frame: SockaWireFrame): void {\n\t\tif (this.websocket.readyState !== WebSocket.OPEN) {\n\t\t\treturn;\n\t\t}\n\t\tconst encoded = this.encodeOutgoing(frame);\n\t\tif (typeof encoded === \"string\") {\n\t\t\tthis.websocket.send(encoded);\n\t\t\treturn;\n\t\t}\n\t\tconst copy = new Uint8Array(encoded.byteLength);\n\t\tcopy.set(encoded);\n\t\tthis.websocket.send(copy.buffer);\n\t}\n\n\t/**\n\t * Send a server event frame (wire). Prefer {@link emitPush} so\n\t * payloads are validated against the contract.\n\t */\n\tpublic emitWireEvent(event: string, body: unknown): void {\n\t\tconst frame = encodeServerEvent(event, body);\n\t\tthis.sendWireFrame(frame);\n\t}\n\n\tpublic async emitPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t): Promise<void> {\n\t\tconst schema = this.config.contract.pushes[name];\n\t\tif (!schema) {\n\t\t\tthrow new Error(`socka: unknown push ${String(name)}`);\n\t\t}\n\t\tconst validated = await parseStandardSchema(\n\t\t\tschema as StandardSchemaV1<unknown, InferSockaPushPayload<TContract, K>>,\n\t\t\tbody,\n\t\t);\n\t\tthis.emitWireEvent(name, validated);\n\t}\n\n\tpublic async broadcastPush<K extends keyof TContract[\"pushes\"] & string>(\n\t\tname: K,\n\t\tbody: InferSockaPushPayload<TContract, K>,\n\t\texcludeSelf = false,\n\t): Promise<void> {\n\t\tconst schema = this.config.contract.pushes[name];\n\t\tif (!schema) {\n\t\t\tthrow new Error(`socka: unknown push ${String(name)}`);\n\t\t}\n\t\tconst validated = await parseStandardSchema(\n\t\t\tschema as StandardSchemaV1<unknown, InferSockaPushPayload<TContract, K>>,\n\t\t\tbody,\n\t\t);\n\t\tbroadcastSockaEventToPeers(\n\t\t\tthis.sessions,\n\t\t\tthis,\n\t\t\tname,\n\t\t\tvalidated,\n\t\t\texcludeSelf,\n\t\t);\n\t}\n\n\tprivate async reportValidationError(\n\t\terror: unknown,\n\t\toriginalMessage: unknown,\n\t): Promise<void> {\n\t\tif (this.config.onValidationError) {\n\t\t\tawait this.config.onValidationError(error, originalMessage);\n\t\t} else {\n\t\t\tconsole.error(\"socka: validation error:\", error, originalMessage);\n\t\t}\n\t}\n}\n\n/**\n * Invoke {@link SockaWebSocketSessionConfig.onAttached} after the session is\n * registered in the shared map.\n */\nexport function runSockaSessionOnAttached<\n\tTContract extends SockaContract<SockaContractConfig>,\n\tTData,\n>(\n\tconfig: SockaWebSocketSessionConfigUnion<TContract, TData>,\n\tsession: SockaWebSocketSession<TContract, TData>,\n): void {\n\tconst cb = config.onAttached;\n\tif (!cb) return;\n\ttry {\n\t\tconst result = cb(session);\n\t\tvoid Promise.resolve(result).catch((error: unknown) => {\n\t\t\treportSockaError(config.reportError, {\n\t\t\t\tkind: \"serverOnAttached\",\n\t\t\t\terror,\n\t\t\t});\n\t\t});\n\t} catch (error) {\n\t\treportSockaError(config.reportError, { kind: \"serverOnAttached\", error });\n\t}\n}\n"]}