statewire 0.17.0 → 0.17.2
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/connection.js +3 -2
- package/dist/client/connection.js.map +1 -1
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +38 -6
- package/dist/client/session.js.map +1 -1
- package/dist/document.d.ts +25 -0
- package/dist/document.d.ts.map +1 -0
- package/dist/document.js +88 -0
- package/dist/document.js.map +1 -0
- package/dist/host/draft.js +1 -1
- package/dist/host/socket.d.ts +2 -2
- package/dist/host/socket.d.ts.map +1 -1
- package/dist/host/socket.js +5 -5
- package/dist/host/socket.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/statewire.d.ts +2 -0
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js.map +1 -1
- package/dist/wire/documents.js +3 -3
- package/dist/wire/documents.js.map +1 -1
- package/dist/wire/meta.d.ts +3 -18
- package/dist/wire/meta.d.ts.map +1 -1
- package/dist/wire/meta.js +8 -57
- package/dist/wire/meta.js.map +1 -1
- package/dist/wire/ops.js +1 -1
- package/package.json +1 -1
- package/src/client/session.ts +35 -9
- package/src/document.ts +185 -0
- package/src/host/socket.ts +8 -7
- package/src/index.ts +2 -0
- package/src/statewire.ts +6 -1
- package/src/wire/meta.ts +11 -94
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { reviveDocumentValue } from "../document.js";
|
|
1
2
|
import { negotiationHeaders, parseNegotiation, validateSelection } from "../wire/protocol.js";
|
|
2
|
-
import { reviveOps
|
|
3
|
+
import { reviveOps } from "../wire/meta.js";
|
|
3
4
|
import { backoff, timing } from "./timing.js";
|
|
4
5
|
import { useEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
|
|
5
6
|
import { flushTapSync } from "@assistant-ui/tap";
|
|
@@ -192,7 +193,7 @@ const deliverEnvelope = (c, env) => {
|
|
|
192
193
|
const settleFin = (c, fin) => {
|
|
193
194
|
const finish = fin.meta === void 0 ? fin : {
|
|
194
195
|
...fin,
|
|
195
|
-
payload:
|
|
196
|
+
payload: reviveDocumentValue(fin.payload, fin.meta)
|
|
196
197
|
};
|
|
197
198
|
releaseHeld(c);
|
|
198
199
|
c.retryAt = Date.now() + (finish.retry ?? 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.js","names":["negotiationHeaders","validateSelection","parseNegotiation","StatewireProtocol","useEffect","useRef","useState","flushTapSync","reviveOps","reviveValue","backoff","timing","ConnectionState","RemoteLink","StatewireFrame","StatewireRemoteProps","StatewireSubmitResult","StatewireClient","StatewireHost","Episode","cause","message","code","TERMINAL","const","StatewireCmd","seq","type","payload","meta","dur","StatewireSyn","version","protocols","Selection","ctxSeq","record","id","idle","retry","StatewireEnvelope","ops","cmd","next","syn","fin","Fin","Gate","latched","wake","newGate","undefined","takeGate","g","was","waitGate","timeoutMs","Promise","resolve","timer","setTimeout","clearTimeout","openGate","AttemptOutcome","Conn","negotiation","Options","connection","Connection","parked","lease","attempt","authDenials","authStale","liveAt","retryAt","error","ConnectionError","episode","awaitingHello","held","gate","abort","AbortController","lifetime","ctx","onError","onChange","attemptOnce","notify","reconnect","degradedOf","state","status","reason","sameState","a","b","nextRetryAt","lastError","setStatus","c","degraded","protocolError","Error","isObject","value","Record","Array","isArray","isNonnegativeSafeInteger","Number","isSafeInteger","isPositiveSafeInteger","validateOptionalString","field","validateSynScalars","validateRefusalSyn","validateCmd","validateFin","validateEnvelope","entry","releaseHeld","length","onCmds","cmdsOf","env","snapshotOf","helloSynOf","handleHello","onHello","onIdle","Date","now","warnedUnknownSynFact","warnUnknownSynFact","console","warn","deliverSyn","onRefusal","Object","keys","deliverEnvelope","onOps","cmds","push","settleFin","finish","denial","terminal","report","assign","onFinish","handleEnvelope","dialing","scheduleRetry","failure","immediate","backoffResetMs","delay","Math","max","reconnectConn","run","alive","outcome","signal","aborted","SyntaxError","test","onDetach","includes","unsupportedVersion","resolveHeaders","headers","HeadersOption","staleAuth","Headers","attachFrame","resolved","name","entries","has","set","lanes","takeAttachLanes","body","JSON","stringify","fromEntries","useLink","props","url","isNew","send","frame","latest","current","setConnection","conn","link","protocol","wireVersion","applicationProtocols","classify","timeout","AbortSignal"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import {\n negotiationHeaders,\n validateSelection,\n parseNegotiation,\n} from \"../wire/protocol\";\nimport type { StatewireProtocol } from \"../wire/protocol\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveValue } from \"../wire/meta\";\nimport { backoff, timing } from \"./timing\";\nimport type {\n ConnectionState,\n RemoteLink,\n StatewireFrame,\n StatewireRemoteProps,\n StatewireSubmitResult,\n} from \"../transports/sse\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\n\nexport type Episode = {\n cause: \"dropped\" | \"reconnect\" | \"error\" | \"unauthorized\";\n message?: string;\n code?: string;\n};\n\n/** The terminal cmd verdict types; \"applied\" is the sole non-terminal type. */\nexport const TERMINAL = [\n \"result\",\n \"rejected\",\n \"failed\",\n \"crashed\",\n \"expired\",\n] as const;\n\nexport type StatewireCmd = {\n seq: number;\n type?: \"applied\" | (typeof TERMINAL)[number];\n code?: string;\n message?: string;\n payload?: unknown;\n meta?: unknown;\n /** Cumulative: resending through this seq will never be needed. */\n dur?: boolean;\n};\n\nexport type StatewireSyn = {\n version?: string;\n protocols?: StatewireProtocol.Selection[\"protocols\"];\n seq?: number;\n ctxSeq?: number;\n record?: \"ephemeral\";\n id?: string;\n idle?: boolean;\n retry?: number;\n};\n\nexport type StatewireEnvelope = {\n ops?: unknown[];\n cmd?: StatewireCmd[];\n next?: true;\n idle?: boolean;\n syn?: StatewireSyn;\n fin?: StatewireHost.Fin;\n};\n\nexport type Gate = { latched: boolean; wake: (() => void) | undefined };\n\nconst newGate = (): Gate => ({ latched: false, wake: undefined });\n\nconst takeGate = (g: Gate) => {\n const was = g.latched;\n g.latched = false;\n return was;\n};\n\nconst waitGate = (g: Gate, timeoutMs?: number) => {\n if (g.latched) {\n g.latched = false;\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n g.wake = undefined;\n resolve();\n }, timeoutMs);\n g.wake = () => {\n clearTimeout(timer);\n g.wake = undefined;\n resolve();\n };\n });\n};\n\nconst openGate = (g: Gate) => {\n if (g.wake) g.wake();\n else g.latched = true;\n};\n\nexport type AttemptOutcome = \"stop\" | \"reattach\" | \"ended\" | \"idle\";\n\nexport type Conn = {\n negotiation?: StatewireProtocol.Options;\n connection: StatewireClient.Connection;\n parked: boolean;\n lease: string | null;\n attempt: number;\n authDenials: number;\n authStale: boolean;\n liveAt: number | null;\n retryAt: number;\n error: StatewireClient.ConnectionError | undefined;\n episode: Episode | null;\n awaitingHello: boolean;\n held: StatewireCmd[];\n gate: Gate;\n abort: AbortController | null;\n lifetime: AbortController | null;\n ctx: StatewireRemoteProps;\n onError: (error: StatewireClient.ConnectionError) => void;\n onChange: (connection: StatewireClient.Connection) => void;\n attemptOnce: (abort: AbortController) => Promise<AttemptOutcome>;\n notify: (connection: StatewireClient.Connection) => void;\n reconnect: () => void;\n};\n\nexport const degradedOf = (state: ConnectionState): boolean =>\n (state.status === \"connecting\" && state.attempt > 0) ||\n (state.status === \"disconnected\" &&\n state.reason !== \"idle\" &&\n state.reason !== \"deferred\");\n\nconst sameState = (a: ConnectionState, b: ConnectionState): boolean => {\n if (a.status !== b.status) return false;\n if (a.status === \"connecting\" && b.status === \"connecting\") {\n return (\n a.attempt === b.attempt &&\n a.cause === b.cause &&\n a.code === b.code &&\n a.nextRetryAt === b.nextRetryAt &&\n a.lastError === b.lastError\n );\n }\n if (a.status === \"disconnected\" && b.status === \"disconnected\") {\n return a.reason === b.reason;\n }\n return true;\n};\n\nconst setStatus = (c: Conn, next: ConnectionState) => {\n if (sameState(next, c.connection) && c.connection.error === c.error) return;\n c.connection = {\n ...next,\n ...(c.error === undefined ? {} : { error: c.error }),\n reconnect: c.reconnect,\n degraded: degradedOf(next),\n };\n c.notify(c.connection);\n c.onChange(c.connection);\n};\n\nconst protocolError = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isNonnegativeSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) >= 0;\n\nconst isPositiveSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) > 0;\n\nconst validateOptionalString = (value: unknown, field: string): void => {\n if (value !== undefined && typeof value !== \"string\") {\n protocolError(`${field} must be a string`);\n }\n};\n\nconst validateSynScalars = (syn: Record<string, unknown>) => {\n if (syn[\"seq\"] !== undefined && !isNonnegativeSafeInteger(syn[\"seq\"])) {\n protocolError(\"syn.seq must be a nonnegative safe integer\");\n }\n if (syn[\"ctxSeq\"] !== undefined && !isNonnegativeSafeInteger(syn[\"ctxSeq\"])) {\n protocolError(\"syn.ctxSeq must be a nonnegative safe integer\");\n }\n if (syn[\"retry\"] !== undefined && !isNonnegativeSafeInteger(syn[\"retry\"])) {\n protocolError(\"syn.retry must be a nonnegative safe integer\");\n }\n validateOptionalString(syn[\"id\"], \"syn.id\");\n if (syn[\"idle\"] !== undefined && typeof syn[\"idle\"] !== \"boolean\") {\n protocolError(\"syn.idle must be a boolean\");\n }\n validateOptionalString(syn[\"record\"], \"syn.record\");\n};\n\nexport const validateRefusalSyn = (value: unknown): StatewireSyn => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value);\n if (\n value[\"id\"] !== undefined ||\n value[\"idle\"] !== undefined ||\n value[\"record\"] !== undefined\n ) {\n protocolError(\"invalid refusal syn\");\n }\n if (\n value[\"seq\"] === undefined &&\n value[\"ctxSeq\"] === undefined &&\n value[\"retry\"] === undefined\n ) {\n protocolError(\"refusal syn has no watermarks or retry\");\n }\n return value as StatewireSyn;\n};\n\nconst validateCmd = (value: unknown): value is StatewireCmd => {\n if (!isObject(value)) return protocolError(\"cmd entry must be an object\");\n if (!isPositiveSafeInteger(value[\"seq\"])) {\n protocolError(\"cmd.seq must be a positive safe integer\");\n }\n validateOptionalString(value[\"type\"], \"cmd.type\");\n validateOptionalString(value[\"code\"], \"cmd.code\");\n validateOptionalString(value[\"message\"], \"cmd.message\");\n if (value[\"dur\"] !== undefined && value[\"dur\"] !== true) {\n protocolError(\"cmd.dur must be true\");\n }\n return true;\n};\n\nconst validateFin = (value: unknown): value is StatewireHost.Fin => {\n if (!isObject(value)) return protocolError(\"fin must be an object\");\n if (typeof value[\"reason\"] !== \"string\") {\n protocolError(\"fin.reason must be a string\");\n }\n validateOptionalString(value[\"message\"], \"fin.message\");\n validateOptionalString(value[\"code\"], \"fin.code\");\n if (\n value[\"status\"] !== undefined &&\n !isNonnegativeSafeInteger(value[\"status\"])\n )\n protocolError(\"fin.status must be a nonnegative safe integer\");\n if (value[\"retry\"] !== undefined && !isNonnegativeSafeInteger(value[\"retry\"]))\n protocolError(\"fin.retry must be a nonnegative safe integer\");\n return true;\n};\n\nconst validateEnvelope = (value: unknown): StatewireEnvelope => {\n if (!isObject(value)) return protocolError(\"packet must be an object\");\n if (value[\"ops\"] !== undefined && !Array.isArray(value[\"ops\"])) {\n protocolError(\"ops must be an array\");\n }\n if (value[\"cmd\"] !== undefined) {\n const cmd = value[\"cmd\"];\n if (!Array.isArray(cmd)) return protocolError(\"cmd must be an array\");\n for (const entry of cmd) validateCmd(entry);\n }\n if (value[\"idle\"] !== undefined && typeof value[\"idle\"] !== \"boolean\") {\n protocolError(\"idle must be a boolean\");\n }\n if (value[\"next\"] !== undefined) {\n if (value[\"next\"] !== true) protocolError(\"next must be true\");\n if (\n value[\"cmd\"] === undefined ||\n value[\"ops\"] !== undefined ||\n value[\"fin\"] !== undefined\n ) {\n protocolError(\"next must ride a cmd-only packet\");\n }\n }\n if (value[\"fin\"] !== undefined) validateFin(value[\"fin\"]);\n return value as StatewireEnvelope;\n};\n\n// A hold's release delivers, never settles: fin and bare close both drain it.\nconst releaseHeld = (c: Conn) => {\n if (c.held.length === 0) return;\n const held = c.held;\n c.held = [];\n c.ctx.onCmds(held);\n};\n\nconst cmdsOf = (env: StatewireEnvelope): StatewireCmd[] => {\n if (env.cmd === undefined) return [];\n return env.cmd;\n};\n\nconst snapshotOf = (env: StatewireEnvelope): unknown[] => {\n const ops = env.ops;\n if (ops === undefined) return protocolError(\"hello missing snapshot\");\n return reviveOps(ops);\n};\n\nconst helloSynOf = (env: StatewireEnvelope): StatewireSyn => {\n if (!isObject(env.syn)) return protocolError(\"expected hello\");\n validateSynScalars(env.syn);\n if (env.syn[\"retry\"] !== undefined) {\n protocolError(\"hello syn cannot carry retry\");\n }\n return env.syn as StatewireSyn;\n};\n\nconst handleHello = (c: Conn, env: StatewireEnvelope) => {\n const syn = helloSynOf(env);\n if (c.negotiation !== undefined) validateSelection(syn, c.negotiation);\n const ops = snapshotOf(env);\n c.ctx.onHello({\n ops,\n syn,\n });\n c.ctx.onIdle(syn.idle ?? false);\n c.awaitingHello = false;\n c.error = undefined;\n c.liveAt = Date.now();\n c.authDenials = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\" });\n};\n\nlet warnedUnknownSynFact = false;\n\nconst warnUnknownSynFact = () => {\n if (warnedUnknownSynFact) return;\n warnedUnknownSynFact = true;\n console.warn(\"statewire: ignoring unknown syn fact\");\n};\n\nconst deliverSyn = (c: Conn, value: unknown) => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value);\n if (\n value[\"version\"] !== undefined ||\n value[\"protocols\"] !== undefined ||\n value[\"record\"] !== undefined ||\n value[\"idle\"] !== undefined\n ) {\n protocolError(\"invalid mid-stream syn\");\n }\n if (\n value[\"seq\"] !== undefined ||\n value[\"ctxSeq\"] !== undefined ||\n value[\"retry\"] !== undefined\n ) {\n c.ctx.onRefusal(validateRefusalSyn(value));\n return;\n }\n if (value[\"id\"] !== undefined) return;\n if (Object.keys(value).length === 0) {\n protocolError(\"invalid mid-stream syn\");\n }\n warnUnknownSynFact();\n};\n\nconst deliverEnvelope = (c: Conn, env: StatewireEnvelope) => {\n if (env.syn !== undefined) deliverSyn(c, env.syn);\n if (env.ops !== undefined) {\n const held = c.held;\n c.held = [];\n c.ctx.onOps({\n ops: reviveOps(env.ops),\n cmds: [...held, ...cmdsOf(env)],\n });\n } else if (env.cmd !== undefined) {\n const cmds = cmdsOf(env);\n if (env.next === true) c.held.push(...cmds);\n else c.ctx.onCmds(cmds);\n }\n if (typeof env.idle === \"boolean\") c.ctx.onIdle(env.idle);\n};\n\nexport const settleFin = (c: Conn, fin: StatewireHost.Fin): AttemptOutcome => {\n const finish =\n fin.meta === undefined\n ? fin\n : { ...fin, payload: reviveValue(fin.payload, fin.meta) };\n releaseHeld(c);\n c.retryAt = Date.now() + (finish.retry ?? 0);\n if (finish.reason === \"idle\") {\n c.ctx.onIdle(true);\n c.attempt = 0;\n c.episode = null;\n c.error = undefined;\n setStatus(c, { status: \"disconnected\", reason: \"idle\" });\n return \"idle\";\n }\n const denial = finish.reason === \"unauthorized\";\n const terminal =\n finish.reason === \"gone\" ||\n finish.reason === \"forbidden\" ||\n finish.reason === \"protocol-error\" ||\n (denial && c.authDenials > 0);\n if (denial) {\n c.authDenials += 1;\n c.authStale = true;\n }\n const report =\n finish.reason !== \"reconnect\" &&\n finish.reason !== \"gone\" &&\n (!denial || terminal);\n c.error = report\n ? Object.assign(new Error(finish.message ?? finish.reason), { fin: finish })\n : undefined;\n if (c.error) c.onError(c.error);\n if (!terminal) {\n c.episode = {\n cause:\n finish.reason === \"reconnect\"\n ? \"reconnect\"\n : denial\n ? \"unauthorized\"\n : \"error\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.code !== undefined && { code: finish.code }),\n };\n if (denial) openGate(c.gate);\n return \"reattach\";\n }\n c.ctx.onFinish(finish);\n setStatus(c, {\n status: \"disconnected\",\n reason: denial\n ? \"unauthorized\"\n : finish.reason === \"forbidden\"\n ? \"forbidden\"\n : finish.reason === \"protocol-error\"\n ? \"protocol-error\"\n : \"gone\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.payload !== undefined && { payload: finish.payload }),\n });\n return \"stop\";\n};\n\nexport const handleEnvelope = (\n c: Conn,\n value: unknown,\n): AttemptOutcome | null => {\n const env = validateEnvelope(value);\n if (c.awaitingHello) {\n if (env.fin !== undefined) return settleFin(c, env.fin);\n handleHello(c, env);\n return null;\n }\n deliverEnvelope(c, env);\n if (env.fin !== undefined) return settleFin(c, env.fin);\n if (c.connection.status !== \"connected\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\" });\n }\n return null;\n};\n\nconst dialing = (c: Conn) =>\n setStatus(c, { status: \"connecting\", attempt: c.attempt });\n\nconst scheduleRetry = (\n c: Conn,\n failure: string | undefined,\n immediate: boolean,\n) => {\n if (c.liveAt !== null && Date.now() - c.liveAt >= timing.backoffResetMs) {\n c.attempt = 0;\n }\n c.liveAt = null;\n c.attempt += 1;\n c.episode ??= { cause: \"dropped\" };\n const delay = Math.max(\n immediate ? 0 : backoff(c.attempt),\n c.retryAt - Date.now(),\n );\n setStatus(c, {\n status: \"connecting\",\n attempt: c.attempt,\n ...c.episode,\n nextRetryAt: Date.now() + delay,\n ...(failure !== undefined && { lastError: failure }),\n });\n return delay;\n};\n\nconst reconnectConn = (c: Conn) => {\n if (!c.lifetime) return;\n if (c.connection.status === \"disconnected\") {\n // A reconnect out of a park starts a fresh episode: first dial, attempt 0.\n c.attempt = 0;\n c.authDenials = 0;\n c.episode = null;\n flushTapSync(() => dialing(c));\n }\n openGate(c.gate);\n c.abort?.abort();\n};\n\nconst run = async (c: Conn, lifetime: AbortController, gate: Gate) => {\n const alive = () => c.lifetime === lifetime;\n if (c.parked) {\n await waitGate(gate);\n if (!alive()) return;\n c.parked = false;\n }\n while (alive()) {\n if (c.retryAt > Date.now()) {\n await waitGate(gate, c.retryAt - Date.now());\n continue;\n }\n // The dial is in flight: attempt alone, no backoff fields.\n flushTapSync(() => dialing(c));\n const abort = new AbortController();\n c.abort = abort;\n c.awaitingHello = true;\n c.held = [];\n let outcome: AttemptOutcome | undefined;\n let failure: string | undefined;\n try {\n outcome = await c.attemptOnce(abort);\n } catch (error) {\n if (!abort.signal.aborted) {\n if (\n error instanceof SyntaxError ||\n (error instanceof Error &&\n /^(statewire: protocol error:|Statewire cannot apply)/.test(\n error.message,\n ))\n ) {\n outcome = flushTapSync(() =>\n settleFin(c, { reason: \"protocol-error\", message: error.message }),\n );\n } else if (c.authStale) {\n outcome = flushTapSync(() =>\n settleFin(c, {\n reason: \"unauthorized\",\n message:\n error instanceof Error\n ? error.message\n : \"credential refresh failed\",\n }),\n );\n }\n failure =\n error instanceof Error && error.message ? error.message : \"network\";\n }\n }\n abort.abort();\n if (!alive()) return;\n flushTapSync(() => {\n releaseHeld(c);\n c.ctx.onDetach();\n });\n if (!alive()) return;\n if (\n c.connection.status === \"disconnected\" &&\n ![\"deferred\", \"idle\"].includes(c.connection.reason)\n )\n outcome = \"stop\";\n if (outcome === \"stop\" || outcome === \"idle\") {\n await waitGate(gate);\n continue;\n }\n const immediate = takeGate(gate);\n const delay = flushTapSync(() => scheduleRetry(c, failure, immediate));\n if (delay === 0) continue;\n await waitGate(gate, delay);\n }\n};\n\nexport const unsupportedVersion = (c: Conn, version: string): AttemptOutcome =>\n flushTapSync(() =>\n handleEnvelope(c, {\n fin: {\n reason: \"protocol-error\",\n message: `unsupported protocol version: ${version || '\"\"'}`,\n },\n }),\n ) ?? \"stop\";\n\nexport const resolveHeaders = async (\n headers: StatewireClient.HeadersOption | undefined,\n staleAuth: boolean,\n): Promise<Headers> =>\n new Headers(\n typeof headers === \"function\" ? await headers({ staleAuth }) : headers,\n );\n\n// The stale flag clears only once the resolver returns: a throwing refresh keeps it for the next attempt.\nexport const attachFrame = async (\n c: Conn,\n headers: StatewireClient.HeadersOption | undefined,\n) => {\n const resolved = await resolveHeaders(headers, c.authStale);\n for (const [name, value] of Object.entries(\n negotiationHeaders(c.negotiation ?? {}),\n )) {\n if (!resolved.has(name)) resolved.set(name, value);\n }\n c.negotiation = parseNegotiation(resolved);\n c.authStale = false;\n const lanes = flushTapSync(() => c.ctx.takeAttachLanes());\n return {\n headers: resolved,\n body: JSON.stringify({\n headers: Object.fromEntries(resolved),\n ...(lanes ?? {}),\n }),\n };\n};\n\nexport const useLink = (\n props: StatewireProtocol.Options & {\n url: string;\n isNew?: boolean | undefined;\n onChange?: ((connection: StatewireClient.Connection) => void) | undefined;\n onError?: ((error: StatewireClient.ConnectionError) => void) | undefined;\n ctx: StatewireRemoteProps;\n attemptOnce: (c: Conn, abort: AbortController) => Promise<AttemptOutcome>;\n send: (c: Conn, frame: StatewireFrame) => Promise<StatewireSubmitResult>;\n },\n): RemoteLink => {\n const latest = useRef(props);\n latest.current = props;\n const [, setConnection] = useState<StatewireClient.Connection | null>(null);\n const [c] = useState((): Conn => {\n const conn: Conn = {\n parked: props.isNew ?? false,\n lease: null,\n attempt: 0,\n authDenials: 0,\n authStale: false,\n liveAt: null,\n retryAt: 0,\n error: undefined,\n episode: null,\n awaitingHello: true,\n held: [],\n abort: null,\n gate: newGate(),\n lifetime: null,\n get ctx() {\n return latest.current.ctx;\n },\n onError: (error) => latest.current.onError?.(error),\n onChange: (connection) => latest.current.onChange?.(connection),\n attemptOnce: (abort) => {\n conn.negotiation = latest.current;\n return latest.current.attemptOnce(conn, abort);\n },\n notify: setConnection,\n reconnect: () => reconnectConn(conn),\n connection: {\n ...((props.isNew ?? false)\n ? { status: \"disconnected\", reason: \"deferred\" }\n : { status: \"connecting\", attempt: 0 }),\n degraded: false,\n reconnect: () => conn.reconnect(),\n },\n };\n return conn;\n });\n const [link] = useState(\n (): RemoteLink => ({\n get connection() {\n return c.connection;\n },\n get parked() {\n return c.parked;\n },\n send: (frame) => latest.current.send(c, frame),\n }),\n );\n\n const negotiation = JSON.stringify([\n props.protocol,\n props.wireVersion,\n props.applicationProtocols,\n ]);\n useEffect(() => {\n c.lease = null;\n c.attempt = 0;\n c.authDenials = 0;\n c.authStale = false;\n c.liveAt = null;\n c.retryAt = 0;\n c.episode = null;\n setStatus(\n c,\n c.parked\n ? { status: \"disconnected\", reason: \"deferred\" }\n : { status: \"connecting\", attempt: 0 },\n );\n const lifetime = new AbortController();\n c.lifetime = lifetime;\n c.gate = newGate();\n void run(c, lifetime, c.gate);\n return () => {\n c.abort?.abort();\n lifetime.abort();\n if (c.lifetime === lifetime) c.lifetime = null;\n openGate(c.gate);\n };\n }, [c, props.url, negotiation]);\n\n return link;\n};\n\nexport const classify = (timeout: AbortSignal) =>\n new Error(timeout.aborted ? \"timeout\" : \"network\");\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"connection.js","names":["negotiationHeaders","validateSelection","parseNegotiation","StatewireProtocol","useEffect","useRef","useState","flushTapSync","reviveOps","reviveValue","backoff","timing","ConnectionState","RemoteLink","StatewireFrame","StatewireRemoteProps","StatewireSubmitResult","StatewireClient","StatewireHost","Episode","cause","message","code","TERMINAL","const","StatewireCmd","seq","type","payload","meta","dur","StatewireSyn","version","protocols","Selection","ctxSeq","record","id","idle","retry","StatewireEnvelope","ops","cmd","next","syn","fin","Fin","Gate","latched","wake","newGate","undefined","takeGate","g","was","waitGate","timeoutMs","Promise","resolve","timer","setTimeout","clearTimeout","openGate","AttemptOutcome","Conn","negotiation","Options","connection","Connection","parked","lease","attempt","authDenials","authStale","liveAt","retryAt","error","ConnectionError","episode","awaitingHello","held","gate","abort","AbortController","lifetime","ctx","onError","onChange","attemptOnce","notify","reconnect","degradedOf","state","status","reason","sameState","a","b","nextRetryAt","lastError","setStatus","c","degraded","protocolError","Error","isObject","value","Record","Array","isArray","isNonnegativeSafeInteger","Number","isSafeInteger","isPositiveSafeInteger","validateOptionalString","field","validateSynScalars","validateRefusalSyn","validateCmd","validateFin","validateEnvelope","entry","releaseHeld","length","onCmds","cmdsOf","env","snapshotOf","helloSynOf","handleHello","onHello","onIdle","Date","now","warnedUnknownSynFact","warnUnknownSynFact","console","warn","deliverSyn","onRefusal","Object","keys","deliverEnvelope","onOps","cmds","push","settleFin","finish","denial","terminal","report","assign","onFinish","handleEnvelope","dialing","scheduleRetry","failure","immediate","backoffResetMs","delay","Math","max","reconnectConn","run","alive","outcome","signal","aborted","SyntaxError","test","onDetach","includes","unsupportedVersion","resolveHeaders","headers","HeadersOption","staleAuth","Headers","attachFrame","resolved","name","entries","has","set","lanes","takeAttachLanes","body","JSON","stringify","fromEntries","useLink","props","url","isNew","send","frame","latest","current","setConnection","conn","link","protocol","wireVersion","applicationProtocols","classify","timeout","AbortSignal"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import {\n negotiationHeaders,\n validateSelection,\n parseNegotiation,\n} from \"../wire/protocol\";\nimport type { StatewireProtocol } from \"../wire/protocol\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveValue } from \"../wire/meta\";\nimport { backoff, timing } from \"./timing\";\nimport type {\n ConnectionState,\n RemoteLink,\n StatewireFrame,\n StatewireRemoteProps,\n StatewireSubmitResult,\n} from \"../transports/sse\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\n\nexport type Episode = {\n cause: \"dropped\" | \"reconnect\" | \"error\" | \"unauthorized\";\n message?: string;\n code?: string;\n};\n\n/** The terminal cmd verdict types; \"applied\" is the sole non-terminal type. */\nexport const TERMINAL = [\n \"result\",\n \"rejected\",\n \"failed\",\n \"crashed\",\n \"expired\",\n] as const;\n\nexport type StatewireCmd = {\n seq: number;\n type?: \"applied\" | (typeof TERMINAL)[number];\n code?: string;\n message?: string;\n payload?: unknown;\n meta?: unknown;\n /** Cumulative: resending through this seq will never be needed. */\n dur?: boolean;\n};\n\nexport type StatewireSyn = {\n version?: string;\n protocols?: StatewireProtocol.Selection[\"protocols\"];\n seq?: number;\n ctxSeq?: number;\n record?: \"ephemeral\";\n id?: string;\n idle?: boolean;\n retry?: number;\n};\n\nexport type StatewireEnvelope = {\n ops?: unknown[];\n cmd?: StatewireCmd[];\n next?: true;\n idle?: boolean;\n syn?: StatewireSyn;\n fin?: StatewireHost.Fin;\n};\n\nexport type Gate = { latched: boolean; wake: (() => void) | undefined };\n\nconst newGate = (): Gate => ({ latched: false, wake: undefined });\n\nconst takeGate = (g: Gate) => {\n const was = g.latched;\n g.latched = false;\n return was;\n};\n\nconst waitGate = (g: Gate, timeoutMs?: number) => {\n if (g.latched) {\n g.latched = false;\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n g.wake = undefined;\n resolve();\n }, timeoutMs);\n g.wake = () => {\n clearTimeout(timer);\n g.wake = undefined;\n resolve();\n };\n });\n};\n\nconst openGate = (g: Gate) => {\n if (g.wake) g.wake();\n else g.latched = true;\n};\n\nexport type AttemptOutcome = \"stop\" | \"reattach\" | \"ended\" | \"idle\";\n\nexport type Conn = {\n negotiation?: StatewireProtocol.Options;\n connection: StatewireClient.Connection;\n parked: boolean;\n lease: string | null;\n attempt: number;\n authDenials: number;\n authStale: boolean;\n liveAt: number | null;\n retryAt: number;\n error: StatewireClient.ConnectionError | undefined;\n episode: Episode | null;\n awaitingHello: boolean;\n held: StatewireCmd[];\n gate: Gate;\n abort: AbortController | null;\n lifetime: AbortController | null;\n ctx: StatewireRemoteProps;\n onError: (error: StatewireClient.ConnectionError) => void;\n onChange: (connection: StatewireClient.Connection) => void;\n attemptOnce: (abort: AbortController) => Promise<AttemptOutcome>;\n notify: (connection: StatewireClient.Connection) => void;\n reconnect: () => void;\n};\n\nexport const degradedOf = (state: ConnectionState): boolean =>\n (state.status === \"connecting\" && state.attempt > 0) ||\n (state.status === \"disconnected\" &&\n state.reason !== \"idle\" &&\n state.reason !== \"deferred\");\n\nconst sameState = (a: ConnectionState, b: ConnectionState): boolean => {\n if (a.status !== b.status) return false;\n if (a.status === \"connecting\" && b.status === \"connecting\") {\n return (\n a.attempt === b.attempt &&\n a.cause === b.cause &&\n a.code === b.code &&\n a.nextRetryAt === b.nextRetryAt &&\n a.lastError === b.lastError\n );\n }\n if (a.status === \"disconnected\" && b.status === \"disconnected\") {\n return a.reason === b.reason;\n }\n return true;\n};\n\nconst setStatus = (c: Conn, next: ConnectionState) => {\n if (sameState(next, c.connection) && c.connection.error === c.error) return;\n c.connection = {\n ...next,\n ...(c.error === undefined ? {} : { error: c.error }),\n reconnect: c.reconnect,\n degraded: degradedOf(next),\n };\n c.notify(c.connection);\n c.onChange(c.connection);\n};\n\nconst protocolError = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isNonnegativeSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) >= 0;\n\nconst isPositiveSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) > 0;\n\nconst validateOptionalString = (value: unknown, field: string): void => {\n if (value !== undefined && typeof value !== \"string\") {\n protocolError(`${field} must be a string`);\n }\n};\n\nconst validateSynScalars = (syn: Record<string, unknown>) => {\n if (syn[\"seq\"] !== undefined && !isNonnegativeSafeInteger(syn[\"seq\"])) {\n protocolError(\"syn.seq must be a nonnegative safe integer\");\n }\n if (syn[\"ctxSeq\"] !== undefined && !isNonnegativeSafeInteger(syn[\"ctxSeq\"])) {\n protocolError(\"syn.ctxSeq must be a nonnegative safe integer\");\n }\n if (syn[\"retry\"] !== undefined && !isNonnegativeSafeInteger(syn[\"retry\"])) {\n protocolError(\"syn.retry must be a nonnegative safe integer\");\n }\n validateOptionalString(syn[\"id\"], \"syn.id\");\n if (syn[\"idle\"] !== undefined && typeof syn[\"idle\"] !== \"boolean\") {\n protocolError(\"syn.idle must be a boolean\");\n }\n validateOptionalString(syn[\"record\"], \"syn.record\");\n};\n\nexport const validateRefusalSyn = (value: unknown): StatewireSyn => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value);\n if (\n value[\"id\"] !== undefined ||\n value[\"idle\"] !== undefined ||\n value[\"record\"] !== undefined\n ) {\n protocolError(\"invalid refusal syn\");\n }\n if (\n value[\"seq\"] === undefined &&\n value[\"ctxSeq\"] === undefined &&\n value[\"retry\"] === undefined\n ) {\n protocolError(\"refusal syn has no watermarks or retry\");\n }\n return value as StatewireSyn;\n};\n\nconst validateCmd = (value: unknown): value is StatewireCmd => {\n if (!isObject(value)) return protocolError(\"cmd entry must be an object\");\n if (!isPositiveSafeInteger(value[\"seq\"])) {\n protocolError(\"cmd.seq must be a positive safe integer\");\n }\n validateOptionalString(value[\"type\"], \"cmd.type\");\n validateOptionalString(value[\"code\"], \"cmd.code\");\n validateOptionalString(value[\"message\"], \"cmd.message\");\n if (value[\"dur\"] !== undefined && value[\"dur\"] !== true) {\n protocolError(\"cmd.dur must be true\");\n }\n return true;\n};\n\nconst validateFin = (value: unknown): value is StatewireHost.Fin => {\n if (!isObject(value)) return protocolError(\"fin must be an object\");\n if (typeof value[\"reason\"] !== \"string\") {\n protocolError(\"fin.reason must be a string\");\n }\n validateOptionalString(value[\"message\"], \"fin.message\");\n validateOptionalString(value[\"code\"], \"fin.code\");\n if (\n value[\"status\"] !== undefined &&\n !isNonnegativeSafeInteger(value[\"status\"])\n )\n protocolError(\"fin.status must be a nonnegative safe integer\");\n if (value[\"retry\"] !== undefined && !isNonnegativeSafeInteger(value[\"retry\"]))\n protocolError(\"fin.retry must be a nonnegative safe integer\");\n return true;\n};\n\nconst validateEnvelope = (value: unknown): StatewireEnvelope => {\n if (!isObject(value)) return protocolError(\"packet must be an object\");\n if (value[\"ops\"] !== undefined && !Array.isArray(value[\"ops\"])) {\n protocolError(\"ops must be an array\");\n }\n if (value[\"cmd\"] !== undefined) {\n const cmd = value[\"cmd\"];\n if (!Array.isArray(cmd)) return protocolError(\"cmd must be an array\");\n for (const entry of cmd) validateCmd(entry);\n }\n if (value[\"idle\"] !== undefined && typeof value[\"idle\"] !== \"boolean\") {\n protocolError(\"idle must be a boolean\");\n }\n if (value[\"next\"] !== undefined) {\n if (value[\"next\"] !== true) protocolError(\"next must be true\");\n if (\n value[\"cmd\"] === undefined ||\n value[\"ops\"] !== undefined ||\n value[\"fin\"] !== undefined\n ) {\n protocolError(\"next must ride a cmd-only packet\");\n }\n }\n if (value[\"fin\"] !== undefined) validateFin(value[\"fin\"]);\n return value as StatewireEnvelope;\n};\n\n// A hold's release delivers, never settles: fin and bare close both drain it.\nconst releaseHeld = (c: Conn) => {\n if (c.held.length === 0) return;\n const held = c.held;\n c.held = [];\n c.ctx.onCmds(held);\n};\n\nconst cmdsOf = (env: StatewireEnvelope): StatewireCmd[] => {\n if (env.cmd === undefined) return [];\n return env.cmd;\n};\n\nconst snapshotOf = (env: StatewireEnvelope): unknown[] => {\n const ops = env.ops;\n if (ops === undefined) return protocolError(\"hello missing snapshot\");\n return reviveOps(ops);\n};\n\nconst helloSynOf = (env: StatewireEnvelope): StatewireSyn => {\n if (!isObject(env.syn)) return protocolError(\"expected hello\");\n validateSynScalars(env.syn);\n if (env.syn[\"retry\"] !== undefined) {\n protocolError(\"hello syn cannot carry retry\");\n }\n return env.syn as StatewireSyn;\n};\n\nconst handleHello = (c: Conn, env: StatewireEnvelope) => {\n const syn = helloSynOf(env);\n if (c.negotiation !== undefined) validateSelection(syn, c.negotiation);\n const ops = snapshotOf(env);\n c.ctx.onHello({\n ops,\n syn,\n });\n c.ctx.onIdle(syn.idle ?? false);\n c.awaitingHello = false;\n c.error = undefined;\n c.liveAt = Date.now();\n c.authDenials = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\" });\n};\n\nlet warnedUnknownSynFact = false;\n\nconst warnUnknownSynFact = () => {\n if (warnedUnknownSynFact) return;\n warnedUnknownSynFact = true;\n console.warn(\"statewire: ignoring unknown syn fact\");\n};\n\nconst deliverSyn = (c: Conn, value: unknown) => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value);\n if (\n value[\"version\"] !== undefined ||\n value[\"protocols\"] !== undefined ||\n value[\"record\"] !== undefined ||\n value[\"idle\"] !== undefined\n ) {\n protocolError(\"invalid mid-stream syn\");\n }\n if (\n value[\"seq\"] !== undefined ||\n value[\"ctxSeq\"] !== undefined ||\n value[\"retry\"] !== undefined\n ) {\n c.ctx.onRefusal(validateRefusalSyn(value));\n return;\n }\n if (value[\"id\"] !== undefined) return;\n if (Object.keys(value).length === 0) {\n protocolError(\"invalid mid-stream syn\");\n }\n warnUnknownSynFact();\n};\n\nconst deliverEnvelope = (c: Conn, env: StatewireEnvelope) => {\n if (env.syn !== undefined) deliverSyn(c, env.syn);\n if (env.ops !== undefined) {\n const held = c.held;\n c.held = [];\n c.ctx.onOps({\n ops: reviveOps(env.ops),\n cmds: [...held, ...cmdsOf(env)],\n });\n } else if (env.cmd !== undefined) {\n const cmds = cmdsOf(env);\n if (env.next === true) c.held.push(...cmds);\n else c.ctx.onCmds(cmds);\n }\n if (typeof env.idle === \"boolean\") c.ctx.onIdle(env.idle);\n};\n\nexport const settleFin = (c: Conn, fin: StatewireHost.Fin): AttemptOutcome => {\n const finish =\n fin.meta === undefined\n ? fin\n : { ...fin, payload: reviveValue(fin.payload, fin.meta) };\n releaseHeld(c);\n c.retryAt = Date.now() + (finish.retry ?? 0);\n if (finish.reason === \"idle\") {\n c.ctx.onIdle(true);\n c.attempt = 0;\n c.episode = null;\n c.error = undefined;\n setStatus(c, { status: \"disconnected\", reason: \"idle\" });\n return \"idle\";\n }\n const denial = finish.reason === \"unauthorized\";\n const terminal =\n finish.reason === \"gone\" ||\n finish.reason === \"forbidden\" ||\n finish.reason === \"protocol-error\" ||\n (denial && c.authDenials > 0);\n if (denial) {\n c.authDenials += 1;\n c.authStale = true;\n }\n const report =\n finish.reason !== \"reconnect\" &&\n finish.reason !== \"gone\" &&\n (!denial || terminal);\n c.error = report\n ? Object.assign(new Error(finish.message ?? finish.reason), { fin: finish })\n : undefined;\n if (c.error) c.onError(c.error);\n if (!terminal) {\n c.episode = {\n cause:\n finish.reason === \"reconnect\"\n ? \"reconnect\"\n : denial\n ? \"unauthorized\"\n : \"error\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.code !== undefined && { code: finish.code }),\n };\n if (denial) openGate(c.gate);\n return \"reattach\";\n }\n c.ctx.onFinish(finish);\n setStatus(c, {\n status: \"disconnected\",\n reason: denial\n ? \"unauthorized\"\n : finish.reason === \"forbidden\"\n ? \"forbidden\"\n : finish.reason === \"protocol-error\"\n ? \"protocol-error\"\n : \"gone\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.payload !== undefined && { payload: finish.payload }),\n });\n return \"stop\";\n};\n\nexport const handleEnvelope = (\n c: Conn,\n value: unknown,\n): AttemptOutcome | null => {\n const env = validateEnvelope(value);\n if (c.awaitingHello) {\n if (env.fin !== undefined) return settleFin(c, env.fin);\n handleHello(c, env);\n return null;\n }\n deliverEnvelope(c, env);\n if (env.fin !== undefined) return settleFin(c, env.fin);\n if (c.connection.status !== \"connected\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\" });\n }\n return null;\n};\n\nconst dialing = (c: Conn) =>\n setStatus(c, { status: \"connecting\", attempt: c.attempt });\n\nconst scheduleRetry = (\n c: Conn,\n failure: string | undefined,\n immediate: boolean,\n) => {\n if (c.liveAt !== null && Date.now() - c.liveAt >= timing.backoffResetMs) {\n c.attempt = 0;\n }\n c.liveAt = null;\n c.attempt += 1;\n c.episode ??= { cause: \"dropped\" };\n const delay = Math.max(\n immediate ? 0 : backoff(c.attempt),\n c.retryAt - Date.now(),\n );\n setStatus(c, {\n status: \"connecting\",\n attempt: c.attempt,\n ...c.episode,\n nextRetryAt: Date.now() + delay,\n ...(failure !== undefined && { lastError: failure }),\n });\n return delay;\n};\n\nconst reconnectConn = (c: Conn) => {\n if (!c.lifetime) return;\n if (c.connection.status === \"disconnected\") {\n // A reconnect out of a park starts a fresh episode: first dial, attempt 0.\n c.attempt = 0;\n c.authDenials = 0;\n c.episode = null;\n flushTapSync(() => dialing(c));\n }\n openGate(c.gate);\n c.abort?.abort();\n};\n\nconst run = async (c: Conn, lifetime: AbortController, gate: Gate) => {\n const alive = () => c.lifetime === lifetime;\n if (c.parked) {\n await waitGate(gate);\n if (!alive()) return;\n c.parked = false;\n }\n while (alive()) {\n if (c.retryAt > Date.now()) {\n await waitGate(gate, c.retryAt - Date.now());\n continue;\n }\n // The dial is in flight: attempt alone, no backoff fields.\n flushTapSync(() => dialing(c));\n const abort = new AbortController();\n c.abort = abort;\n c.awaitingHello = true;\n c.held = [];\n let outcome: AttemptOutcome | undefined;\n let failure: string | undefined;\n try {\n outcome = await c.attemptOnce(abort);\n } catch (error) {\n if (!abort.signal.aborted) {\n if (\n error instanceof SyntaxError ||\n (error instanceof Error &&\n /^(statewire: protocol error:|Statewire cannot apply)/.test(\n error.message,\n ))\n ) {\n outcome = flushTapSync(() =>\n settleFin(c, { reason: \"protocol-error\", message: error.message }),\n );\n } else if (c.authStale) {\n outcome = flushTapSync(() =>\n settleFin(c, {\n reason: \"unauthorized\",\n message:\n error instanceof Error\n ? error.message\n : \"credential refresh failed\",\n }),\n );\n }\n failure =\n error instanceof Error && error.message ? error.message : \"network\";\n }\n }\n abort.abort();\n if (!alive()) return;\n flushTapSync(() => {\n releaseHeld(c);\n c.ctx.onDetach();\n });\n if (!alive()) return;\n if (\n c.connection.status === \"disconnected\" &&\n ![\"deferred\", \"idle\"].includes(c.connection.reason)\n )\n outcome = \"stop\";\n if (outcome === \"stop\" || outcome === \"idle\") {\n await waitGate(gate);\n continue;\n }\n const immediate = takeGate(gate);\n const delay = flushTapSync(() => scheduleRetry(c, failure, immediate));\n if (delay === 0) continue;\n await waitGate(gate, delay);\n }\n};\n\nexport const unsupportedVersion = (c: Conn, version: string): AttemptOutcome =>\n flushTapSync(() =>\n handleEnvelope(c, {\n fin: {\n reason: \"protocol-error\",\n message: `unsupported protocol version: ${version || '\"\"'}`,\n },\n }),\n ) ?? \"stop\";\n\nexport const resolveHeaders = async (\n headers: StatewireClient.HeadersOption | undefined,\n staleAuth: boolean,\n): Promise<Headers> =>\n new Headers(\n typeof headers === \"function\" ? await headers({ staleAuth }) : headers,\n );\n\n// The stale flag clears only once the resolver returns: a throwing refresh keeps it for the next attempt.\nexport const attachFrame = async (\n c: Conn,\n headers: StatewireClient.HeadersOption | undefined,\n) => {\n const resolved = await resolveHeaders(headers, c.authStale);\n for (const [name, value] of Object.entries(\n negotiationHeaders(c.negotiation ?? {}),\n )) {\n if (!resolved.has(name)) resolved.set(name, value);\n }\n c.negotiation = parseNegotiation(resolved);\n c.authStale = false;\n const lanes = flushTapSync(() => c.ctx.takeAttachLanes());\n return {\n headers: resolved,\n body: JSON.stringify({\n headers: Object.fromEntries(resolved),\n ...(lanes ?? {}),\n }),\n };\n};\n\nexport const useLink = (\n props: StatewireProtocol.Options & {\n url: string;\n isNew?: boolean | undefined;\n onChange?: ((connection: StatewireClient.Connection) => void) | undefined;\n onError?: ((error: StatewireClient.ConnectionError) => void) | undefined;\n ctx: StatewireRemoteProps;\n attemptOnce: (c: Conn, abort: AbortController) => Promise<AttemptOutcome>;\n send: (c: Conn, frame: StatewireFrame) => Promise<StatewireSubmitResult>;\n },\n): RemoteLink => {\n const latest = useRef(props);\n latest.current = props;\n const [, setConnection] = useState<StatewireClient.Connection | null>(null);\n const [c] = useState((): Conn => {\n const conn: Conn = {\n parked: props.isNew ?? false,\n lease: null,\n attempt: 0,\n authDenials: 0,\n authStale: false,\n liveAt: null,\n retryAt: 0,\n error: undefined,\n episode: null,\n awaitingHello: true,\n held: [],\n abort: null,\n gate: newGate(),\n lifetime: null,\n get ctx() {\n return latest.current.ctx;\n },\n onError: (error) => latest.current.onError?.(error),\n onChange: (connection) => latest.current.onChange?.(connection),\n attemptOnce: (abort) => {\n conn.negotiation = latest.current;\n return latest.current.attemptOnce(conn, abort);\n },\n notify: setConnection,\n reconnect: () => reconnectConn(conn),\n connection: {\n ...((props.isNew ?? false)\n ? { status: \"disconnected\", reason: \"deferred\" }\n : { status: \"connecting\", attempt: 0 }),\n degraded: false,\n reconnect: () => conn.reconnect(),\n },\n };\n return conn;\n });\n const [link] = useState(\n (): RemoteLink => ({\n get connection() {\n return c.connection;\n },\n get parked() {\n return c.parked;\n },\n send: (frame) => latest.current.send(c, frame),\n }),\n );\n\n const negotiation = JSON.stringify([\n props.protocol,\n props.wireVersion,\n props.applicationProtocols,\n ]);\n useEffect(() => {\n c.lease = null;\n c.attempt = 0;\n c.authDenials = 0;\n c.authStale = false;\n c.liveAt = null;\n c.retryAt = 0;\n c.episode = null;\n setStatus(\n c,\n c.parked\n ? { status: \"disconnected\", reason: \"deferred\" }\n : { status: \"connecting\", attempt: 0 },\n );\n const lifetime = new AbortController();\n c.lifetime = lifetime;\n c.gate = newGate();\n void run(c, lifetime, c.gate);\n return () => {\n c.abort?.abort();\n lifetime.abort();\n if (c.lifetime === lifetime) c.lifetime = null;\n openGate(c.gate);\n };\n }, [c, props.url, negotiation]);\n\n return link;\n};\n\nexport const classify = (timeout: AbortSignal) =>\n new Error(timeout.aborted ? \"timeout\" : \"network\");\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":";;;;;;;;KAyCK;EACH;EACA,WAAW,YAAY,gBAAgB;EACvC;EACA;EACA;;KAGG;WACM;WACA,SAAS;WACT,KAAK;;EAEd;;EAEA;;EAEA;EACA,UAAU;EACV,SAAS,OAAO;;KAGb;WACM;WACA;EACT;;KAeG;KAEO,0BAA0B,kBAAkB;EACtD,eAAe,gBAAgB;EAC/B,gBAAgB,gBAAgB;EAChC;;KAGG;EACH,KAAK;EACL,QAAQ,gBAAgB;EACxB;;KAGG;EACH,SAAS;EACT,WAAW,kBAAkB;EAC7B,kBAAkB,mBAAmB;EACrC,QAAQ,gBAAgB;EACxB,KAAK;EACL;EACA,OAAO,gBAAgB;EACvB,eAAe,mBAAmB;EAClC,QAAQ;EACR;;EAEA;EACA;EACA;EACA;EACA;EACA,eAAe,gBAAgB;EAC/B;EACA;EACA,YAAY;EACZ;EACA,0BAA0B,qBAAqB;EAC/C;EACA,SAAS;EACT;EACA,mBAAmB;EACnB,WAAW,mBAAmB;EAC9B;EACA,SAAS;EACT,QAAQ,UAAU;EAClB,QAAQ;EACR;EACA;EACA;EACA,WAAW;EACX;EACA,WAAW;EACX;EACA,UAAU,mBAAmB,sBAAsB;;cAsIxC,iBACX,GAAG,qBACO,gBAAgB;cAkqBtB,eAAgB,GAAG,SAAS,WAAW;cAuKhC,gBACX,GAAG,SACH,OAAO,gBAAgB;cAYZ,cACX,GAAG,SACH,OAAO,gBAAgB,kBACtB;cA+IU,gBAAiB,GAAG,SAAS;cAGpC,aACJ,GAAG,SACH,OAAO,yBACP;cAuBW,iBAAkB,GAAG,YAAU,mBAAmB;cA+BlD,iBACX,GAAG,SACH,kBACA,gBACA,+BAA0B;cAyBf,sBACX,SAAS,4BACR"}
|
package/dist/client/session.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { encodeDocument, reviveDocumentValue } from "../document.js";
|
|
1
2
|
import { inRange, protocolOffers } from "../wire/protocol.js";
|
|
2
|
-
import { encodeParams,
|
|
3
|
+
import { encodeParams, reviveResponse } from "../wire/meta.js";
|
|
3
4
|
import { applyDocumentOps, findDocument, mainDocument, resolveDocumentKey } from "../wire/documents.js";
|
|
4
5
|
import { createMethodProxy } from "../util/methodProxy.js";
|
|
5
6
|
import { StatewireSendError } from "../types.js";
|
|
@@ -369,6 +370,36 @@ const publishIngested = (s) => {
|
|
|
369
370
|
wake(s);
|
|
370
371
|
};
|
|
371
372
|
const snapCtxClock = (s, ctxWm) => {
|
|
373
|
+
if (s.record.context?.recover === "version-1") {
|
|
374
|
+
const document = s.contextDocuments.documents.get(0);
|
|
375
|
+
if (s.contextDocuments.documents.size !== 1 || !document?.main) throw new Error("statewire: version-1 context recovery requires one main document at doc 0");
|
|
376
|
+
const encoded = encodeDocument(document.value);
|
|
377
|
+
const ops = [{
|
|
378
|
+
...ctxWm === 0 ? {
|
|
379
|
+
op: "mount",
|
|
380
|
+
protocol: document.protocol,
|
|
381
|
+
main: true
|
|
382
|
+
} : {
|
|
383
|
+
op: "replace",
|
|
384
|
+
path: []
|
|
385
|
+
},
|
|
386
|
+
...encoded
|
|
387
|
+
}];
|
|
388
|
+
s.ctxPending = [{
|
|
389
|
+
seq: ctxWm + 1,
|
|
390
|
+
ops,
|
|
391
|
+
posted: false
|
|
392
|
+
}];
|
|
393
|
+
setRecord(s, {
|
|
394
|
+
...s.record,
|
|
395
|
+
ctxNextSeq: ctxWm + 2,
|
|
396
|
+
context: {
|
|
397
|
+
ops: contextSnapshot(s.contextDocuments),
|
|
398
|
+
pending: s.ctxPending
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
372
403
|
if (!(s.ctxPending.every((c, i) => c.seq === ctxWm + 1 + i) && s.record.ctxNextSeq === ctxWm + s.ctxPending.length + 1)) {
|
|
373
404
|
if (ctxWm > 0) throw new Error("statewire: context history is missing; use a new client id");
|
|
374
405
|
setRecord(s, {
|
|
@@ -528,7 +559,7 @@ const takeAttachLanes = (s) => {
|
|
|
528
559
|
s.attachLaneSeqs = [/* @__PURE__ */ new Set(), /* @__PURE__ */ new Set()];
|
|
529
560
|
const wanted = s.lanesOnAttach;
|
|
530
561
|
s.lanesOnAttach = false;
|
|
531
|
-
if (!wanted || !s.sessionKnown) return null;
|
|
562
|
+
if (!wanted || !s.sessionKnown || s.record.context?.recover !== void 0) return null;
|
|
532
563
|
const lanes = buildLanes(s);
|
|
533
564
|
if (!lanes) return null;
|
|
534
565
|
s.attachLaneSeqs = [new Set(lanes.cmdEntries.map((p) => p.seq)), new Set(lanes.ctxEntries.map((c) => c.seq))];
|
|
@@ -693,7 +724,7 @@ const adoptStored = (s) => {
|
|
|
693
724
|
for (const { seq, ...command } of stored) {
|
|
694
725
|
const offers = protocolOffers(s.options);
|
|
695
726
|
if (offers !== "*" && !offers.some((offer) => offer.name === command.protocol)) continue;
|
|
696
|
-
const params = command.meta === void 0 ? command.params :
|
|
727
|
+
const params = command.meta === void 0 ? command.params : reviveDocumentValue([...command.params], command.meta);
|
|
697
728
|
const entry = {
|
|
698
729
|
seq,
|
|
699
730
|
command,
|
|
@@ -775,7 +806,7 @@ const retryFailed = (s, entry) => {
|
|
|
775
806
|
});
|
|
776
807
|
const found = findFailed(s, entry);
|
|
777
808
|
if (found === void 0) throw unknownFailed(entry);
|
|
778
|
-
const params = found.meta === void 0 ? found.params :
|
|
809
|
+
const params = found.meta === void 0 ? found.params : reviveDocumentValue([...found.params], found.meta);
|
|
779
810
|
const result = new Promise((resolve, reject) => {
|
|
780
811
|
const retry = () => {
|
|
781
812
|
if (!s.running) {
|
|
@@ -821,7 +852,7 @@ const retryFailed = (s, entry) => {
|
|
|
821
852
|
return result;
|
|
822
853
|
};
|
|
823
854
|
const contextSnapshot = (documents) => [...documents.documents].map(([doc, d]) => {
|
|
824
|
-
const encoded =
|
|
855
|
+
const encoded = encodeDocument(d.value);
|
|
825
856
|
return {
|
|
826
857
|
op: "mount",
|
|
827
858
|
...doc === 0 ? {} : { doc },
|
|
@@ -839,6 +870,7 @@ const persistContext = (s) => {
|
|
|
839
870
|
...s.record,
|
|
840
871
|
context: {
|
|
841
872
|
ops,
|
|
873
|
+
...s.record.context?.recover === void 0 ? {} : { recover: s.record.context.recover },
|
|
842
874
|
pending: s.ctxPending.map(({ seq, ops }) => ({
|
|
843
875
|
seq,
|
|
844
876
|
ops
|
|
@@ -888,7 +920,7 @@ const changeContext = (s, build) => {
|
|
|
888
920
|
const updateContext = (s, operations) => changeContext(s, () => operations);
|
|
889
921
|
const setContext = (s, value, protocol = s.options.protocol ?? "default") => {
|
|
890
922
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("statewire: context must be a plain object");
|
|
891
|
-
const encoded =
|
|
923
|
+
const encoded = encodeDocument(value);
|
|
892
924
|
changeContext(s, (documents) => {
|
|
893
925
|
const found = [...documents.documents].find(([, d]) => d.protocol === protocol && d.main);
|
|
894
926
|
const doc = found?.[0] ?? Math.max(-1, ...documents.documents.keys()) + 1;
|