statewire 0.20.0 → 0.22.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 (143) hide show
  1. package/dist/client/changes.d.ts +3 -6
  2. package/dist/client/changes.d.ts.map +1 -1
  3. package/dist/client/changes.js +1 -2
  4. package/dist/client/connection.d.ts +80 -83
  5. package/dist/client/connection.d.ts.map +1 -1
  6. package/dist/client/connection.js +20 -7
  7. package/dist/client/connection.js.map +1 -1
  8. package/dist/client/core.d.ts +39 -41
  9. package/dist/client/core.d.ts.map +1 -1
  10. package/dist/client/core.js +2 -3
  11. package/dist/client/session.d.ts +93 -93
  12. package/dist/client/session.d.ts.map +1 -1
  13. package/dist/client/session.js +47 -23
  14. package/dist/client/session.js.map +1 -1
  15. package/dist/client/sessionStore.d.ts +11 -14
  16. package/dist/client/sessionStore.d.ts.map +1 -1
  17. package/dist/client/sessionStore.js +1 -2
  18. package/dist/client/storageError.d.ts +2 -5
  19. package/dist/client/storageError.d.ts.map +1 -1
  20. package/dist/client/storageError.js +1 -2
  21. package/dist/client/timing.d.ts +11 -14
  22. package/dist/client/timing.d.ts.map +1 -1
  23. package/dist/client/timing.js +1 -2
  24. package/dist/document.d.ts +17 -20
  25. package/dist/document.d.ts.map +1 -1
  26. package/dist/document.js +1 -2
  27. package/dist/host/adapter.d.ts +4 -7
  28. package/dist/host/adapter.d.ts.map +1 -1
  29. package/dist/host/adapter.js +1 -2
  30. package/dist/host/draft.d.ts +13 -16
  31. package/dist/host/draft.d.ts.map +1 -1
  32. package/dist/host/draft.js +1 -2
  33. package/dist/host/engine.d.ts +7 -10
  34. package/dist/host/engine.d.ts.map +1 -1
  35. package/dist/host/engine.js +1 -2
  36. package/dist/host/host.d.ts +42 -45
  37. package/dist/host/host.d.ts.map +1 -1
  38. package/dist/host/host.js +15 -13
  39. package/dist/host/host.js.map +1 -1
  40. package/dist/host/http.d.ts +4 -7
  41. package/dist/host/http.d.ts.map +1 -1
  42. package/dist/host/http.js +15 -11
  43. package/dist/host/http.js.map +1 -1
  44. package/dist/host/socket.d.ts +145 -140
  45. package/dist/host/socket.d.ts.map +1 -1
  46. package/dist/host/socket.js +99 -17
  47. package/dist/host/socket.js.map +1 -1
  48. package/dist/host/synced.d.ts +3 -6
  49. package/dist/host/synced.d.ts.map +1 -1
  50. package/dist/host/synced.js +1 -2
  51. package/dist/host/work.d.ts +2 -5
  52. package/dist/host/work.d.ts.map +1 -1
  53. package/dist/host/work.js +1 -2
  54. package/dist/host-internal.d.ts +99 -90
  55. package/dist/host-internal.d.ts.map +1 -1
  56. package/dist/host.d.ts +90 -91
  57. package/dist/host.d.ts.map +1 -1
  58. package/dist/index.d.ts +11 -8
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +1 -1
  61. package/dist/statewire.d.ts +265 -268
  62. package/dist/statewire.d.ts.map +1 -1
  63. package/dist/statewire.js +7 -7
  64. package/dist/statewire.js.map +1 -1
  65. package/dist/storage.d.ts +23 -26
  66. package/dist/storage.d.ts.map +1 -1
  67. package/dist/storage.js +1 -2
  68. package/dist/transports/fake-sse.d.ts +7 -10
  69. package/dist/transports/fake-sse.d.ts.map +1 -1
  70. package/dist/transports/fake-sse.js +1 -2
  71. package/dist/transports/fixtures.d.ts +19 -25
  72. package/dist/transports/fixtures.d.ts.map +1 -1
  73. package/dist/transports/fixtures.js +1 -2
  74. package/dist/transports/remote.d.ts +8 -11
  75. package/dist/transports/remote.d.ts.map +1 -1
  76. package/dist/transports/remote.js +1 -2
  77. package/dist/transports/sse-parser.d.ts +1 -4
  78. package/dist/transports/sse-parser.d.ts.map +1 -1
  79. package/dist/transports/sse-parser.js +1 -2
  80. package/dist/transports/sse.d.ts +50 -52
  81. package/dist/transports/sse.d.ts.map +1 -1
  82. package/dist/transports/sse.js +9 -3
  83. package/dist/transports/sse.js.map +1 -1
  84. package/dist/transports/testing.d.ts +31 -34
  85. package/dist/transports/testing.d.ts.map +1 -1
  86. package/dist/transports/testing.js +1 -2
  87. package/dist/transports/ws.d.ts +5 -7
  88. package/dist/transports/ws.d.ts.map +1 -1
  89. package/dist/transports/ws.js +3 -4
  90. package/dist/transports/ws.js.map +1 -1
  91. package/dist/types.d.ts +81 -78
  92. package/dist/types.d.ts.map +1 -1
  93. package/dist/types.js +1 -2
  94. package/dist/util/draftTraps.d.ts +2 -4
  95. package/dist/util/draftTraps.d.ts.map +1 -1
  96. package/dist/util/draftTraps.js +1 -2
  97. package/dist/util/macrotask.d.ts +1 -4
  98. package/dist/util/macrotask.d.ts.map +1 -1
  99. package/dist/util/macrotask.js +1 -2
  100. package/dist/util/methodProxy.d.ts +1 -4
  101. package/dist/util/methodProxy.d.ts.map +1 -1
  102. package/dist/util/methodProxy.js +1 -2
  103. package/dist/util/randomId.d.ts +1 -4
  104. package/dist/util/randomId.d.ts.map +1 -1
  105. package/dist/util/randomId.js +1 -2
  106. package/dist/util/recordMutations.d.ts +5 -7
  107. package/dist/util/recordMutations.d.ts.map +1 -1
  108. package/dist/util/recordMutations.js +1 -2
  109. package/dist/util/statePath.d.ts +9 -12
  110. package/dist/util/statePath.d.ts.map +1 -1
  111. package/dist/util/statePath.js +1 -2
  112. package/dist/wire/context.d.ts +7 -12
  113. package/dist/wire/context.d.ts.map +1 -1
  114. package/dist/wire/context.js +2 -3
  115. package/dist/wire/documents.d.ts +36 -39
  116. package/dist/wire/documents.d.ts.map +1 -1
  117. package/dist/wire/documents.js +2 -3
  118. package/dist/wire/documents.js.map +1 -1
  119. package/dist/wire/limits.d.ts +7 -10
  120. package/dist/wire/limits.d.ts.map +1 -1
  121. package/dist/wire/limits.js +1 -2
  122. package/dist/wire/meta.d.ts +9 -11
  123. package/dist/wire/meta.d.ts.map +1 -1
  124. package/dist/wire/meta.js +1 -2
  125. package/dist/wire/meta.js.map +1 -1
  126. package/dist/wire/ops.d.ts +9 -12
  127. package/dist/wire/ops.d.ts.map +1 -1
  128. package/dist/wire/ops.js +1 -2
  129. package/dist/wire/protocol.d.ts +53 -56
  130. package/dist/wire/protocol.d.ts.map +1 -1
  131. package/dist/wire/protocol.js +1 -2
  132. package/dist/wire/version.d.ts +1 -4
  133. package/dist/wire/version.d.ts.map +1 -1
  134. package/dist/wire/version.js +1 -2
  135. package/package.json +6 -6
  136. package/src/client/connection.ts +25 -15
  137. package/src/client/session.ts +54 -15
  138. package/src/host/host.ts +9 -3
  139. package/src/host/http.ts +37 -5
  140. package/src/host/socket.ts +158 -9
  141. package/src/host-internal.ts +14 -0
  142. package/src/statewire.ts +11 -6
  143. package/src/transports/sse.ts +12 -0
package/dist/host/http.js CHANGED
@@ -1,7 +1,7 @@
1
- import { MAX_FRAME_BODY_BYTES } from "../wire/limits.js";
2
1
  import { negotiateProtocols } from "../wire/protocol.js";
3
- import { CLIENT_ID_RE, PRINCIPAL_MISMATCH_MESSAGE, SUBSCRIBER_LIMIT_MESSAGE, admitFrame, atSubscriberLimit, authEquals, closeConn, flush, parseFrame, parseFrameValue, register, sendTo } from "./socket.js";
4
- //#region src/host/http.ts
2
+ import { MAX_FRAME_BODY_BYTES } from "../wire/limits.js";
3
+ import { CLIENT_ID_RE, PRINCIPAL_MISMATCH_MESSAGE, SUBSCRIBER_LIMIT_MESSAGE, admitFrame, atSubscriberLimit, authEquals, closeConn, expireLease, flush, parseFrame, parseFrameValue, register, sendTo } from "./socket.js";
4
+ // src/host/http.ts
5
5
  const CLIENT_ID_HEADER = "Statewire-Client-Id";
6
6
  const LEASE_HEADER = "Statewire-Lease";
7
7
  const encoder = new TextEncoder();
