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.
- package/dist/client/changes.d.ts +3 -6
- package/dist/client/changes.d.ts.map +1 -1
- package/dist/client/changes.js +1 -2
- package/dist/client/connection.d.ts +80 -83
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +20 -7
- package/dist/client/connection.js.map +1 -1
- package/dist/client/core.d.ts +39 -41
- package/dist/client/core.d.ts.map +1 -1
- package/dist/client/core.js +2 -3
- package/dist/client/session.d.ts +93 -93
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +47 -23
- package/dist/client/session.js.map +1 -1
- package/dist/client/sessionStore.d.ts +11 -14
- package/dist/client/sessionStore.d.ts.map +1 -1
- package/dist/client/sessionStore.js +1 -2
- package/dist/client/storageError.d.ts +2 -5
- package/dist/client/storageError.d.ts.map +1 -1
- package/dist/client/storageError.js +1 -2
- package/dist/client/timing.d.ts +11 -14
- package/dist/client/timing.d.ts.map +1 -1
- package/dist/client/timing.js +1 -2
- package/dist/document.d.ts +17 -20
- package/dist/document.d.ts.map +1 -1
- package/dist/document.js +1 -2
- package/dist/host/adapter.d.ts +4 -7
- package/dist/host/adapter.d.ts.map +1 -1
- package/dist/host/adapter.js +1 -2
- package/dist/host/draft.d.ts +13 -16
- package/dist/host/draft.d.ts.map +1 -1
- package/dist/host/draft.js +1 -2
- package/dist/host/engine.d.ts +7 -10
- package/dist/host/engine.d.ts.map +1 -1
- package/dist/host/engine.js +1 -2
- package/dist/host/host.d.ts +42 -45
- package/dist/host/host.d.ts.map +1 -1
- package/dist/host/host.js +15 -13
- package/dist/host/host.js.map +1 -1
- package/dist/host/http.d.ts +4 -7
- package/dist/host/http.d.ts.map +1 -1
- package/dist/host/http.js +15 -11
- package/dist/host/http.js.map +1 -1
- package/dist/host/socket.d.ts +145 -140
- package/dist/host/socket.d.ts.map +1 -1
- package/dist/host/socket.js +99 -17
- package/dist/host/socket.js.map +1 -1
- package/dist/host/synced.d.ts +3 -6
- package/dist/host/synced.d.ts.map +1 -1
- package/dist/host/synced.js +1 -2
- package/dist/host/work.d.ts +2 -5
- package/dist/host/work.d.ts.map +1 -1
- package/dist/host/work.js +1 -2
- package/dist/host-internal.d.ts +99 -90
- package/dist/host-internal.d.ts.map +1 -1
- package/dist/host.d.ts +90 -91
- package/dist/host.d.ts.map +1 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -1
- package/dist/statewire.d.ts +265 -268
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js +7 -7
- package/dist/statewire.js.map +1 -1
- package/dist/storage.d.ts +23 -26
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +1 -2
- package/dist/transports/fake-sse.d.ts +7 -10
- package/dist/transports/fake-sse.d.ts.map +1 -1
- package/dist/transports/fake-sse.js +1 -2
- package/dist/transports/fixtures.d.ts +19 -25
- package/dist/transports/fixtures.d.ts.map +1 -1
- package/dist/transports/fixtures.js +1 -2
- package/dist/transports/remote.d.ts +8 -11
- package/dist/transports/remote.d.ts.map +1 -1
- package/dist/transports/remote.js +1 -2
- package/dist/transports/sse-parser.d.ts +1 -4
- package/dist/transports/sse-parser.d.ts.map +1 -1
- package/dist/transports/sse-parser.js +1 -2
- package/dist/transports/sse.d.ts +50 -52
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +9 -3
- package/dist/transports/sse.js.map +1 -1
- package/dist/transports/testing.d.ts +31 -34
- package/dist/transports/testing.d.ts.map +1 -1
- package/dist/transports/testing.js +1 -2
- package/dist/transports/ws.d.ts +5 -7
- package/dist/transports/ws.d.ts.map +1 -1
- package/dist/transports/ws.js +3 -4
- package/dist/transports/ws.js.map +1 -1
- package/dist/types.d.ts +81 -78
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -2
- package/dist/util/draftTraps.d.ts +2 -4
- package/dist/util/draftTraps.d.ts.map +1 -1
- package/dist/util/draftTraps.js +1 -2
- package/dist/util/macrotask.d.ts +1 -4
- package/dist/util/macrotask.d.ts.map +1 -1
- package/dist/util/macrotask.js +1 -2
- package/dist/util/methodProxy.d.ts +1 -4
- package/dist/util/methodProxy.d.ts.map +1 -1
- package/dist/util/methodProxy.js +1 -2
- package/dist/util/randomId.d.ts +1 -4
- package/dist/util/randomId.d.ts.map +1 -1
- package/dist/util/randomId.js +1 -2
- package/dist/util/recordMutations.d.ts +5 -7
- package/dist/util/recordMutations.d.ts.map +1 -1
- package/dist/util/recordMutations.js +1 -2
- package/dist/util/statePath.d.ts +9 -12
- package/dist/util/statePath.d.ts.map +1 -1
- package/dist/util/statePath.js +1 -2
- package/dist/wire/context.d.ts +7 -12
- package/dist/wire/context.d.ts.map +1 -1
- package/dist/wire/context.js +2 -3
- package/dist/wire/documents.d.ts +36 -39
- package/dist/wire/documents.d.ts.map +1 -1
- package/dist/wire/documents.js +2 -3
- package/dist/wire/documents.js.map +1 -1
- package/dist/wire/limits.d.ts +7 -10
- package/dist/wire/limits.d.ts.map +1 -1
- package/dist/wire/limits.js +1 -2
- package/dist/wire/meta.d.ts +9 -11
- package/dist/wire/meta.d.ts.map +1 -1
- package/dist/wire/meta.js +1 -2
- package/dist/wire/meta.js.map +1 -1
- package/dist/wire/ops.d.ts +9 -12
- package/dist/wire/ops.d.ts.map +1 -1
- package/dist/wire/ops.js +1 -2
- package/dist/wire/protocol.d.ts +53 -56
- package/dist/wire/protocol.d.ts.map +1 -1
- package/dist/wire/protocol.js +1 -2
- package/dist/wire/version.d.ts +1 -4
- package/dist/wire/version.d.ts.map +1 -1
- package/dist/wire/version.js +1 -2
- package/package.json +6 -6
- package/src/client/connection.ts +25 -15
- package/src/client/session.ts +54 -15
- package/src/host/host.ts +9 -3
- package/src/host/http.ts +37 -5
- package/src/host/socket.ts +158 -9
- package/src/host-internal.ts +14 -0
- package/src/statewire.ts +11 -6
- 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 {
|
|
4
|
-
|
|
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 {
|
|
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
|
package/dist/host/http.js.map
CHANGED
|
@@ -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":";;;;AAsBA,MAAMmB,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,CAAC3C,aAAaoD,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,YACuD;CACvD,IAAI;EACF,OAAO,EAAEqC,MAAM,MAAMD,EAAED,YAAY,EAAEnC,QAAQ,CAAC,EAAE;CAClD,SAASuC,OAAO;EACd,IAAIA,iBAAiBb,UAAU,OAAO,EAAEY,SAASC,MAAM;EACvD,MAAMA;CACR;AACF;AAEA,MAAMC,gCACJd,SAASC,KAAK,EAAEC,QAAQvD,yBAAyB,GAAG,EAAEwD,QAAQ,IAAI,CAAC;AAGrE,MAAMY,6BACJL,GACAd,UACAe,SACoB;CACpB,MAAMK,MAAMN,EAAEO,QAAQ1C,IAAIqB,QAAQ;CAClC,IAAIoB,QAAQE,KAAAA,KAAa,CAACpE,WAAWkE,IAAIG,WAAWR,IAAI,GACtD,OAAOX,SAASC,KACd,EAAEC,QAAQxD,2BAA2B,GACrC,EAAEyD,QAAQ,IAAI,CAChB;CAEF,OAAO;AACT;AAEA,MAAMiB,kBAA0B;CAC9B,MAAMC,QAAQC,OAAOC,gCAAgB,IAAIxC,WAAW,EAAE,CAAC;CACvD,OAAOyC,KAAKC,OAAOC,aAAa,GAAGL,KAAK,CAAC,CAAC,CACvCM,WAAW,KAAK,GAAG,CAAC,CACpBA,WAAW,KAAK,GAAG,CAAC,CACpBC,QAAQ,OAAO,EAAE;AACtB;AAQA,MAAMK,aACJvB,GACAd,UACAe,MACAuB,WACAE,UACkB;CAClB,IAAIC;CACJ,IAAIE,aAAgD;CACpD,IAAIC,OAAO;CACX,IAAIC,qBAAqB;CACzB,MAAMhE,OAAO,IAAIqD,eACf;EACEY,QAAQC,SAAS;GACfN,aAAaM;EACf;EACAjE,cAAc;GACZ8D,OAAO;GACPD,YAAYK,MAAM;EACpB;CACF,GACA,EAAEC,eAAenC,EAAEoC,gBAAgB,CACrC;CAqCA,MAAMf,eAAe5E,SACnBuD,GACAd,UACAmD;EAtCAC,OAAOC,SAAiB;GACtB,IAAI,CAACT,MAAM;GACX,IACEC,sBACAJ,WAAWa,gBAAgB,QAC3Bb,WAAWa,eAAe,GAC1B;IACAV,OAAO;IACP,IAAI;KACFH,WAAWc,QAAQpF,UAAU;KAC7BsE,WAAWO,MAAM;IACnB,QAAQ,CACN;IAEFL,YAAYK,MAAM;IAClB;GACF;GACA,MAAMR,QAAQa,SAAS,OAAO,eAAe,SAASA,KAAI;GAC1D,IAAI;IACFZ,WAAWc,QAAQtF,QAAQG,OAAOoE,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,OACApC,MACAuB,WACAE,KACF;CACAG,aAAaR,cAAcQ,cAAc;CACzC,IAAI,CAACC,MAAMD,YAAYK,MAAM;CAC7B,OAAO;EACLnE;EACAsD;EACAC,4BAA4B;GAC1BS,qBAAqB;EACvB;CACF;AACF;AAEA,MAAMW,kBACJC,YACAC,UACa;CACbD,WAAWrB,qBAAqB;CAChC,OAAO,IAAIhC,SAASqD,WAAW5E,MAAM;EACnC0B,QAAQ;EACR7B,SAAS;GACP,gBAAgB;GAChB,GAAIgF,UAAU,QAAQ,GAAG1F,eAAe0F,MAAM;EAChD;CACF,CAAC;AACH;AAEA,MAAMC,YAAY,OAChB7C,GACAxC,YACsB;CACtB,MAAMsF,aAAa,MAAM/C,UAAUC,GAAGL,UAAUnC,OAAO,CAAC;CACxD,IAAI,aAAasF,YAAY,OAAOA,WAAW5C;CAC/C,MAAM6C,SAAS3D,iBAAiB5B,OAAO;CACvC,IAAI,cAAcuF,QAAQ,OAAOA,OAAO1D;CACxC,MAAM2D,WAAW3C,0BACfL,GACA+C,OAAO7D,UACP4D,WAAW7C,IACb;CACA,IAAI+C,aAAa,MAAM,OAAOA;CAC9B,IAAI7G,kBAAkB6D,CAAC,GAAG,OAAOI,wBAAwB;CACzD,MAAMoB,YAAYzE,mBAAmBS,QAAQI,SAASoC,EAAEiD,aAAa,CACnEjD,EAAEkD,QAAQ,CACX;CACD,IAAI,SAAS1B,WACX,OAAOlC,SAASC,KAAKiC,WAAW,EAAE/B,QAAQ+B,UAAU2B,IAAI1D,OAAO,CAAC;CAClE,MAAMkD,aAAapB,UAAUvB,GAAG+C,OAAO7D,UAAU4D,WAAW7C,MAAMuB,SAAS;CAC3E,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,OACjBrD,GACAxC,YACsB;CACtB,MAAMuF,SAAS3D,iBAAiB5B,OAAO;CACvC,IAAI,cAAcuF,QAAQ,OAAOA,OAAO1D;CACxC,MAAMiE,MAAM,MAAM/F,cAAcC,OAAO;CACvC,IAAI8F,QAAQ,MACV,OAAOhE,SAASC,KAAK,EAAEC,QAAQ,uBAAuB,GAAG,EAAEC,QAAQ,IAAI,CAAC;CAE1E,IAAI1B;CACJ,IAAI;EACFA,OAAOuF,IAAIC,KAAK,IAAIC,KAAKC,MAAMH,GAAG,IAAI;CACxC,QAAQ;EACN,OAAOhE,SAASC,KAAK,EAAEC,QAAQ,oBAAoB,GAAG,EAAEC,QAAQ,IAAI,CAAC;CACvE;CACA,IAAIiC;CACJ,IAAI;EACFA,QAAQ3D,SAAS,QAAQ,CAACuF,IAAIC,KAAK,IAAI,EAAEG,KAAK,CAAA,EAAG,IAAIlH,gBAAgBuB,IAAI;CAC3E,SAASoC,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EAER,OAAOb,SAASC,KAAK,EAAEC,QAAQW,MAAM0D,QAAQ,GAAG,EAAEpE,QAAQ,IAAI,CAAC;CACjE;CACA,MAAMqD,aAAa,MAAM/C,UAAUC,GAAGL,UAAUnC,OAAO,CAAC;CACxD,IAAI,aAAasF,YAAY,OAAOA,WAAW5C;CAC/C,MAAM8C,WAAW3C,0BACfL,GACA+C,OAAO7D,UACP4D,WAAW7C,IACb;CACA,IAAI+C,aAAa,MAAM,OAAOA;CAC9B,IAAI7G,kBAAkB6D,CAAC,GAAG,OAAOI,wBAAwB;CACzD,MAAMoB,YAAYzE,mBAAmBS,QAAQI,SAASoC,EAAEiD,aAAa,CACnEjD,EAAEkD,QAAQ,CACX;CACD,IAAI,SAAS1B,WACX,OAAOlC,SAASC,KAAKiC,WAAW,EAAE/B,QAAQ+B,UAAU2B,IAAI1D,OAAO,CAAC;CAClE,IAAIkD;CACJ,IAAI;EACFA,aAAapB,UACXvB,GACA+C,OAAO7D,UACP4D,WAAW7C,MACXuB,WACAE,KACF;CACF,SAASvB,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EACR,OAAOb,SAASC,KACd,EAAE4D,KAAK;GAAEzD,QAAQ;GAAkBmE,SAAS1D,MAAM0D;EAAQ,EAAE,GAC5D,EAAEpE,QAAQ,IAAI,CAChB;CACF;CACA,IAAIkD,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,OACpB9D,GACAxC,YACsB;CACtB,IAAIA,QAAQuG,WAAW,OAAO,OAAOlB,UAAU7C,GAAGxC,OAAO;CACzD,IAAIA,QAAQuG,WAAW,QAAQ,OAAOV,WAAWrD,GAAGxC,OAAO;CAC3D,OAAO,IAAI8B,SAAS,MAAM;EACxBG,QAAQ;EACR7B,SAAS,EAAEoG,OAAO,YAAY;CAChC,CAAC;AACH;AAEA,MAAMC,aACJjE,GACAd,UACAiE,QACG;CACH7G,MAAM0D,CAAC;CACP,KAAK,MAAMoD,QAAQ,CAAC,GAAGpD,EAAEmE,KAAK,GAAG;EAC/B,IAAIf,KAAKlE,aAAaA,UAAU;EAChCxC,OAAOsD,GAAGoD,MAAMI,KAAKY,UAAU,EAAEjB,IAAI,CAAC,CAAC;EACvC9G,UAAU2D,GAAGoD,IAAI;CACnB;AACF;AAEA,MAAMiB,qBACJrE,GACAd,UACAQ,WACG;CACHuE,UAAUjE,GAAGd,UAAU;EACrBQ,QAAQ;EACRmE,SAASnE;CACX,CAAC;CACD,OAAOJ,SAASC,KAAK,EAAEY,OAAOT,OAAO,GAAG,EAAED,QAAQ,IAAI,CAAC;AACzD;AAEA,MAAa6E,SAAS,OACpBtE,GACAxC,YACsB;CACtB,MAAMoF,QAAQpF,QAAQI,QAAQC,IAAIX,YAAY;CAE9C,MAAMqH,SACJ3B,UAAU,OACNpC,KAAAA,IACA,CAAC,GAAGR,EAAEmE,KAAK,CAAC,CAACK,MAAMpB,SAASA,KAAKtB,QAAQsB,KAAKR,UAAUA,KAAK;CACnE,IAAI5C,EAAEyE,YAAYzE,EAAE0E,aAAa,QAAQH,WAAW/D,KAAAA,GAClD,OAAOlB,SAASC,KAAK,EAAEY,OAAO,cAAc,GAAG,EAAEV,QAAQ,IAAI,CAAC;CAEhE,MAAMP,WAAWqF,OAAOrF;CACxB,MAAMoE,MAAM,MAAM/F,cAAcC,OAAO;CACvC,IAAI8F,QAAQ,MACV,OAAOhE,SAASC,KAAK,EAAEY,OAAO,uBAAuB,GAAG,EAAEV,QAAQ,IAAI,CAAC;CAEzE,IAAIiC;CACJ,IAAI;EACFA,QAAQnF,WAAW+G,GAAG;CACxB,SAASnD,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EAER,OAAOkE,kBAAkBrE,GAAGd,UAAUiB,MAAM0D,OAAO;CACrD;CACA,IAAI,CAACU,OAAOzC,QAAQ9B,EAAEyE,YAAYzE,EAAE0E,aAAa,MAC/C,OAAOpF,SAASC,KAAK,EAAEY,OAAO,cAAc,GAAG,EAAEV,QAAQ,IAAI,CAAC;CAEhE,IAAIkF;CACJ,IAAI;EACFA,YAAYzI,WAAW8D,GAAGuE,QAAQ7C,KAAK;CACzC,SAASvB,OAAO;EACd,IAAI,EAAEA,iBAAiBwD,UAAUxD,MAAMyD,SAAS,sBAC9C,MAAMzD;EACR,OAAOkE,kBAAkBrE,GAAGd,UAAUiB,MAAM0D,OAAO;CACrD;CACA,IAAIc,UAAUE,SAAS,WAAW;EAChC,MAAMC,QAAQH,UAAUI,IAAIA,IAAID;EAChC,OAAOxF,SAASC,KAAKoF,UAAUI,KAAK;GAClCtF,QAAQqF,UAAUtE,KAAAA,IAAY,MAAM;GACpC,GAAIsE,UAAUtE,KAAAA,KAAa,EACzB5C,SAAS,EAAE,eAAemD,OAAOiE,KAAKC,KAAKH,QAAQ,GAAI,CAAC,EAAE,EAC5D;EACF,CAAC;CACH;CACA,OAAOxF,SAASC,KAAK,CAAC,CAAC;AACzB"}
|
|
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":"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"}
|
package/dist/host/socket.d.ts
CHANGED
|
@@ -1,168 +1,174 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
declare const
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
98
|
-
|
|
90
|
+
seq: number;
|
|
91
|
+
method: string;
|
|
92
|
+
params: unknown;
|
|
93
|
+
meta?: unknown;
|
|
99
94
|
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
138
|
-
declare const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
145
|
-
syn: {
|
|
150
|
+
type: "refused";
|
|
146
151
|
syn: {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
158
|
-
|
|
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
|
-
|
|
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","
|
|
1
|
+
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/host/socket.ts"],"names":[],"mappings":"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"}
|