@@ -50,7 +50,10 @@ const clientIdResponse = (request) => {
50
50
  const headersOf = (request) => Object.fromEntries(request.headers);
51
51
  const authorize = async (h, headers) => {
52
52
  try {
53
- return { auth: await h.authorize?.({ headers }) };
53
+ return {
54
+ auth: await h.authorize?.({ headers }),
55
+ authorizedAt: Date.now()
56
+ };
54
57
  } catch (error) {
55
58
  if (error instanceof Response) return { refused: error };
56
59
  throw error;
@@ -66,7 +69,7 @@ const mintLease = () => {
66
69
  const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
67
70
  return btoa(String.fromCharCode(...bytes)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
68
71
  };
69
- const attachSse = (h, clientId, auth, selection, frame) => {
72
+ const attachSse = (h, clientId, auth, authorizedAt, selection, frame) => {
70
73
  let controller;
71
74
  let connection = null;
72
75
  let open = true;
@@ -109,7 +112,7 @@ const attachSse = (h, clientId, auth, selection, frame) => {
109
112
  return;
110
113
  }
111
114
  }
112
- }, false, auth, selection, frame);
115
+ }, false, auth, selection, frame, authorizedAt);
113
116
  connection = registration?.connection ?? null;
114
117
  if (!open) connection?.close();
115
118
  return {
@@ -140,7 +143,7 @@ const getStream = async (h, request) => {
140
143
  if (atSubscriberLimit(h)) return subscriberLimitResponse();
141
144
  const selection = negotiateProtocols(request.headers, h.wireVersion, [h.protocol]);
142
145
  if ("fin" in selection) return Response.json(selection, { status: selection.fin.status });
143
- const attachment = attachSse(h, client.clientId, authorized.auth, selection);
146
+ const attachment = attachSse(h, client.clientId, authorized.auth, authorized.authorizedAt, selection);
144
147
  const lease = attachment.registration === null ? null : mintLease();
145
148
  if (attachment.registration !== null) attachment.registration.conn.lease = lease;
146
149
  return streamResponse(attachment, lease);
@@ -172,7 +175,7 @@ const postStream = async (h, request) => {
172
175
  if ("fin" in selection) return Response.json(selection, { status: selection.fin.status });
173
176
  let attachment;
174
177
  try {
175
- attachment = attachSse(h, client.clientId, authorized.auth, selection, frame);
178
+ attachment = attachSse(h, client.clientId, authorized.auth, authorized.authorizedAt, selection, frame);
176
179
  } catch (error) {
177
180
  if (!(error instanceof Error) || error.name !== "StatewireViolation") throw error;
178
181
  return Response.json({ fin: {
@@ -211,9 +214,10 @@ const violationResponse = (h, clientId, reason) => {
211
214
  const frames = async (h, request) => {
212
215
  const lease = request.headers.get(LEASE_HEADER);
213
216
  const leased = lease === null ? void 0 : [...h.conns].find((conn) => conn.open && conn.lease === lease);
214
- if (h.disposed || h.finished !== null || leased === void 0) return Response.json({ error: "stale-lease" }, { status: 423 });
217
+ if (h.disposed || h.finished !== null || leased === void 0 || expireLease(h, leased)) return Response.json({ error: "stale-lease" }, { status: 423 });
215
218
  const clientId = leased.clientId;
216
219
  const raw = await readFrameBody(request);
220
+ if (!leased.open || h.disposed || h.finished !== null || expireLease(h, leased)) return Response.json({ error: "stale-lease" }, { status: 423 });
217
221
  if (raw === null) return Response.json({ error: "frame body too large" }, { status: 413 });
218
222
  let frame;
219
223
  try {
@@ -222,7 +226,7 @@ const frames = async (h, request) => {
222
226
  if (!(error instanceof Error) || error.name !== "StatewireViolation") throw error;
223
227
  return violationResponse(h, clientId, error.message);
224
228
  }
225
- if (!leased.open || h.disposed || h.finished !== null) return Response.json({ error: "stale-lease" }, { status: 423 });
229
+ if (!leased.open || h.disposed || h.finished !== null || expireLease(h, leased)) return Response.json({ error: "stale-lease" }, { status: 423 });
226
230
  let admission;
227
231
  try {
228
232
  admission = admitFrame(h, leased, frame);
@@ -230,6 +234,7 @@ const frames = async (h, request) => {
230
234
  if (!(error instanceof Error) || error.name !== "StatewireViolation") throw error;
231
235
  return violationResponse(h, clientId, error.message);
232
236
  }
237
+ if (admission.type === "expired") return Response.json({ error: "stale-lease" }, { status: 423 });
233
238
  if (admission.type === "refused") {
234
239
  const retry = admission.syn.syn.retry;
235
240
  return Response.json(admission.syn, {
@@ -239,7 +244,6 @@ const frames = async (h, request) => {
239
244
  }
240
245
  return Response.json({});
241
246
  };
242
- //#endregion
243
247
  export { MAX_FRAME_BODY_BYTES, frames, stream };
244
248
 
245
249
  //# sourceMappingURL=http.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","names":["StatewireHost","CLIENT_ID_RE","PRINCIPAL_MISMATCH_MESSAGE","SUBSCRIBER_LIMIT_MESSAGE","admitFrame","atSubscriberLimit","authEquals","closeConn","flush","parseFrame","parseFrameValue","register","sendTo","ParsedFrame","Registration","SocketHostState","MAX_FRAME_BODY_BYTES","negotiateProtocols","StatewireProtocol","CLIENT_ID_HEADER","LEASE_HEADER","encoder","TextEncoder","laggardFin","encode","readFrameBody","request","Request","Promise","declared","headers","get","Number","body","cancel","catch","reader","getReader","chunks","Uint8Array","size","done","value","read","length","push","offset","chunk","set","TextDecoder","decode","invalidClientIdReason","clientId","test","clientIdResponse","response","Response","json","detail","status","reason","headersOf","Record","Object","fromEntries","authorize","h","auth","refused","error","subscriberLimitResponse","principalMismatchResponse","rec","clients","undefined","principal","mintLease","bytes","crypto","getRandomValues","btoa","String","fromCharCode","replaceAll","replace","SseAttachment","ReadableStream","registration","activateBackpressure","attachSse","selection","Selection","frame","controller","ReadableStreamDefaultController","connection","open","backpressureActive","start","next","close","highWaterMark","streamQueueSize","socket","send","data","desiredSize","enqueue","streamResponse","attachment","lease","getStream","authorized","client","mismatch","wireVersion","protocol","fin","conn","postStream","raw","trim","JSON","parse","cmd","Error","name","message","stream","method","Allow","finClient","Fin","conns","stringify","violationResponse","frames","leased","find","disposed","finished","admission","ReturnType","type","retry","syn","Math","ceil"],"sources":["../../src/host/http.ts"],"sourcesContent":["import type { StatewireHost } from \"../host\";\nimport {\n CLIENT_ID_RE,\n PRINCIPAL_MISMATCH_MESSAGE,\n SUBSCRIBER_LIMIT_MESSAGE,\n admitFrame,\n atSubscriberLimit,\n authEquals,\n closeConn,\n flush,\n parseFrame,\n parseFrameValue,\n register,\n sendTo,\n} from \"./socket\";\nimport type { ParsedFrame, Registration, SocketHostState } from \"./socket\";\nimport { MAX_FRAME_BODY_BYTES } from \"../wire/limits\";\nimport { negotiateProtocols } from \"../wire/protocol\";\nimport type { StatewireProtocol } from \"../wire/protocol\";\n\nexport { MAX_FRAME_BODY_BYTES } from \"../wire/limits\";\n\nconst CLIENT_ID_HEADER = \"Statewire-Client-Id\";\nconst LEASE_HEADER = \"Statewire-Lease\";\nconst encoder = new TextEncoder();\nconst laggardFin = encoder.encode(\n 'data: {\"fin\":{\"reason\":\"reconnect\",\"code\":\"client-fell-behind\"}}\\n\\n',\n);\nconst readFrameBody = async (request: Request): Promise<string | null> => {\n const declared = request.headers.get(\"content-length\");\n if (declared !== null && Number(declared) > MAX_FRAME_BODY_BYTES) {\n await request.body?.cancel(\"frame body too large\").catch(() => {});\n return null;\n }\n if (request.body === null) return \"\";\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.length;\n if (size > MAX_FRAME_BODY_BYTES) {\n await reader.cancel(\"frame body too large\").catch(() => {});\n return null;\n }\n chunks.push(value);\n }\n const body = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.length;\n }\n return new TextDecoder().decode(body);\n};\n\nconst invalidClientIdReason = (clientId: string): string | null => {\n if (clientId === \"\") return \"id must be non-empty\";\n if (clientId.length > 256) return \"id must be at most 256 characters\";\n if (!CLIENT_ID_RE.test(clientId)) {\n return \"id must contain only [A-Za-z0-9._~-]\";\n }\n return null;\n};\n\nconst clientIdResponse = (\n request: Request,\n): { clientId: string } | { response: Response } => {\n const clientId = request.headers.get(CLIENT_ID_HEADER);\n if (clientId === null) {\n return {\n response: Response.json(\n { detail: `missing ${CLIENT_ID_HEADER} header` },\n { status: 400 },\n ),\n };\n }\n const reason = invalidClientIdReason(clientId);\n if (reason !== null) {\n return {\n response: Response.json(\n { detail: `invalid ${CLIENT_ID_HEADER}: ${reason}` },\n { status: 400 },\n ),\n };\n }\n return { clientId };\n};\n\nconst headersOf = (request: Request): Record<string, string> =>\n Object.fromEntries(request.headers);\n\nconst authorize = async (\n h: SocketHostState,\n headers: Record<string, string>,\n): Promise<{ auth: unknown } | { refused: Response }> => {\n try {\n return { auth: await h.authorize?.({ headers }) };\n } catch (error) {\n if (error instanceof Response) return { refused: error };\n throw error;\n }\n};\n\nconst subscriberLimitResponse = (): Response =>\n Response.json({ detail: SUBSCRIBER_LIMIT_MESSAGE }, { status: 503 });\n\n// No awaits between this check and register: the binding cannot race.\nconst principalMismatchResponse = (\n h: SocketHostState,\n clientId: string,\n auth: unknown,\n): Response | null => {\n const rec = h.clients.get(clientId);\n if (rec !== undefined && !authEquals(rec.principal, auth)) {\n return Response.json(\n { detail: PRINCIPAL_MISMATCH_MESSAGE },\n { status: 403 },\n );\n }\n return null;\n};\n\nconst mintLease = (): string => {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return btoa(String.fromCharCode(...bytes))\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replace(/=+$/, \"\");\n};\n\ntype SseAttachment = {\n body: ReadableStream<Uint8Array>;\n registration: Registration | null;\n activateBackpressure: () => void;\n};\n\nconst attachSse = (\n h: SocketHostState,\n clientId: string,\n auth: unknown,\n selection: StatewireProtocol.Selection,\n frame?: ParsedFrame,\n): SseAttachment => {\n let controller: ReadableStreamDefaultController<Uint8Array>;\n let connection: Registration[\"connection\"] | null = null;\n let open = true;\n let backpressureActive = false;\n const body = new ReadableStream(\n {\n start: (next) => {\n controller = next;\n },\n cancel: () => {\n open = false;\n connection?.close();\n },\n },\n { highWaterMark: h.streamQueueSize },\n );\n const socket = {\n send: (data: string) => {\n if (!open) return;\n if (\n backpressureActive &&\n controller.desiredSize !== null &&\n controller.desiredSize <= 0\n ) {\n open = false;\n try {\n controller.enqueue(laggardFin);\n controller.close();\n } catch {\n /* stream already gone */\n }\n connection?.close();\n return;\n }\n const frame = data === \"{}\" ? \": ping\\n\\n\" : `data: ${data}\\n\\n`;\n try {\n controller.enqueue(encoder.encode(frame));\n } catch {\n open = false;\n connection?.close();\n }\n },\n close: () => {\n if (!open) return;\n open = false;\n try {\n controller.close();\n } catch {\n return;\n }\n },\n };\n const registration = register(\n h,\n clientId,\n socket,\n false,\n auth,\n selection,\n frame,\n );\n connection = registration?.connection ?? null;\n if (!open) connection?.close();\n return {\n body,\n registration,\n activateBackpressure: () => {\n backpressureActive = true;\n },\n };\n};\n\nconst streamResponse = (\n attachment: SseAttachment,\n lease: string | null,\n): Response => {\n attachment.activateBackpressure();\n return new Response(attachment.body, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n ...(lease !== null && { [LEASE_HEADER]: lease }),\n },\n });\n};\n\nconst getStream = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n const authorized = await authorize(h, headersOf(request));\n if (\"refused\" in authorized) return authorized.refused;\n const client = clientIdResponse(request);\n if (\"response\" in client) return client.response;\n const mismatch = principalMismatchResponse(\n h,\n client.clientId,\n authorized.auth,\n );\n if (mismatch !== null) return mismatch;\n if (atSubscriberLimit(h)) return subscriberLimitResponse();\n const selection = negotiateProtocols(request.headers, h.wireVersion, [\n h.protocol,\n ]);\n if (\"fin\" in selection)\n return Response.json(selection, { status: selection.fin.status });\n const attachment = attachSse(h, client.clientId, authorized.auth, selection);\n const lease = attachment.registration === null ? null : mintLease();\n if (attachment.registration !== null)\n attachment.registration.conn.lease = lease;\n return streamResponse(attachment, lease);\n};\n\nconst postStream = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n const client = clientIdResponse(request);\n if (\"response\" in client) return client.response;\n const raw = await readFrameBody(request);\n if (raw === null) {\n return Response.json({ detail: \"frame body too large\" }, { status: 413 });\n }\n let body: unknown;\n try {\n body = raw.trim() ? JSON.parse(raw) : null;\n } catch {\n return Response.json({ detail: \"body must be JSON\" }, { status: 400 });\n }\n let frame: ParsedFrame;\n try {\n frame = body === null && !raw.trim() ? { cmd: [] } : parseFrameValue(body);\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\") {\n throw error;\n }\n return Response.json({ detail: error.message }, { status: 400 });\n }\n const authorized = await authorize(h, headersOf(request));\n if (\"refused\" in authorized) return authorized.refused;\n const mismatch = principalMismatchResponse(\n h,\n client.clientId,\n authorized.auth,\n );\n if (mismatch !== null) return mismatch;\n if (atSubscriberLimit(h)) return subscriberLimitResponse();\n const selection = negotiateProtocols(request.headers, h.wireVersion, [\n h.protocol,\n ]);\n if (\"fin\" in selection)\n return Response.json(selection, { status: selection.fin.status });\n let attachment: SseAttachment;\n try {\n attachment = attachSse(\n h,\n client.clientId,\n authorized.auth,\n selection,\n frame,\n );\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\")\n throw error;\n return Response.json(\n { fin: { reason: \"protocol-error\", message: error.message } },\n { status: 400 },\n );\n }\n if (attachment.registration === null) return streamResponse(attachment, null);\n const lease = mintLease();\n attachment.registration.conn.lease = lease;\n return streamResponse(attachment, lease);\n};\n\nexport const stream = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n if (request.method === \"GET\") return getStream(h, request);\n if (request.method === \"POST\") return postStream(h, request);\n return new Response(null, {\n status: 405,\n headers: { Allow: \"GET, POST\" },\n });\n};\n\nconst finClient = (\n h: SocketHostState,\n clientId: string,\n fin: StatewireHost.Fin,\n) => {\n flush(h);\n for (const conn of [...h.conns]) {\n if (conn.clientId !== clientId) continue;\n sendTo(h, conn, JSON.stringify({ fin }));\n closeConn(h, conn);\n }\n};\n\nconst violationResponse = (\n h: SocketHostState,\n clientId: string,\n reason: string,\n) => {\n finClient(h, clientId, {\n reason: \"protocol-error\",\n message: reason,\n });\n return Response.json({ error: reason }, { status: 400 });\n};\n\nexport const frames = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n const lease = request.headers.get(LEASE_HEADER);\n // A lease lives and dies with its attach: any live attach of the id accepts.\n const leased =\n lease === null\n ? undefined\n : [...h.conns].find((conn) => conn.open && conn.lease === lease);\n if (h.disposed || h.finished !== null || leased === undefined) {\n return Response.json({ error: \"stale-lease\" }, { status: 423 });\n }\n const clientId = leased.clientId;\n const raw = await readFrameBody(request);\n if (raw === null) {\n return Response.json({ error: \"frame body too large\" }, { status: 413 });\n }\n let frame: ParsedFrame;\n try {\n frame = parseFrame(raw);\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\") {\n throw error;\n }\n return violationResponse(h, clientId, error.message);\n }\n if (!leased.open || h.disposed || h.finished !== null) {\n return Response.json({ error: \"stale-lease\" }, { status: 423 });\n }\n let admission: ReturnType<typeof admitFrame>;\n try {\n admission = admitFrame(h, leased, frame);\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\")\n throw error;\n return violationResponse(h, clientId, error.message);\n }\n if (admission.type === \"refused\") {\n const retry = admission.syn.syn.retry;\n return Response.json(admission.syn, {\n status: retry === undefined ? 409 : 429,\n ...(retry !== undefined && {\n headers: { \"Retry-After\": String(Math.ceil(retry / 1000)) },\n }),\n });\n }\n return Response.json({});\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"http.js","names":["StatewireHost","CLIENT_ID_RE","PRINCIPAL_MISMATCH_MESSAGE","SUBSCRIBER_LIMIT_MESSAGE","admitFrame","atSubscriberLimit","authEquals","closeConn","flush","expireLease","parseFrame","parseFrameValue","register","sendTo","ParsedFrame","Registration","SocketHostState","MAX_FRAME_BODY_BYTES","negotiateProtocols","StatewireProtocol","CLIENT_ID_HEADER","LEASE_HEADER","encoder","TextEncoder","laggardFin","encode","readFrameBody","request","Request","Promise","declared","headers","get","Number","body","cancel","catch","reader","getReader","chunks","Uint8Array","size","done","value","read","length","push","offset","chunk","set","TextDecoder","decode","invalidClientIdReason","clientId","test","clientIdResponse","response","Response","json","detail","status","reason","headersOf","Record","Object","fromEntries","authorize","h","auth","authorizedAt","refused","Date","now","error","subscriberLimitResponse","principalMismatchResponse","rec","clients","undefined","principal","mintLease","bytes","crypto","getRandomValues","btoa","String","fromCharCode","replaceAll","replace","SseAttachment","ReadableStream","registration","activateBackpressure","attachSse","selection","Selection","frame","controller","ReadableStreamDefaultController","connection","open","backpressureActive","start","next","close","highWaterMark","streamQueueSize","socket","send","data","desiredSize","enqueue","streamResponse","attachment","lease","getStream","authorized","client","mismatch","wireVersion","protocol","fin","conn","postStream","raw","trim","JSON","parse","cmd","Error","name","message","stream","method","Allow","finClient","Fin","conns","stringify","violationResponse","frames","leased","find","disposed","finished","admission","ReturnType","type","retry","syn","Math","ceil"],"sources":["../../src/host/http.ts"],"sourcesContent":["import type { StatewireHost } from \"../host\";\nimport {\n CLIENT_ID_RE,\n PRINCIPAL_MISMATCH_MESSAGE,\n SUBSCRIBER_LIMIT_MESSAGE,\n admitFrame,\n atSubscriberLimit,\n authEquals,\n closeConn,\n flush,\n expireLease,\n parseFrame,\n parseFrameValue,\n register,\n sendTo,\n} from \"./socket\";\nimport type { ParsedFrame, Registration, SocketHostState } from \"./socket\";\nimport { MAX_FRAME_BODY_BYTES } from \"../wire/limits\";\nimport { negotiateProtocols } from \"../wire/protocol\";\nimport type { StatewireProtocol } from \"../wire/protocol\";\n\nexport { MAX_FRAME_BODY_BYTES } from \"../wire/limits\";\n\nconst CLIENT_ID_HEADER = \"Statewire-Client-Id\";\nconst LEASE_HEADER = \"Statewire-Lease\";\nconst encoder = new TextEncoder();\nconst laggardFin = encoder.encode(\n 'data: {\"fin\":{\"reason\":\"reconnect\",\"code\":\"client-fell-behind\"}}\\n\\n',\n);\nconst readFrameBody = async (request: Request): Promise<string | null> => {\n const declared = request.headers.get(\"content-length\");\n if (declared !== null && Number(declared) > MAX_FRAME_BODY_BYTES) {\n await request.body?.cancel(\"frame body too large\").catch(() => {});\n return null;\n }\n if (request.body === null) return \"\";\n const reader = request.body.getReader();\n const chunks: Uint8Array[] = [];\n let size = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.length;\n if (size > MAX_FRAME_BODY_BYTES) {\n await reader.cancel(\"frame body too large\").catch(() => {});\n return null;\n }\n chunks.push(value);\n }\n const body = new Uint8Array(size);\n let offset = 0;\n for (const chunk of chunks) {\n body.set(chunk, offset);\n offset += chunk.length;\n }\n return new TextDecoder().decode(body);\n};\n\nconst invalidClientIdReason = (clientId: string): string | null => {\n if (clientId === \"\") return \"id must be non-empty\";\n if (clientId.length > 256) return \"id must be at most 256 characters\";\n if (!CLIENT_ID_RE.test(clientId)) {\n return \"id must contain only [A-Za-z0-9._~-]\";\n }\n return null;\n};\n\nconst clientIdResponse = (\n request: Request,\n): { clientId: string } | { response: Response } => {\n const clientId = request.headers.get(CLIENT_ID_HEADER);\n if (clientId === null) {\n return {\n response: Response.json(\n { detail: `missing ${CLIENT_ID_HEADER} header` },\n { status: 400 },\n ),\n };\n }\n const reason = invalidClientIdReason(clientId);\n if (reason !== null) {\n return {\n response: Response.json(\n { detail: `invalid ${CLIENT_ID_HEADER}: ${reason}` },\n { status: 400 },\n ),\n };\n }\n return { clientId };\n};\n\nconst headersOf = (request: Request): Record<string, string> =>\n Object.fromEntries(request.headers);\n\nconst authorize = async (\n h: SocketHostState,\n headers: Record<string, string>,\n): Promise<{ auth: unknown; authorizedAt: number } | { refused: Response }> => {\n try {\n const auth = await h.authorize?.({ headers });\n return { auth, authorizedAt: Date.now() };\n } catch (error) {\n if (error instanceof Response) return { refused: error };\n throw error;\n }\n};\n\nconst subscriberLimitResponse = (): Response =>\n Response.json({ detail: SUBSCRIBER_LIMIT_MESSAGE }, { status: 503 });\n\n// No awaits between this check and register: the binding cannot race.\nconst principalMismatchResponse = (\n h: SocketHostState,\n clientId: string,\n auth: unknown,\n): Response | null => {\n const rec = h.clients.get(clientId);\n if (rec !== undefined && !authEquals(rec.principal, auth)) {\n return Response.json(\n { detail: PRINCIPAL_MISMATCH_MESSAGE },\n { status: 403 },\n );\n }\n return null;\n};\n\nconst mintLease = (): string => {\n const bytes = crypto.getRandomValues(new Uint8Array(16));\n return btoa(String.fromCharCode(...bytes))\n .replaceAll(\"+\", \"-\")\n .replaceAll(\"/\", \"_\")\n .replace(/=+$/, \"\");\n};\n\ntype SseAttachment = {\n body: ReadableStream<Uint8Array>;\n registration: Registration | null;\n activateBackpressure: () => void;\n};\n\nconst attachSse = (\n h: SocketHostState,\n clientId: string,\n auth: unknown,\n authorizedAt: number,\n selection: StatewireProtocol.Selection,\n frame?: ParsedFrame,\n): SseAttachment => {\n let controller: ReadableStreamDefaultController<Uint8Array>;\n let connection: Registration[\"connection\"] | null = null;\n let open = true;\n let backpressureActive = false;\n const body = new ReadableStream(\n {\n start: (next) => {\n controller = next;\n },\n cancel: () => {\n open = false;\n connection?.close();\n },\n },\n { highWaterMark: h.streamQueueSize },\n );\n const socket = {\n send: (data: string) => {\n if (!open) return;\n if (\n backpressureActive &&\n controller.desiredSize !== null &&\n controller.desiredSize <= 0\n ) {\n open = false;\n try {\n controller.enqueue(laggardFin);\n controller.close();\n } catch {\n /* stream already gone */\n }\n connection?.close();\n return;\n }\n const frame = data === \"{}\" ? \": ping\\n\\n\" : `data: ${data}\\n\\n`;\n try {\n controller.enqueue(encoder.encode(frame));\n } catch {\n open = false;\n connection?.close();\n }\n },\n close: () => {\n if (!open) return;\n open = false;\n try {\n controller.close();\n } catch {\n return;\n }\n },\n };\n const registration = register(\n h,\n clientId,\n socket,\n false,\n auth,\n selection,\n frame,\n authorizedAt,\n );\n connection = registration?.connection ?? null;\n if (!open) connection?.close();\n return {\n body,\n registration,\n activateBackpressure: () => {\n backpressureActive = true;\n },\n };\n};\n\nconst streamResponse = (\n attachment: SseAttachment,\n lease: string | null,\n): Response => {\n attachment.activateBackpressure();\n return new Response(attachment.body, {\n status: 200,\n headers: {\n \"Content-Type\": \"text/event-stream\",\n ...(lease !== null && { [LEASE_HEADER]: lease }),\n },\n });\n};\n\nconst getStream = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n const authorized = await authorize(h, headersOf(request));\n if (\"refused\" in authorized) return authorized.refused;\n const client = clientIdResponse(request);\n if (\"response\" in client) return client.response;\n const mismatch = principalMismatchResponse(\n h,\n client.clientId,\n authorized.auth,\n );\n if (mismatch !== null) return mismatch;\n if (atSubscriberLimit(h)) return subscriberLimitResponse();\n const selection = negotiateProtocols(request.headers, h.wireVersion, [\n h.protocol,\n ]);\n if (\"fin\" in selection)\n return Response.json(selection, { status: selection.fin.status });\n const attachment = attachSse(\n h,\n client.clientId,\n authorized.auth,\n authorized.authorizedAt,\n selection,\n );\n const lease = attachment.registration === null ? null : mintLease();\n if (attachment.registration !== null)\n attachment.registration.conn.lease = lease;\n return streamResponse(attachment, lease);\n};\n\nconst postStream = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n const client = clientIdResponse(request);\n if (\"response\" in client) return client.response;\n const raw = await readFrameBody(request);\n if (raw === null) {\n return Response.json({ detail: \"frame body too large\" }, { status: 413 });\n }\n let body: unknown;\n try {\n body = raw.trim() ? JSON.parse(raw) : null;\n } catch {\n return Response.json({ detail: \"body must be JSON\" }, { status: 400 });\n }\n let frame: ParsedFrame;\n try {\n frame = body === null && !raw.trim() ? { cmd: [] } : parseFrameValue(body);\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\") {\n throw error;\n }\n return Response.json({ detail: error.message }, { status: 400 });\n }\n const authorized = await authorize(h, headersOf(request));\n if (\"refused\" in authorized) return authorized.refused;\n const mismatch = principalMismatchResponse(\n h,\n client.clientId,\n authorized.auth,\n );\n if (mismatch !== null) return mismatch;\n if (atSubscriberLimit(h)) return subscriberLimitResponse();\n const selection = negotiateProtocols(request.headers, h.wireVersion, [\n h.protocol,\n ]);\n if (\"fin\" in selection)\n return Response.json(selection, { status: selection.fin.status });\n let attachment: SseAttachment;\n try {\n attachment = attachSse(\n h,\n client.clientId,\n authorized.auth,\n authorized.authorizedAt,\n selection,\n frame,\n );\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\")\n throw error;\n return Response.json(\n { fin: { reason: \"protocol-error\", message: error.message } },\n { status: 400 },\n );\n }\n if (attachment.registration === null) return streamResponse(attachment, null);\n const lease = mintLease();\n attachment.registration.conn.lease = lease;\n return streamResponse(attachment, lease);\n};\n\nexport const stream = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n if (request.method === \"GET\") return getStream(h, request);\n if (request.method === \"POST\") return postStream(h, request);\n return new Response(null, {\n status: 405,\n headers: { Allow: \"GET, POST\" },\n });\n};\n\nconst finClient = (\n h: SocketHostState,\n clientId: string,\n fin: StatewireHost.Fin,\n) => {\n flush(h);\n for (const conn of [...h.conns]) {\n if (conn.clientId !== clientId) continue;\n sendTo(h, conn, JSON.stringify({ fin }));\n closeConn(h, conn);\n }\n};\n\nconst violationResponse = (\n h: SocketHostState,\n clientId: string,\n reason: string,\n) => {\n finClient(h, clientId, {\n reason: \"protocol-error\",\n message: reason,\n });\n return Response.json({ error: reason }, { status: 400 });\n};\n\nexport const frames = async (\n h: SocketHostState,\n request: Request,\n): Promise<Response> => {\n const lease = request.headers.get(LEASE_HEADER);\n // A lease lives and dies with its attach: any live attach of the id accepts.\n const leased =\n lease === null\n ? undefined\n : [...h.conns].find((conn) => conn.open && conn.lease === lease);\n if (\n h.disposed ||\n h.finished !== null ||\n leased === undefined ||\n expireLease(h, leased)\n ) {\n return Response.json({ error: \"stale-lease\" }, { status: 423 });\n }\n const clientId = leased.clientId;\n const raw = await readFrameBody(request);\n if (\n !leased.open ||\n h.disposed ||\n h.finished !== null ||\n expireLease(h, leased)\n ) {\n return Response.json({ error: \"stale-lease\" }, { status: 423 });\n }\n if (raw === null) {\n return Response.json({ error: \"frame body too large\" }, { status: 413 });\n }\n let frame: ParsedFrame;\n try {\n frame = parseFrame(raw);\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\") {\n throw error;\n }\n return violationResponse(h, clientId, error.message);\n }\n if (\n !leased.open ||\n h.disposed ||\n h.finished !== null ||\n expireLease(h, leased)\n ) {\n return Response.json({ error: \"stale-lease\" }, { status: 423 });\n }\n let admission: ReturnType<typeof admitFrame>;\n try {\n admission = admitFrame(h, leased, frame);\n } catch (error) {\n if (!(error instanceof Error) || error.name !== \"StatewireViolation\")\n throw error;\n return violationResponse(h, clientId, error.message);\n }\n if (admission.type === \"expired\") {\n return Response.json({ error: \"stale-lease\" }, { status: 423 });\n }\n if (admission.type === \"refused\") {\n const retry = admission.syn.syn.retry;\n return Response.json(admission.syn, {\n status: retry === undefined ? 409 : 429,\n ...(retry !== undefined && {\n headers: { \"Retry-After\": String(Math.ceil(retry / 1000)) },\n }),\n });\n }\n return Response.json({});\n};\n"],"mappings":";;;;AAuBA,MAAMoB,mBAAmB;AACzB,MAAMC,eAAe;AACrB,MAAMC,UAAU,IAAIC,YAAY;AAChC,MAAMC,aAAaF,QAAQG,OACzB,gFACF;AACA,MAAMC,gBAAgB,OAAOC,YAA6C;CACxE,MAAMG,WAAWH,QAAQI,QAAQC,IAAI,gBAAgB;CACrD,IAAIF,aAAa,QAAQG,OAAOH,QAAQ,IAAA,SAA0B;EAChE,MAAMH,QAAQO,MAAMC,OAAO,sBAAsB,CAAC,CAACC,YAAY,CAAC,CAAC;EACjE,OAAO;CACT;CACA,IAAIT,QAAQO,SAAS,MAAM,OAAO;CAClC,MAAMG,SAASV,QAAQO,KAAKI,UAAU;CACtC,MAAMC,SAAuB,CAAA;CAC7B,IAAIE,OAAO;CACX,SAAS;EACP,MAAM,EAAEC,MAAMC,UAAU,MAAMN,OAAOO,KAAK;EAC1C,IAAIF,MAAM;EACVD,QAAQE,MAAME;EACd,IAAIJ,OAAAA,SAA6B;GAC/B,MAAMJ,OAAOF,OAAO,sBAAsB,CAAC,CAACC,YAAY,CAAC,CAAC;GAC1D,OAAO;EACT;EACAG,OAAOO,KAAKH,KAAK;CACnB;CACA,MAAMT,OAAO,IAAIM,WAAWC,IAAI;CAChC,IAAIM,SAAS;CACb,KAAK,MAAMC,SAAST,QAAQ;EAC1BL,KAAKe,IAAID,OAAOD,MAAM;EACtBA,UAAUC,MAAMH;CAClB;CACA,OAAO,IAAIK,YAAY,CAAC,CAACC,OAAOjB,IAAI;AACtC;AAEA,MAAMkB,yBAAyBC,aAAoC;CACjE,IAAIA,aAAa,IAAI,OAAO;CAC5B,IAAIA,SAASR,SAAS,KAAK,OAAO;CAClC,IAAI,CAAC5C,aAAaqD,KAAKD,QAAQ,GAC7B,OAAO;CAET,OAAO;AACT;AAEA,MAAME,oBACJ5B,YACkD;CAClD,MAAM0B,WAAW1B,QAAQI,QAAQC,IAAIZ,gBAAgB;CACrD,IAAIiC,aAAa,MACf,OAAO,EACLG,UAAUC,SAASC,KACjB,EAAEC,QAAQ,WAAWvC,iBAAgB,SAAU,GAC/C,EAAEwC,QAAQ,IAAI,CAChB,EACF;CAEF,MAAMC,SAAST,sBAAsBC,QAAQ;CAC7C,IAAIQ,WAAW,MACb,OAAO,EACLL,UAAUC,SAASC,KACjB,EAAEC,QAAQ,WAAWvC,iBAAgB,IAAKyC,SAAS,GACnD,EAAED,QAAQ,IAAI,CAChB,EACF;CAEF,OAAO,EAAEP,SAAS;AACpB;AAEA,MAAMS,aAAanC,YACjBqC,OAAOC,YAAYtC,QAAQI,OAAO;AAEpC,MAAMmC,YAAY,OAChBC,GACApC,YAC6E;CAC7E,IAAI;EAEF,OAAO;GAAEqC,MAAAA,MADUD,EAAED,YAAY,EAAEnC,QAAQ,CAAC;GAC7BsC,cAAcE,KAAKC,IAAI;EAAE;CAC1C,SAASC,OAAO;EACd,IAAIA,iBAAiBhB,UAAU,OAAO,EAAEa,SAASG,MAAM;EACvD,MAAMA;CACR;AACF;AAEA,MAAMC,gCACJjB,SAASC,KAAK,EAAEC,QAAQxD,yBAAyB,GAAG,EAAEyD,QAAQ,IAAI,CAAC;AAGrE,MAAMe,6BACJR,GACAd,UACAe,SACoB;CACpB,MAAMQ,MAAMT,EAAEU,QAAQ7C,IAAIqB,QAAQ;CAClC,IAAIuB,QAAQE,KAAAA,KAAa,CAACxE,WAAWsE,IAAIG,WAAWX,IAAI,GACtD,OAAOX,SAASC,KACd,EAAEC,QAAQzD,2BAA2B,GACrC,EAAE0D,QAAQ,IAAI,CAChB;CAEF,OAAO;AACT;AAEA,MAAMoB,kBAA0B;CAC9B,MAAMC,QAAQC,OAAOC,gCAAgB,IAAI3C,WAAW,EAAE,CAAC;CACvD,OAAO4C,KAAKC,OAAOC,aAAa,GAAGL,KAAK,CAAC,CAAC,CACvCM,WAAW,KAAK,GAAG,CAAC,CACpBA,WAAW,KAAK,GAAG,CAAC,CACpBC,QAAQ,OAAO,EAAE;AACtB;AAQA,MAAMK,aACJ1B,GACAd,UACAe,MACAC,cACAyB,WACAE,UACkB;CAClB,IAAIC;CACJ,IAAIE,aAAgD;CACpD,IAAIC,OAAO;CACX,IAAIC,qBAAqB;CACzB,MAAMnE,OAAO,IAAIwD,eACf;EACEY,QAAQC,SAAS;GACfN,aAAaM;EACf;EACApE,cAAc;GACZiE,OAAO;GACPD,YAAYK,MAAM;EACpB;CACF,GACA,EAAEC,eAAetC,EAAEuC,gBAAgB,CACrC;CAqCA,MAAMf,eAAe/E,SACnBuD,GACAd,UACAsD;EAtCAC,OAAOC,SAAiB;GACtB,IAAI,CAACT,MAAM;GACX,IACEC,sBACAJ,WAAWa,gBAAgB,QAC3Bb,WAAWa,eAAe,GAC1B;IACAV,OAAO;IACP,IAAI;KACFH,WAAWc,QAAQvF,UAAU;KAC7ByE,WAAWO,MAAM;IACnB,QAAQ,CACN;IAEFL,YAAYK,MAAM;IAClB;GACF;GACA,MAAMR,QAAQa,SAAS,OAAO,eAAe,SAASA,KAAI;GAC1D,IAAI;IACFZ,WAAWc,QAAQzF,QAAQG,OAAOuE,KAAK,CAAC;GAC1C,QAAQ;IACNI,OAAO;IACPD,YAAYK,MAAM;GACpB;EACF;EACAA,aAAa;GACX,IAAI,CAACJ,MAAM;GACXA,OAAO;GACP,IAAI;IACFH,WAAWO,MAAM;GACnB,QAAQ;IACN;GACF;EACF;CAKAG,GACA,OACAvC,MACA0B,WACAE,OACA3B,YACF;CACA8B,aAAaR,cAAcQ,cAAc;CACzC,IAAI,CAACC,MAAMD,YAAYK,MAAM;CAC7B,OAAO;EACLtE;EACAyD;EACAC,4BAA4B;GAC1BS,qBAAqB;EACvB;CACF;AACF;AAEA,MAAMW,kBACJC,YACAC,UACa;CACbD,WAAWrB,qBAAqB;CAChC,OAAO,IAAInC,SAASwD,WAAW/E,MAAM;EACnC0B,QAAQ;EACR7B,SAAS;GACP,gBAAgB;GAChB,GAAImF,UAAU,QAAQ,GAAG7F,eAAe6F,MAAM;EAChD;CACF,CAAC;AACH;AAEA,MAAMC,YAAY,OAChBhD,GACAxC,YACsB;CACtB,MAAMyF,aAAa,MAAMlD,UAAUC,GAAGL,UAAUnC,OAAO,CAAC;CACxD,IAAI,aAAayF,YAAY,OAAOA,WAAW9C;CAC/C,MAAM+C,SAAS9D,iBAAiB5B,OAAO;CACvC,IAAI,cAAc0F,QAAQ,OAAOA,OAAO7D;CACxC,MAAM8D,WAAW3C,0BACfR,GACAkD,OAAOhE,UACP+D,WAAWhD,IACb;CACA,IAAIkD,aAAa,MAAM,OAAOA;CAC9B,IAAIjH,kBAAkB8D,CAAC,GAAG,OAAOO,wBAAwB;CACzD,MAAMoB,YAAY5E,mBAAmBS,QAAQI,SAASoC,EAAEoD,aAAa,CACnEpD,EAAEqD,QAAQ,CACX;CACD,IAAI,SAAS1B,WACX,OAAOrC,SAASC,KAAKoC,WAAW,EAAElC,QAAQkC,UAAU2B,IAAI7D,OAAO,CAAC;CAClE,MAAMqD,aAAapB,UACjB1B,GACAkD,OAAOhE,UACP+D,WAAWhD,MACXgD,WAAW/C,cACXyB,SACF;CACA,MAAMoB,QAAQD,WAAWtB,iBAAiB,OAAO,OAAOX,UAAU;CAClE,IAAIiC,WAAWtB,iBAAiB,MAC9BsB,WAAWtB,aAAa+B,KAAKR,QAAQA;CACvC,OAAOF,eAAeC,YAAYC,KAAK;AACzC;AAEA,MAAMS,aAAa,OACjBxD,GACAxC,YACsB;CACtB,MAAM0F,SAAS9D,iBAAiB5B,OAAO;CACvC,IAAI,cAAc0F,QAAQ,OAAOA,OAAO7D;CACxC,MAAMoE,MAAM,MAAMlG,cAAcC,OAAO;CACvC,IAAIiG,QAAQ,MACV,OAAOnE,SAASC,KAAK,EAAEC,QAAQ,uBAAuB,GAAG,EAAEC,QAAQ,IAAI,CAAC;CAE1E,IAAI1B;CACJ,IAAI;EACFA,OAAO0F,IAAIC,KAAK,IAAIC,KAAKC,MAAMH,GAAG,IAAI;CACxC,QAAQ;EACN,OAAOnE,SAASC,KAAK,EAAEC,QAAQ,oBAAoB,GAAG,EAAEC,QAAQ,IAAI,CAAC;CACvE;CACA,IAAIoC;CACJ,IAAI;EACFA,QAAQ9D,SAAS,QAAQ,CAAC0F,IAAIC,KAAK,IAAI,EAAEG,KAAK,CAAA,EAAG,IAAIrH,gBAAgBuB,IAAI;CAC3E,SAASuC,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EAER,OAAOhB,SAASC,KAAK,EAAEC,QAAQc,MAAM0D,QAAQ,GAAG,EAAEvE,QAAQ,IAAI,CAAC;CACjE;CACA,MAAMwD,aAAa,MAAMlD,UAAUC,GAAGL,UAAUnC,OAAO,CAAC;CACxD,IAAI,aAAayF,YAAY,OAAOA,WAAW9C;CAC/C,MAAMgD,WAAW3C,0BACfR,GACAkD,OAAOhE,UACP+D,WAAWhD,IACb;CACA,IAAIkD,aAAa,MAAM,OAAOA;CAC9B,IAAIjH,kBAAkB8D,CAAC,GAAG,OAAOO,wBAAwB;CACzD,MAAMoB,YAAY5E,mBAAmBS,QAAQI,SAASoC,EAAEoD,aAAa,CACnEpD,EAAEqD,QAAQ,CACX;CACD,IAAI,SAAS1B,WACX,OAAOrC,SAASC,KAAKoC,WAAW,EAAElC,QAAQkC,UAAU2B,IAAI7D,OAAO,CAAC;CAClE,IAAIqD;CACJ,IAAI;EACFA,aAAapB,UACX1B,GACAkD,OAAOhE,UACP+D,WAAWhD,MACXgD,WAAW/C,cACXyB,WACAE,KACF;CACF,SAASvB,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EACR,OAAOhB,SAASC,KACd,EAAE+D,KAAK;GAAE5D,QAAQ;GAAkBsE,SAAS1D,MAAM0D;EAAQ,EAAE,GAC5D,EAAEvE,QAAQ,IAAI,CAChB;CACF;CACA,IAAIqD,WAAWtB,iBAAiB,MAAM,OAAOqB,eAAeC,YAAY,IAAI;CAC5E,MAAMC,QAAQlC,UAAU;CACxBiC,WAAWtB,aAAa+B,KAAKR,QAAQA;CACrC,OAAOF,eAAeC,YAAYC,KAAK;AACzC;AAEA,MAAakB,SAAS,OACpBjE,GACAxC,YACsB;CACtB,IAAIA,QAAQ0G,WAAW,OAAO,OAAOlB,UAAUhD,GAAGxC,OAAO;CACzD,IAAIA,QAAQ0G,WAAW,QAAQ,OAAOV,WAAWxD,GAAGxC,OAAO;CAC3D,OAAO,IAAI8B,SAAS,MAAM;EACxBG,QAAQ;EACR7B,SAAS,EAAEuG,OAAO,YAAY;CAChC,CAAC;AACH;AAEA,MAAMC,aACJpE,GACAd,UACAoE,QACG;CACHjH,MAAM2D,CAAC;CACP,KAAK,MAAMuD,QAAQ,CAAC,GAAGvD,EAAEsE,KAAK,GAAG;EAC/B,IAAIf,KAAKrE,aAAaA,UAAU;EAChCxC,OAAOsD,GAAGuD,MAAMI,KAAKY,UAAU,EAAEjB,IAAI,CAAC,CAAC;EACvClH,UAAU4D,GAAGuD,IAAI;CACnB;AACF;AAEA,MAAMiB,qBACJxE,GACAd,UACAQ,WACG;CACH0E,UAAUpE,GAAGd,UAAU;EACrBQ,QAAQ;EACRsE,SAAStE;CACX,CAAC;CACD,OAAOJ,SAASC,KAAK,EAAEe,OAAOZ,OAAO,GAAG,EAAED,QAAQ,IAAI,CAAC;AACzD;AAEA,MAAagF,SAAS,OACpBzE,GACAxC,YACsB;CACtB,MAAMuF,QAAQvF,QAAQI,QAAQC,IAAIX,YAAY;CAE9C,MAAMwH,SACJ3B,UAAU,OACNpC,KAAAA,IACA,CAAC,GAAGX,EAAEsE,KAAK,CAAC,CAACK,MAAMpB,SAASA,KAAKtB,QAAQsB,KAAKR,UAAUA,KAAK;CACnE,IACE/C,EAAE4E,YACF5E,EAAE6E,aAAa,QACfH,WAAW/D,KAAAA,KACXrE,YAAY0D,GAAG0E,MAAM,GAErB,OAAOpF,SAASC,KAAK,EAAEe,OAAO,cAAc,GAAG,EAAEb,QAAQ,IAAI,CAAC;CAEhE,MAAMP,WAAWwF,OAAOxF;CACxB,MAAMuE,MAAM,MAAMlG,cAAcC,OAAO;CACvC,IACE,CAACkH,OAAOzC,QACRjC,EAAE4E,YACF5E,EAAE6E,aAAa,QACfvI,YAAY0D,GAAG0E,MAAM,GAErB,OAAOpF,SAASC,KAAK,EAAEe,OAAO,cAAc,GAAG,EAAEb,QAAQ,IAAI,CAAC;CAEhE,IAAIgE,QAAQ,MACV,OAAOnE,SAASC,KAAK,EAAEe,OAAO,uBAAuB,GAAG,EAAEb,QAAQ,IAAI,CAAC;CAEzE,IAAIoC;CACJ,IAAI;EACFA,QAAQtF,WAAWkH,GAAG;CACxB,SAASnD,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EAER,OAAOkE,kBAAkBxE,GAAGd,UAAUoB,MAAM0D,OAAO;CACrD;CACA,IACE,CAACU,OAAOzC,QACRjC,EAAE4E,YACF5E,EAAE6E,aAAa,QACfvI,YAAY0D,GAAG0E,MAAM,GAErB,OAAOpF,SAASC,KAAK,EAAEe,OAAO,cAAc,GAAG,EAAEb,QAAQ,IAAI,CAAC;CAEhE,IAAIqF;CACJ,IAAI;EACFA,YAAY7I,WAAW+D,GAAG0E,QAAQ7C,KAAK;CACzC,SAASvB,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EACR,OAAOkE,kBAAkBxE,GAAGd,UAAUoB,MAAM0D,OAAO;CACrD;CACA,IAAIc,UAAUE,SAAS,WACrB,OAAO1F,SAASC,KAAK,EAAEe,OAAO,cAAc,GAAG,EAAEb,QAAQ,IAAI,CAAC;CAEhE,IAAIqF,UAAUE,SAAS,WAAW;EAChC,MAAMC,QAAQH,UAAUI,IAAIA,IAAID;EAChC,OAAO3F,SAASC,KAAKuF,UAAUI,KAAK;GAClCzF,QAAQwF,UAAUtE,KAAAA,IAAY,MAAM;GACpC,GAAIsE,UAAUtE,KAAAA,KAAa,EACzB/C,SAAS,EAAE,eAAesD,OAAOiE,KAAKC,KAAKH,QAAQ,GAAI,CAAC,EAAE,EAC5D;EACF,CAAC;CACH;CACA,OAAO3F,SAASC,KAAK,CAAC,CAAC;AACzB"}
@@ -1,168 +1,174 @@
1
- import { CommandsHost } from "./host.js";
2
- import { StatewireHost } from "../host.js";
3
- import { StatewireProtocol } from "../wire/protocol.js";
4
- import { StatewireDocument } from "../document.js";
5
- import { Statewire } from "../types.js";
6
- import { StatewirePath } from "../wire/ops.js";
7
- import { StatewireHostInternal } from "../host-internal.js";
8
- import { ResourceElement } from "@assistant-ui/tap";
9
- //#region src/host/socket.d.ts
10
- declare const CLIENT_ID_RE: RegExp;
11
- declare const PRINCIPAL_MISMATCH_MESSAGE = "client id is bound to another principal";
1
+ import type { StatewireProtocol } from "../wire/protocol.js";
2
+ import type { ResourceElement } from "@assistant-ui/tap";
3
+ import type { CommandsHost } from "./host.js";
4
+ import type { Statewire } from "../types.js";
5
+ import type { StatewireHost } from "../host.js";
6
+ import type { StatewireHostInternal } from "../host-internal.js";
7
+ import type { StatewireDocument } from "../document.js";
8
+ import type { StatewirePath } from "../wire/ops.js";
9
+ export declare const CLIENT_ID_RE: RegExp;
10
+ export declare const PRINCIPAL_MISMATCH_MESSAGE = "client id is bound to another principal";
12
11
  /** Structural equality over auth values: primitives, Dates, arrays, and plain
13
12
  * objects compare by value; anything else by identity. */
14
- declare const authEquals: (a: unknown, b: unknown) => boolean;
15
- declare const SUBSCRIBER_LIMIT_MESSAGE = "stream subscriber limit reached";
13
+ export declare const authEquals: (a: unknown, b: unknown) => boolean;
14
+ export declare const SUBSCRIBER_LIMIT_MESSAGE = "stream subscriber limit reached";
16
15
  type Cmd = StatewireHostInternal.Cmd;
17
16
  type WireOp = {
18
- op: string;
19
- doc?: number;
20
- path?: StatewirePath;
21
- value?: unknown;
22
- meta?: StatewireDocument.MetaEntry[];
23
- protocol?: string;
24
- key?: readonly string[];
25
- main?: boolean;
17
+ op: string;
18
+ doc?: number;
19
+ path?: StatewirePath;
20
+ value?: unknown;
21
+ meta?: StatewireDocument.MetaEntry[];
22
+ protocol?: string;
23
+ key?: readonly string[];
24
+ main?: boolean;
26
25
  };
27
26
  type Admission = {
28
- protocol: string;
29
- seq: number;
30
- method: string;
31
- applied: boolean;
32
- appliedSent: boolean;
33
- settled: boolean;
27
+ protocol: string;
28
+ seq: number;
29
+ method: string;
30
+ applied: boolean;
31
+ appliedSent: boolean;
32
+ settled: boolean;
34
33
  };
35
34
  /** One statement lane: durable lanes live on the client record, ephemeral lanes on the attach. */
36
35
  type Lane = {
37
- protocol: string;
38
- clientId: string;
39
- conn: Conn | null;
40
- lastSeq: number;
41
- results: Map<number, {
42
- ts: number;
43
- cmd: Cmd;
44
- }>;
45
- inflight: Map<number, Admission>;
36
+ protocol: string;
37
+ clientId: string;
38
+ conn: Conn | null;
39
+ lastSeq: number;
40
+ results: Map<number, {
41
+ ts: number;
42
+ cmd: Cmd;
43
+ }>;
44
+ inflight: Map<number, Admission>;
46
45
  };
47
- type ClientRec = {
48
- id: string;
49
- touched: number;
50
- lanes: Map<string, Lane>;
51
- /** The auth captured at the record's first attach; later attaches must match. */
52
- principal: unknown;
46
+ export type ClientRec = {
47
+ id: string;
48
+ touched: number;
49
+ lanes: Map<string, Lane>;
50
+ /** The auth captured at the record's first attach; later attaches must match. */
51
+ principal: unknown;
53
52
  };
54
- type Conn = {
55
- selection: StatewireProtocol.Selection;
56
- clientId: string;
57
- socket: StatewireHostInternal.Socket;
58
- open: boolean;
59
- ready: boolean;
60
- sawFrame: boolean;
61
- lastSentAt: number;
62
- lease: string | null;
63
- /** The awaited `authorize` return captured at this attach's authorization. */
64
- auth: unknown;
65
- lanes: Map<string, Lane>;
66
- contexts: Map<string, Statewire.Context>;
67
- documents: Map<string, StatewireHost.Document>;
68
- included: Set<string>;
69
- view: Map<string, {
70
- doc: number;
71
- value: unknown;
72
- }>;
73
- nextDoc: number;
74
- pendingApplied: Cmd[];
75
- pendingCmds: Cmd[];
76
- attach: StatewireHost.Attach;
53
+ export type Conn = {
54
+ selection: StatewireProtocol.Selection;
55
+ clientId: string;
56
+ socket: StatewireHostInternal.Socket;
57
+ open: boolean;
58
+ ready: boolean;
59
+ sawFrame: boolean;
60
+ lastSentAt: number;
61
+ lease: string | null;
62
+ /** The awaited `authorize` return captured at this attach's authorization. */
63
+ auth: unknown;
64
+ authorizedAt: number | undefined;
65
+ leaseTimer: ReturnType<typeof setTimeout> | null;
66
+ lanes: Map<string, Lane>;
67
+ contexts: Map<string, Statewire.Context>;
68
+ documents: Map<string, StatewireHost.Document>;
69
+ included: Set<string>;
70
+ onIncludedChange: ((included: readonly StatewireHostInternal.IncludedDocument[]) => void) | undefined;
71
+ view: Map<string, {
72
+ doc: number;
73
+ value: unknown;
74
+ }>;
75
+ nextDoc: number;
76
+ pendingApplied: Cmd[];
77
+ pendingCmds: Cmd[];
78
+ attach: StatewireHost.Attach;
77
79
  };
78
80
  type PendingConn = {
79
- socket: StatewireHostInternal.Socket;
80
- open: boolean;
81
- authorizing: boolean;
82
- queued: string[];
83
- timer: ReturnType<typeof setTimeout> | null;
84
- connection: StatewireHostInternal.SocketConnection | null;
81
+ socket: StatewireHostInternal.Socket;
82
+ open: boolean;
83
+ authorizing: boolean;
84
+ queued: string[];
85
+ timer: ReturnType<typeof setTimeout> | null;
86
+ connection: StatewireHostInternal.SocketConnection | null;
85
87
  };
86
88
  type CmdStatement = {
87
- protocol: string;
88
- seq: number;
89
- method: string;
90
- params: unknown;
91
- meta?: unknown;
92
- };
93
- type ParsedFrame = {
94
- cmd: CmdStatement[];
95
- ctx?: {
96
89
  protocol: string;
97
- value: Statewire.Context;
98
- }[];
90
+ seq: number;
91
+ method: string;
92
+ params: unknown;
93
+ meta?: unknown;
99
94
  };
100
- declare const parseFrameValue: (frame: unknown) => ParsedFrame;
101
- declare const parseFrame: (raw: string) => ParsedFrame;
102
- type SocketHostState = {
103
- protocol: StatewireProtocol.Definition;
104
- key: readonly string[] | undefined;
105
- wireVersion: StatewireProtocol.Range;
106
- heartbeatMs: number;
107
- wsInitTimeoutMs: number;
108
- maxSubscribers: number;
109
- maxInflightCommands: number;
110
- streamQueueSize: number;
111
- clientRecordLimit: number;
112
- finOnIdle: boolean;
113
- pushback: (() => number | null) | undefined;
114
- authorize: StatewireHostInternal.SocketHostOptions["authorize"];
115
- clients: Map<string, ClientRec>;
116
- conns: Set<Conn>;
117
- pendingConns: Set<PendingConn>;
118
- pendingOps: WireOp[];
119
- pendingApplied: Map<string, Cmd[]>;
120
- pendingCmds: Map<string, Cmd[]>;
121
- viewsDirty: boolean;
122
- idleWire: boolean;
123
- finished: StatewireHost.Fin | null;
124
- disposed: boolean;
125
- flushScheduled: boolean;
126
- heartbeatTimer: ReturnType<typeof setInterval> | null;
127
- stateHost: StatewireHost.StateHost | null;
128
- commandsHost: CommandsHost | null;
129
- current: Statewire<unknown> | null;
130
- persistence: StatewireHostInternal.SocketHostPersistence | undefined;
131
- post: () => void;
132
- connect: (clientId: string, socket: StatewireHostInternal.Socket, options?: StatewireHostInternal.SocketConnectOptions) => StatewireHostInternal.SocketConnection | null;
133
- finish: (fin: StatewireHost.Fin) => void;
134
- stream: (request: Request) => Promise<Response>;
135
- frames: (request: Request) => Promise<Response>;
95
+ export type ParsedFrame = {
96
+ cmd: CmdStatement[];
97
+ ctx?: {
98
+ protocol: string;
99
+ value: Statewire.Context;
100
+ }[];
136
101
  };
137
- declare const closeConn: (h: SocketHostState, conn: Conn, code?: number, reason?: string) => void;
138
- declare const sendTo: (h: SocketHostState, conn: Conn, data: string) => void;
139
- declare const atSubscriberLimit: (h: SocketHostState) => boolean;
140
- declare const flush: (h: SocketHostState, fin?: StatewireHost.Fin) => void;
141
- type FrameAdmission = {
142
- type: "ok";
102
+ export declare const parseFrameValue: (frame: unknown) => ParsedFrame;
103
+ export declare const parseFrame: (raw: string) => ParsedFrame;
104
+ export type SocketHostState = {
105
+ protocol: StatewireProtocol.Definition;
106
+ key: readonly string[] | undefined;
107
+ wireVersion: StatewireProtocol.Range;
108
+ heartbeatMs: number;
109
+ maxLeaseLifetimeMs: number | null;
110
+ wsInitTimeoutMs: number;
111
+ maxSubscribers: number;
112
+ maxInflightCommands: number;
113
+ streamQueueSize: number;
114
+ clientRecordLimit: number;
115
+ finOnIdle: boolean;
116
+ pushback: (() => number | null) | undefined;
117
+ authorize: StatewireHostInternal.SocketHostOptions["authorize"];
118
+ clients: Map<string, ClientRec>;
119
+ conns: Set<Conn>;
120
+ pendingConns: Set<PendingConn>;
121
+ pendingOps: WireOp[];
122
+ pendingApplied: Map<string, Cmd[]>;
123
+ pendingCmds: Map<string, Cmd[]>;
124
+ viewsDirty: boolean;
125
+ idleWire: boolean;
126
+ finished: StatewireHost.Fin | null;
127
+ disposed: boolean;
128
+ flushScheduled: boolean;
129
+ heartbeatTimer: ReturnType<typeof setInterval> | null;
130
+ stateHost: StatewireHost.StateHost | null;
131
+ commandsHost: CommandsHost | null;
132
+ current: Statewire<unknown> | null;
133
+ persistence: StatewireHostInternal.SocketHostPersistence | undefined;
134
+ post: () => void;
135
+ connect: (clientId: string, socket: StatewireHostInternal.Socket, options?: StatewireHostInternal.SocketConnectOptions) => StatewireHostInternal.SocketConnection | null;
136
+ finish: (fin: StatewireHost.Fin) => void;
137
+ stream: (request: Request) => Promise<Response>;
138
+ frames: (request: Request) => Promise<Response>;
139
+ };
140
+ export declare const closeConn: (h: SocketHostState, conn: Conn, code?: number, reason?: string) => void;
141
+ export declare const sendTo: (h: SocketHostState, conn: Conn, data: string) => void;
142
+ export declare const expireLease: (h: SocketHostState, conn: Conn) => boolean;
143
+ export declare const atSubscriberLimit: (h: SocketHostState) => boolean;
144
+ export declare const flush: (h: SocketHostState, fin?: StatewireHost.Fin) => void;
145
+ export type FrameAdmission = {
146
+ type: "ok";
147
+ } | {
148
+ type: "expired";
143
149
  } | {
144
- type: "refused";
145
- syn: {
150
+ type: "refused";
146
151
  syn: {
147
- protocols: {
148
- name: string;
149
- seq: number;
150
- }[];
151
- retry?: number;
152
+ syn: {
153
+ protocols: {
154
+ name: string;
155
+ seq: number;
156
+ }[];
157
+ retry?: number;
158
+ };
152
159
  };
153
- };
154
160
  };
155
- declare const admitFrame: (h: SocketHostState, conn: Conn, frame: ParsedFrame) => FrameAdmission;
156
- type Registration = {
157
- conn: Conn;
158
- connection: StatewireHostInternal.SocketConnection;
161
+ export declare const admitFrame: (h: SocketHostState, conn: Conn, frame: ParsedFrame) => FrameAdmission;
162
+ export type Registration = {
163
+ conn: Conn;
164
+ connection: StatewireHostInternal.SocketConnection;
159
165
  };
160
166
  /**
161
167
  * Attach a socket: ephemeral-lane statements of the attach frame are admitted
162
168
  * before the snapshot (their documents and answers ride the hello), durable
163
169
  * ones after it. A violation in the attach frame closes the attach and throws.
164
170
  */
165
- declare const register: (h: SocketHostState, clientId: string, socket: StatewireHostInternal.Socket, sawFrame?: boolean, auth?: unknown, selection?: StatewireProtocol.Selection, frame?: ParsedFrame) => Registration | null;
171
+ export declare const register: (h: SocketHostState, clientId: string, socket: StatewireHostInternal.Socket, sawFrame?: boolean, auth?: unknown, selection?: StatewireProtocol.Selection, frame?: ParsedFrame, authorizedAt?: number, included?: Pick<StatewireHostInternal.SocketConnectOptions, "included" | "onIncludedChange">) => Registration | null;
166
172
  /**
167
173
  * Transport-agnostic WS binding over a statewire/host transport:
168
174
  * feed it sockets (anything with `send`/`close`) and raw text frames, and it
@@ -172,7 +178,6 @@ declare const register: (h: SocketHostState, clientId: string, socket: Statewire
172
178
  * admitting attach (ephemeral lanes), per-attach document views, idle edges,
173
179
  * and `fin` on finish.
174
180
  */
175
- declare const StatewireSocketHost: (transport: ResourceElement<Statewire>, options?: StatewireHostInternal.SocketHostOptions, persistence?: StatewireHostInternal.SocketHostPersistence) => StatewireHostInternal.SocketHost;
176
- //#endregion
177
- export { CLIENT_ID_RE, ClientRec, Conn, FrameAdmission, PRINCIPAL_MISMATCH_MESSAGE, ParsedFrame, Registration, SUBSCRIBER_LIMIT_MESSAGE, SocketHostState, StatewireSocketHost, admitFrame, atSubscriberLimit, authEquals, closeConn, flush, parseFrame, parseFrameValue, register, sendTo };
181
+ export declare const StatewireSocketHost: (transport: ResourceElement<Statewire>, options?: StatewireHostInternal.SocketHostOptions, persistence?: StatewireHostInternal.SocketHostPersistence) => StatewireHostInternal.SocketHost;
182
+ export {};
178
183
  //# sourceMappingURL=socket.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket.d.ts","names":[],"sources":["../../src/host/socket.ts"],"mappings":";;;;;;;;;cAiCa,cAAY;cACZ;;;cAKA,aAAc,YAAY;cAoC1B;KAGR,MAAM,sBAAsB;KAE5B;EACH;EACA;EACA,OAAO;EACP;EACA,OAAO,kBAAkB;EACzB;EACA;EACA;;KAGG;EACH;EACA;EACA;EACA;EACA;EACA;;;KAIG;EACH;EACA;EACA,MAAM;EACN;EACA,SAAS;IAAc;IAAY,KAAK;;EACxC,UAAU,YAAY;;KAGZ;EACV;EACA;EACA,OAAO,YAAY;;EAEnB;;KAIU;EACV,WAAW,kBAAkB;EAC7B;EACA,QAAQ,sBAAsB;EAC9B;EACA;EACA;EACA;EACA;;EAEA;EACA,OAAO,YAAY;EACnB,UAAU,YAAY,UAAU;EAChC,WAAW,YAAY,cAAc;EACrC,UAAU;EACV,MAAM;IAAc;IAAa;;EACjC;EACA,gBAAgB;EAChB,aAAa;EACb,QAAQ,cAAc;;KAGnB;EACH,QAAQ,sBAAsB;EAC9B;EACA;EACA;EACA,OAAO,kBAAkB;EACzB,YAAY,sBAAsB;;KAc/B;EACH;EACA;EACA;EACA;EACA;;KAGU;EACV,KAAK;EACL;IAAQ;IAAkB,OAAO,UAAU;;;cAQhC,kBAAmB,mBAAiB;cAqFpC,aAAc,gBAAc;KAyF7B;EACV,UAAU,kBAAkB;EAC5B;EACA,aAAa,kBAAkB;EAC/B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,WAAW,sBAAsB;EACjC,SAAS,YAAY;EACrB,OAAO,IAAI;EACX,cAAc,IAAI;EAClB,YAAY;EACZ,gBAAgB,YAAY;EAC5B,aAAa,YAAY;EACzB;EACA;EACA,UAAU,cAAc;EACxB;EACA;EACA,gBAAgB,kBAAkB;EAClC,WAAW,cAAc;EACzB,cAAc;EACd,SAAS;EACT,aAAa,sBAAsB;EACnC;EACA,UACE,kBACA,QAAQ,sBAAsB,QAC9B,UAAU,sBAAsB,yBAC7B,sBAAsB;EAC3B,SAAS,KAAK,cAAc;EAC5B,SAAS,SAAS,YAAY,QAAQ;EACtC,SAAS,SAAS,YAAY,QAAQ;;cAsD3B,YACX,GAAG,iBACH,MAAM,MACN,eACA;cAiBW,SAAU,GAAG,iBAAiB,MAAM,MAAM;cAmB1C,oBAAqB,GAAG;cAsLxB,QAAS,GAAG,iBAAiB,MAAM,cAAc;KAoUlD;EACN;;EAEA;EACA;IACE;MAAO;QAAa;QAAc;;MAAiB;;;;cAyE9C,aACX,GAAG,iBACH,MAAM,MACN,OAAO,gBACN;KA8YS;EACV,MAAM;EACN,YAAY,sBAAsB;;;;;;;cAQvB,WACX,GAAG,iBACH,kBACA,QAAQ,sBAAsB,QAC9B,oBACA,gBACA,YAAW,kBAAkB,WAI7B,QAAO,gBACN;;;;;;;;;;cA0UU,sBACX,WAAW,gBAAgB,YAC3B,UAAU,sBAAsB,mBAChC,cAAc,sBAAsB,0BACnC,sBAAsB"}
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/host/socket.ts"],"names":[],"mappings":"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"}