statewire 0.9.2 → 0.10.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.
@@ -42,6 +42,7 @@ type Conn = {
42
42
  hasSnapshot: boolean;
43
43
  lease: string | null;
44
44
  attempt: number;
45
+ authDenials: number;
45
46
  liveAt: number | null;
46
47
  episode: Episode | null;
47
48
  awaitingHello: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","names":[],"sources":["../../src/client/connection.ts"],"mappings":";;;;KAQY;EACV;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA;EACA;;EAEA;;KAGU;EACV;EACA;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA,MAAM;EACN;EACA;EACA,MAAM;EACN,MAAM,cAAc;;KAGV;EAAS;EAAkB;;KAoC3B;KAEA;EACV,YAAY,gBAAgB;EAC5B;EACA;EACA;EACA;EACA,SAAS;EACT;EACA,MAAM;EACN,MAAM;EACN,OAAO;EACP,UAAU;EACV,KAAK;EACL,WAAW,YAAY,gBAAgB;EACvC,cAAc,OAAO,oBAAoB,QAAQ;EACjD,SAAS,YAAY,gBAAgB;EACrC;;cA8CW,qBAAsB,mBAAiB;cAyNvC,iBACX,GAAG,MACH,mBACC;cAuFU,mBAAoB;EAC/B;EACA,aAAa,YAAY,gBAAgB;EACzC,KAAK;EACL,cAAc,GAAG,MAAM,OAAO,oBAAoB,QAAQ;MACxD;cAoDS,WAAY,SAAS,gBAAW"}
1
+ {"version":3,"file":"connection.d.ts","names":[],"sources":["../../src/client/connection.ts"],"mappings":";;;;KAQY;EACV;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA;EACA;;EAEA;;KAGU;EACV;EACA;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA,MAAM;EACN;EACA;EACA,MAAM;EACN,MAAM,cAAc;;KAGV;EAAS;EAAkB;;KAoC3B;KAEA;EACV,YAAY,gBAAgB;EAC5B;EACA;EACA;EACA;EACA;EACA,SAAS;EACT;EACA,MAAM;EACN,MAAM;EACN,OAAO;EACP,UAAU;EACV,KAAK;EACL,WAAW,YAAY,gBAAgB;EACvC,cAAc,OAAO,oBAAoB,QAAQ;EACjD,SAAS,YAAY,gBAAgB;EACrC;;cA8CW,qBAAsB,mBAAiB;cAiOvC,iBACX,GAAG,MACH,mBACC;cAwFU,mBAAoB;EAC/B;EACA,aAAa,YAAY,gBAAgB;EACzC,KAAK;EACL,cAAc,GAAG,MAAM,OAAO,oBAAoB,QAAQ;MACxD;cAsDS,WAAY,SAAS,gBAAW"}
@@ -132,6 +132,7 @@ const handleHello = (c, env) => {
132
132
  c.awaitingHello = false;
133
133
  c.hasSnapshot = true;
134
134
  c.liveAt = Date.now();
135
+ c.authDenials = 0;
135
136
  c.episode = null;
136
137
  setStatus(c, { status: "live" });
137
138
  };
@@ -194,7 +195,9 @@ const settleFin = (c, fin) => {
194
195
  setStatus(c, { status: "idle" });
195
196
  return "idle";
196
197
  }
197
- const terminal = finish.reason === "gone" || finish.reason === "superseded";
198
+ const denial = finish.reason === "unauthorized";
199
+ const terminal = finish.reason === "gone" || finish.reason === "superseded" || denial && c.authDenials > 0;
200
+ if (denial) c.authDenials += 1;
198
201
  c.ctx.onFinish(terminal ? finish : {
199
202
  ...finish,
200
203
  reason: "error"
@@ -204,6 +207,7 @@ const settleFin = (c, fin) => {
204
207
  cause: transientCauseOf(finish.reason),
205
208
  ...finish.message !== void 0 && { message: finish.message }
206
209
  };
210
+ if (denial) openGate(c.gate);
207
211
  return "reattach";
208
212
  }
209
213
  setStatus(c, {
@@ -248,6 +252,7 @@ const reconnectConn = (c) => {
248
252
  if (!c.lifetime) return;
249
253
  if (c.connection.status === "gone" || c.connection.status === "idle") {
250
254
  c.attempt = 0;
255
+ c.authDenials = 0;
251
256
  c.episode = { cause: "dropped" };
252
257
  flushTapSync(() => {
253
258
  scheduleRetry(c, void 0, true);
@@ -296,6 +301,7 @@ const useStatewireConn = (props) => {
296
301
  hasSnapshot: false,
297
302
  lease: null,
298
303
  attempt: 0,
304
+ authDenials: 0,
299
305
  liveAt: null,
300
306
  episode: null,
301
307
  awaitingHello: true,
@@ -321,6 +327,7 @@ const useStatewireConn = (props) => {
321
327
  c.hasSnapshot = false;
322
328
  c.lease = null;
323
329
  c.attempt = 0;
330
+ c.authDenials = 0;
324
331
  c.liveAt = null;
325
332
  c.episode = null;
326
333
  if (c.connection.status !== "connecting") setStatus(c, { status: "connecting" });
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","names":["useEffect","useRef","useState","flushTapSync","reviveOps","reviveValue","backoff","timing","ConnectionState","StatewireRemoteProps","StatewireClient","StatewireHost","Episode","cause","message","StatewireCmd","seq","type","code","payload","meta","dur","StatewireSyn","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","connection","Connection","hasSnapshot","lease","attempt","liveAt","episode","awaitingHello","held","gate","abort","AbortController","lifetime","ctx","onChange","attemptOnce","notify","reconnect","setStatus","c","changed","status","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","op","Object","hasOwn","helloSynOf","handleHello","onHello","onIdle","Date","now","warnedUnknownSynFact","warnUnknownSynFact","console","warn","deliverSyn","onRefusal","keys","deliverEnvelope","onOps","cmds","push","transientCauseOf","reason","settleFin","finish","rest","terminal","onFinish","handleEnvelope","scheduleRetry","failure","immediate","backoffResetMs","delay","nextRetryAt","lastError","reconnectConn","run","alive","outcome","error","signal","aborted","onDetach","useStatewireConn","props","url","latest","current","setConnection","conn","classify","timeout","AbortSignal"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveValue } from \"../wire/meta\";\nimport { backoff, timing } from \"./timing\";\nimport type { ConnectionState, StatewireRemoteProps } from \"../transports/sse\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\n\nexport type Episode = {\n cause: \"dropped\" | \"evicted\" | \"error\" | \"unauthorized\";\n message?: string;\n};\n\nexport type StatewireCmd = {\n seq: number;\n type?: \"applied\" | \"result\" | \"rejected\" | \"failed\" | \"crashed\" | \"expired\";\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 seq?: number;\n ctxSeq?: number;\n record?: \"fresh\" | \"resumed\" | \"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 connection: StatewireClient.Connection;\n hasSnapshot: boolean;\n lease: string | null;\n attempt: number;\n liveAt: number | null;\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 onChange: (connection: StatewireClient.Connection) => void;\n attemptOnce: (abort: AbortController) => Promise<AttemptOutcome>;\n notify: (connection: StatewireClient.Connection) => void;\n reconnect: () => void;\n};\n\nconst setStatus = (c: Conn, next: ConnectionState) => {\n const changed = next.status !== c.connection.status;\n c.connection = { ...next, reconnect: c.reconnect };\n c.notify(c.connection);\n if (changed) 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 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 if (ops.length !== 1 || !isObject(ops[0])) {\n return protocolError(\"hello snapshot must be one root replace op\");\n }\n const op = ops[0];\n if (\n op[\"op\"] !== \"replace\" ||\n !Array.isArray(op[\"path\"]) ||\n op[\"path\"].length !== 0 ||\n !Object.hasOwn(op, \"value\")\n ) {\n return protocolError(\"hello snapshot must be one root replace op\");\n }\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 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.hasSnapshot = true;\n c.liveAt = Date.now();\n c.episode = null;\n setStatus(c, { status: \"live\" });\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 (value[\"record\"] !== undefined || value[\"idle\"] !== undefined) {\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\nconst transientCauseOf = (\n reason: StatewireHost.Fin[\"reason\"],\n): Episode[\"cause\"] => {\n switch (reason) {\n case \"evicted\":\n return \"evicted\";\n case \"error\":\n return \"error\";\n case \"unauthorized\":\n return \"unauthorized\";\n default:\n return \"error\";\n }\n};\n\nconst settleFin = (c: Conn, fin: StatewireHost.Fin): AttemptOutcome => {\n let finish = fin;\n if (finish.meta !== undefined) {\n const { meta, ...rest } = finish;\n finish = { ...rest, payload: reviveValue(rest.payload, meta) };\n }\n releaseHeld(c);\n if (finish.reason === \"idle\") {\n c.ctx.onIdle(true);\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"idle\" });\n return \"idle\";\n }\n const terminal = finish.reason === \"gone\" || finish.reason === \"superseded\";\n c.ctx.onFinish(terminal ? finish : { ...finish, reason: \"error\" });\n if (!terminal) {\n c.episode = {\n cause: transientCauseOf(finish.reason),\n ...(finish.message !== undefined && { message: finish.message }),\n };\n return \"reattach\";\n }\n setStatus(c, {\n status: \"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 !== \"live\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"live\" });\n }\n return null;\n};\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 = immediate ? 0 : backoff(c.attempt);\n setStatus(c, {\n status: \"reconnecting\",\n ...c.episode,\n attempt: c.attempt,\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 === \"gone\" || c.connection.status === \"idle\") {\n c.attempt = 0;\n c.episode = { cause: \"dropped\" };\n flushTapSync(() => {\n scheduleRetry(c, undefined, true);\n });\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 while (alive()) {\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 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 (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 useStatewireConn = (props: {\n url: string;\n onChange?: ((connection: StatewireClient.Connection) => void) | undefined;\n ctx: StatewireRemoteProps;\n attemptOnce: (c: Conn, abort: AbortController) => Promise<AttemptOutcome>;\n}): Conn => {\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 hasSnapshot: false,\n lease: null,\n attempt: 0,\n liveAt: null,\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 onChange: (connection) => latest.current.onChange?.(connection),\n attemptOnce: (abort) => latest.current.attemptOnce(conn, abort),\n notify: setConnection,\n reconnect: () => reconnectConn(conn),\n connection: { status: \"connecting\", reconnect: () => conn.reconnect() },\n };\n return conn;\n });\n\n useEffect(() => {\n c.hasSnapshot = false;\n c.lease = null;\n c.attempt = 0;\n c.liveAt = null;\n c.episode = null;\n if (c.connection.status !== \"connecting\") {\n setStatus(c, { status: \"connecting\" });\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]);\n\n return c;\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":["useEffect","useRef","useState","flushTapSync","reviveOps","reviveValue","backoff","timing","ConnectionState","StatewireRemoteProps","StatewireClient","StatewireHost","Episode","cause","message","StatewireCmd","seq","type","code","payload","meta","dur","StatewireSyn","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","connection","Connection","hasSnapshot","lease","attempt","authDenials","liveAt","episode","awaitingHello","held","gate","abort","AbortController","lifetime","ctx","onChange","attemptOnce","notify","reconnect","setStatus","c","changed","status","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","op","Object","hasOwn","helloSynOf","handleHello","onHello","onIdle","Date","now","warnedUnknownSynFact","warnUnknownSynFact","console","warn","deliverSyn","onRefusal","keys","deliverEnvelope","onOps","cmds","push","transientCauseOf","reason","settleFin","finish","rest","denial","terminal","onFinish","handleEnvelope","scheduleRetry","failure","immediate","backoffResetMs","delay","nextRetryAt","lastError","reconnectConn","run","alive","outcome","error","signal","aborted","onDetach","useStatewireConn","props","url","latest","current","setConnection","conn","classify","timeout","AbortSignal"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveValue } from \"../wire/meta\";\nimport { backoff, timing } from \"./timing\";\nimport type { ConnectionState, StatewireRemoteProps } from \"../transports/sse\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\n\nexport type Episode = {\n cause: \"dropped\" | \"evicted\" | \"error\" | \"unauthorized\";\n message?: string;\n};\n\nexport type StatewireCmd = {\n seq: number;\n type?: \"applied\" | \"result\" | \"rejected\" | \"failed\" | \"crashed\" | \"expired\";\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 seq?: number;\n ctxSeq?: number;\n record?: \"fresh\" | \"resumed\" | \"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 connection: StatewireClient.Connection;\n hasSnapshot: boolean;\n lease: string | null;\n attempt: number;\n authDenials: number;\n liveAt: number | null;\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 onChange: (connection: StatewireClient.Connection) => void;\n attemptOnce: (abort: AbortController) => Promise<AttemptOutcome>;\n notify: (connection: StatewireClient.Connection) => void;\n reconnect: () => void;\n};\n\nconst setStatus = (c: Conn, next: ConnectionState) => {\n const changed = next.status !== c.connection.status;\n c.connection = { ...next, reconnect: c.reconnect };\n c.notify(c.connection);\n if (changed) 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 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 if (ops.length !== 1 || !isObject(ops[0])) {\n return protocolError(\"hello snapshot must be one root replace op\");\n }\n const op = ops[0];\n if (\n op[\"op\"] !== \"replace\" ||\n !Array.isArray(op[\"path\"]) ||\n op[\"path\"].length !== 0 ||\n !Object.hasOwn(op, \"value\")\n ) {\n return protocolError(\"hello snapshot must be one root replace op\");\n }\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 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.hasSnapshot = true;\n c.liveAt = Date.now();\n c.authDenials = 0;\n c.episode = null;\n setStatus(c, { status: \"live\" });\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 (value[\"record\"] !== undefined || value[\"idle\"] !== undefined) {\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\nconst transientCauseOf = (\n reason: StatewireHost.Fin[\"reason\"],\n): Episode[\"cause\"] => {\n switch (reason) {\n case \"evicted\":\n return \"evicted\";\n case \"error\":\n return \"error\";\n case \"unauthorized\":\n return \"unauthorized\";\n default:\n return \"error\";\n }\n};\n\nconst settleFin = (c: Conn, fin: StatewireHost.Fin): AttemptOutcome => {\n let finish = fin;\n if (finish.meta !== undefined) {\n const { meta, ...rest } = finish;\n finish = { ...rest, payload: reviveValue(rest.payload, meta) };\n }\n releaseHeld(c);\n if (finish.reason === \"idle\") {\n c.ctx.onIdle(true);\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"idle\" });\n return \"idle\";\n }\n // An auth denial gets one immediate redial; a consecutive repeat parks as gone.\n const denial = finish.reason === \"unauthorized\";\n const terminal =\n finish.reason === \"gone\" ||\n finish.reason === \"superseded\" ||\n (denial && c.authDenials > 0);\n if (denial) c.authDenials += 1;\n c.ctx.onFinish(terminal ? finish : { ...finish, reason: \"error\" });\n if (!terminal) {\n c.episode = {\n cause: transientCauseOf(finish.reason),\n ...(finish.message !== undefined && { message: finish.message }),\n };\n if (denial) openGate(c.gate);\n return \"reattach\";\n }\n setStatus(c, {\n status: \"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 !== \"live\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"live\" });\n }\n return null;\n};\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 = immediate ? 0 : backoff(c.attempt);\n setStatus(c, {\n status: \"reconnecting\",\n ...c.episode,\n attempt: c.attempt,\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 === \"gone\" || c.connection.status === \"idle\") {\n c.attempt = 0;\n c.authDenials = 0;\n c.episode = { cause: \"dropped\" };\n flushTapSync(() => {\n scheduleRetry(c, undefined, true);\n });\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 while (alive()) {\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 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 (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 useStatewireConn = (props: {\n url: string;\n onChange?: ((connection: StatewireClient.Connection) => void) | undefined;\n ctx: StatewireRemoteProps;\n attemptOnce: (c: Conn, abort: AbortController) => Promise<AttemptOutcome>;\n}): Conn => {\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 hasSnapshot: false,\n lease: null,\n attempt: 0,\n authDenials: 0,\n liveAt: null,\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 onChange: (connection) => latest.current.onChange?.(connection),\n attemptOnce: (abort) => latest.current.attemptOnce(conn, abort),\n notify: setConnection,\n reconnect: () => reconnectConn(conn),\n connection: { status: \"connecting\", reconnect: () => conn.reconnect() },\n };\n return conn;\n });\n\n useEffect(() => {\n c.hasSnapshot = false;\n c.lease = null;\n c.attempt = 0;\n c.authDenials = 0;\n c.liveAt = null;\n c.episode = null;\n if (c.connection.status !== \"connecting\") {\n setStatus(c, { status: \"connecting\" });\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]);\n\n return c;\n};\n\nexport const classify = (timeout: AbortSignal) =>\n new Error(timeout.aborted ? \"timeout\" : \"network\");\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { StatewireSessionRecord, StatewireSessionStore, StatewireSessionStoreOptions } from "./sessionStore.js";
1
+ import { StatewireClient } from "../statewire.js";
2
2
  import { Statewire, StatewireSendError } from "../types.js";
3
3
  import { StatewirePath } from "../wire/ops.js";
4
4
  import { CommandsInvocation, CommandsListener } from "../host/host.js";
@@ -28,15 +28,18 @@ type CtxPending = {
28
28
  posted: boolean;
29
29
  };
30
30
  type AttachState = "detached" | "attached" | "finished";
31
- type StatewireSessionOptions = StatewireSessionStoreOptions & {
31
+ type StatewireSessionOptions = {
32
+ sessionStore?: StatewireClient.SessionStorage | undefined;
32
33
  onDone?: (() => void) | undefined;
33
34
  };
34
35
  type Session = {
35
- record: StatewireSessionRecord;
36
+ record: StatewireClient.SessionRecord;
36
37
  ctx: StatewireRemoteProps;
37
38
  recordPersisted: boolean;
38
- store: StatewireSessionStore;
39
+ store: StatewireClient.SessionStorage;
39
40
  ephemeral: boolean;
41
+ /** An ephemeral record died with its attach: the storage is off for good. */
42
+ deactivated: boolean;
40
43
  sessionKnown: boolean;
41
44
  durableSeq: number;
42
45
  resumeAt: number;
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":";;;;;;KAyBK;EACH;EACA;EACA;;KAGG;WACM;WACA,SAAS;WACT,KAAK;;EAEd;;EAEA;;EAEA;EACA,UAAU;EACV,SAAS,OAAO;;KAGb;WACM;WACA;EACT;;KAiBG;KAEO,0BAA0B;EACpC;;KAGG;EACH,QAAQ;EACR,KAAK;EACL;EACA,OAAO;EACP;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YAAY;EACZ;EACA,0BAA0B,qBAAqB;EAC/C;EACA,SAAS;EACT;EACA;EACA,SAAS;EACT,QAAQ,UAAU;EAClB,QAAQ;EACR;EACA;EACA;EACA,WAAW;EACX;EACA,WAAW;EACX;EACA,UAAU,mBAAmB,sBAAsB;;cAsd/C,eAAgB,GAAG,SAAS,WAAW;cA6DvC,aAAc,GAAG,SAAS,OAAO;cAoB1B,sBACX,SAAS,4BACR"}
1
+ {"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":";;;;;;KA4BK;EACH;EACA;EACA;;KAGG;WACM;WACA,SAAS;WACT,KAAK;;EAEd;;EAEA;;EAEA;EACA,UAAU;EACV,SAAS,OAAO;;KAGb;WACM;WACA;EACT;;KAiBG;KAEO;EACV,eAAe,gBAAgB;EAC/B;;KAGG;EACH,QAAQ,gBAAgB;EACxB,KAAK;EACL;EACA,OAAO,gBAAgB;EACvB;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,YAAY;EACZ;EACA,0BAA0B,qBAAqB;EAC/C;EACA,SAAS;EACT;EACA;EACA,SAAS;EACT,QAAQ,UAAU;EAClB,QAAQ;EACR;EACA;EACA;EACA,WAAW;EACX;EACA,WAAW;EACX;EACA,UAAU,mBAAmB,sBAAsB;;cA2e/C,eAAgB,GAAG,SAAS,WAAW;cA2FvC,aAAc,GAAG,SAAS,OAAO;cAoB1B,sBACX,SAAS,4BACR"}
@@ -2,11 +2,11 @@ import { applyOps } from "../wire/ops.js";
2
2
  import { createMethodProxy } from "../util/methodProxy.js";
3
3
  import { StatewireSendError } from "../types.js";
4
4
  import { bindCommandsHost } from "../host/host.js";
5
- import { encodeParams, encodeValue, reviveResponse } from "../wire/meta.js";
5
+ import { encodeParams, encodeValue, reviveResponse, reviveValue } from "../wire/meta.js";
6
+ import { SessionStorageContext, createMemorySessionStore } from "./sessionStore.js";
6
7
  import { backoff } from "./timing.js";
7
- import { createMemorySessionStore } from "./sessionStore.js";
8
8
  import { randomId } from "../util/randomId.js";
9
- import { useEffect, useState } from "@assistant-ui/tap/react-shim";
9
+ import { useContext, useEffect, useState } from "@assistant-ui/tap/react-shim";
10
10
  //#region src/client/session.ts
11
11
  const protocolError = (message) => {
12
12
  throw new Error(`statewire: protocol error: ${message}`);
@@ -41,7 +41,19 @@ const sleepUntilWake = (s, delayMs) => new Promise((resolve) => {
41
41
  });
42
42
  const setRecord = (s, record) => {
43
43
  s.record = record;
44
- if (!s.ephemeral) s.store.save(record);
44
+ if (!s.deactivated) s.store.save(record);
45
+ };
46
+ const backlog = (s) => s.pending.filter((p) => p.seq > s.durableSeq).map((p) => ({
47
+ seq: p.seq,
48
+ ...p.command
49
+ }));
50
+ const syncBacklog = (s) => {
51
+ const commands = backlog(s);
52
+ if (commands.length === s.record.commands.length && commands.every((c, i) => c.seq === s.record.commands[i].seq)) return;
53
+ setRecord(s, {
54
+ ...s.record,
55
+ commands
56
+ });
45
57
  };
46
58
  const setIdle = (s, level) => {
47
59
  if (level === s.idle) return;
@@ -134,7 +146,8 @@ const resetRecord = (s, clientId) => {
134
146
  setRecord(s, {
135
147
  clientId,
136
148
  nextSeq: 1,
137
- ctxNextSeq: 1
149
+ ctxNextSeq: 1,
150
+ commands: []
138
151
  });
139
152
  for (const old of survivors) {
140
153
  s.lifecycle?.onCovered?.(old.inv);
@@ -202,6 +215,7 @@ const handleCmd = (s, cmd) => {
202
215
  };
203
216
  const handleCmds = (s, cmds) => {
204
217
  for (const cmd of cmds) handleCmd(s, cmd);
218
+ syncBacklog(s);
205
219
  wake(s);
206
220
  };
207
221
  const ingestOps = (s, ops) => {
@@ -248,6 +262,7 @@ const handleHello = (s, { ops, syn }) => {
248
262
  s.frameFailures = 0;
249
263
  s.resumeAt = 0;
250
264
  s.ephemeral = record === "ephemeral";
265
+ if (s.ephemeral) s.deactivated = true;
251
266
  const [attachCmd, attachCtx] = s.attachLaneSeqs;
252
267
  s.attachLaneSeqs = [/* @__PURE__ */ new Set(), /* @__PURE__ */ new Set()];
253
268
  if (record === "resumed") {
@@ -256,6 +271,7 @@ const handleHello = (s, { ops, syn }) => {
256
271
  s.ctxPending = s.ctxPending.filter((c) => c.seq > ctxWatermark);
257
272
  for (const c of s.ctxPending) c.posted = attachCtx.has(c.seq);
258
273
  snapClocks(s, syn.seq ?? 0, ctxWatermark);
274
+ syncBacklog(s);
259
275
  } else resetRecord(s, s.record.clientId);
260
276
  s.sessionKnown = true;
261
277
  publishIngested(s);
@@ -264,6 +280,7 @@ const handleHello = (s, { ops, syn }) => {
264
280
  const handleOps = (s, { ops, cmds }) => {
265
281
  ingestOps(s, ops);
266
282
  for (const cmd of cmds) handleCmd(s, cmd);
283
+ syncBacklog(s);
267
284
  publishIngested(s);
268
285
  };
269
286
  const handleRefusal = (s, syn) => {
@@ -400,6 +417,7 @@ const start = (s) => {
400
417
  s.recordPersisted = true;
401
418
  s.store.save(s.record);
402
419
  }
420
+ resume(s);
403
421
  s.running = true;
404
422
  pump(s);
405
423
  };
@@ -415,10 +433,6 @@ const setTransport = (s, transport) => {
415
433
  };
416
434
  const enqueue = (s, command, params, resolve, reject) => {
417
435
  const seq = s.record.nextSeq;
418
- setRecord(s, {
419
- ...s.record,
420
- nextSeq: seq + 1
421
- });
422
436
  const entry = {
423
437
  seq,
424
438
  command,
@@ -436,9 +450,38 @@ const enqueue = (s, command, params, resolve, reject) => {
436
450
  reject
437
451
  };
438
452
  s.pending.push(entry);
453
+ setRecord(s, {
454
+ ...s.record,
455
+ nextSeq: seq + 1,
456
+ commands: backlog(s)
457
+ });
439
458
  s.lifecycle?.onStart(entry.inv);
440
459
  pump(s);
441
460
  };
461
+ const resume = (s) => {
462
+ const stored = [...s.record.commands].sort((a, b) => a.seq - b.seq);
463
+ for (const { seq, ...command } of stored) {
464
+ const params = command.meta === void 0 ? command.params : reviveValue([...command.params], command.meta);
465
+ const entry = {
466
+ seq,
467
+ command,
468
+ inv: {
469
+ method: command.method,
470
+ params,
471
+ ts: Date.now(),
472
+ seq,
473
+ clientId: s.record.clientId
474
+ },
475
+ attempted: true,
476
+ posted: false,
477
+ applied: false,
478
+ resolve: () => {},
479
+ reject: () => {}
480
+ };
481
+ s.pending.push(entry);
482
+ s.lifecycle?.onStart(entry.inv);
483
+ }
484
+ };
442
485
  const sendCommand = (s, method, params) => {
443
486
  if (!s.running) return rejectedSend({
444
487
  fate: "aborted",
@@ -483,14 +526,18 @@ const setContext = (s, value) => {
483
526
  };
484
527
  const useStatewireSession = (options) => {
485
528
  const [defaultStore] = useState(createMemorySessionStore);
486
- const store = options.sessionStore ?? defaultStore;
529
+ const mounted = useContext(SessionStorageContext);
530
+ if (options.sessionStore !== void 0 && mounted !== void 0) throw new Error("statewire: session storage is set twice — drop the transport's sessionStore or the client's storage.session");
531
+ const store = options.sessionStore ?? mounted ?? defaultStore;
487
532
  const [s] = useState(() => {
488
533
  const stored = store.load();
534
+ if (stored !== null && !Array.isArray(stored.commands)) throw new Error("statewire: session storage loaded a record without a commands array");
489
535
  const session = {
490
536
  record: stored ?? {
491
537
  clientId: newClientId(),
492
538
  nextSeq: 1,
493
- ctxNextSeq: 1
539
+ ctxNextSeq: 1,
540
+ commands: []
494
541
  },
495
542
  ctx: {
496
543
  get clientId() {
@@ -508,6 +555,7 @@ const useStatewireSession = (options) => {
508
555
  recordPersisted: stored !== null,
509
556
  store,
510
557
  ephemeral: false,
558
+ deactivated: false,
511
559
  sessionKnown: false,
512
560
  durableSeq: 0,
513
561
  resumeAt: 0,
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":["useEffect","useState","applyOps","StatewirePath","StatewireCmd","StatewireSyn","encodeParams","encodeValue","reviveResponse","bindCommandsHost","CommandsInvocation","CommandsListener","Statewire","StatewireClient","createMemorySessionStore","StatewireSessionRecord","StatewireSessionStore","StatewireSessionStoreOptions","backoff","createMethodProxy","randomId","StatewireSendError","RemoteLink","StatewireFrame","StatewireRemoteProps","WireCommand","method","params","meta","Pending","seq","command","inv","attempted","posted","applied","resolve","payload","reject","error","CtxPending","ops","protocolError","message","Error","newClientId","rejectedSend","failure","SendFailure","Promise","result","catch","AttachState","StatewireSessionOptions","onDone","Session","record","ctx","recordPersisted","store","ephemeral","sessionKnown","durableSeq","resumeAt","idle","ctxOps","ctxPending","lanesOnAttach","attachLaneSeqs","ReadonlySet","frameFailures","pending","canonical","lastPublished","changed","source","StateSource","attach","attachEpoch","running","pumping","transport","waiters","lifecycle","notify","commands","Record","publish","s","wake","waiter","waitForWake","r","push","sleepUntilWake","delayMs","clearTimeout","timer","setTimeout","filter","w","setRecord","save","setIdle","level","cover","entry","onApplied","onCovered","settleEntry","outcome","ok","p","onSettle","type","settleAll","detach","cause","unmount","gone","superseded","const","batch","detachFailure","predecessorLost","some","fate","restateContext","undefined","ctxNextSeq","resetRecord","clientId","survivors","nextSeq","old","enqueue","ephemeralDetach","rejectedFailure","cmd","code","handleCmd","Number","isSafeInteger","dur","Math","max","find","String","handleCmds","cmds","ingestOps","state","changedPaths","publishIngested","RECORDS","snapClocks","seqWm","ctxWm","tail","cmdAligned","every","i","length","ctxAligned","c","handleHello","syn","includes","attachCmd","attachCtx","Set","has","ctxWatermark","ctxSeq","pump","handleOps","handleRefusal","watermark","retry","Date","now","firstCmd","firstCtx","clocksAhead","connection","reconnect","handleDetach","handleFinish","reason","isFinished","Lanes","frame","cmdEntries","ctxEntries","buildLanes","at","map","takeAttachLanes","wanted","lanes","status","resumeDelay","epoch","send","onPosted","start","stop","setTransport","ts","onStart","sendCommand","encoded","setContext","value","Array","isArray","op","path","useStatewireSession","options","defaultStore","sessionStore","stored","load","session","onHello","args","onOps","onCmds","onRefusal","onIdle","onDetach","onFinish","snapshot","takeChanged","setOnChange","listener","setListener"],"sources":["../../src/client/session.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { applyOps } from \"../wire/ops\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport type { StatewireCmd, StatewireSyn } from \"./connection\";\nimport { encodeParams, encodeValue, reviveResponse } from \"../wire/meta\";\nimport { bindCommandsHost } from \"../host/host\";\nimport type { CommandsInvocation, CommandsListener } from \"../host/host\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\nimport { createMemorySessionStore } from \"./sessionStore\";\nimport type {\n StatewireSessionRecord,\n StatewireSessionStore,\n StatewireSessionStoreOptions,\n} from \"./sessionStore\";\nimport { backoff } from \"./timing\";\nimport { createMethodProxy } from \"../util/methodProxy\";\nimport { randomId } from \"../util/randomId\";\nimport { StatewireSendError } from \"../types\";\nimport type {\n RemoteLink,\n StatewireFrame,\n StatewireRemoteProps,\n} from \"../transports/sse\";\n\ntype WireCommand = {\n method: string;\n params: unknown[];\n meta?: unknown;\n};\n\ntype Pending = {\n readonly seq: number;\n readonly command: WireCommand;\n readonly inv: CommandsInvocation;\n /** A send carrying this statement may have reached the server. */\n attempted: boolean;\n /** In the resend queue when false. */\n posted: boolean;\n /** The server acknowledged admission; the terminal verdict is still due. */\n applied: boolean;\n resolve: (payload: unknown) => void;\n reject: (error: StatewireSendError) => void;\n};\n\ntype CtxPending = {\n readonly seq: number;\n readonly ops: unknown[];\n posted: boolean;\n};\n\nconst protocolError = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nconst newClientId = () => `c-${randomId()}`;\n\nconst rejectedSend = (\n failure: StatewireClient.SendFailure,\n): Promise<unknown> => {\n const result = Promise.reject<unknown>(new StatewireSendError(failure));\n result.catch(() => {});\n return result;\n};\n\ntype AttachState = \"detached\" | \"attached\" | \"finished\";\n\nexport type StatewireSessionOptions = StatewireSessionStoreOptions & {\n onDone?: (() => void) | undefined;\n};\n\ntype Session = {\n record: StatewireSessionRecord;\n ctx: StatewireRemoteProps;\n recordPersisted: boolean;\n store: StatewireSessionStore;\n ephemeral: boolean;\n sessionKnown: boolean;\n durableSeq: number;\n resumeAt: number;\n idle: boolean;\n onDone: (() => void) | undefined;\n ctxOps: unknown[] | undefined;\n ctxPending: CtxPending[];\n lanesOnAttach: boolean;\n attachLaneSeqs: readonly [ReadonlySet<number>, ReadonlySet<number>];\n frameFailures: number;\n pending: Pending[];\n canonical: unknown;\n lastPublished: unknown;\n changed: StatewirePath[];\n source: Statewire.StateSource;\n attach: AttachState;\n attachEpoch: number;\n running: boolean;\n pumping: boolean;\n transport: RemoteLink | null;\n waiters: (() => void)[];\n lifecycle: CommandsListener | null;\n notify: () => void;\n commands: Record<string, (...params: unknown[]) => Promise<unknown>>;\n};\n\nconst publish = (s: Session) => {\n if (s.canonical === s.lastPublished) return;\n s.lastPublished = s.canonical;\n s.notify();\n};\n\nconst wake = (s: Session) => {\n const waiters = s.waiters;\n s.waiters = [];\n for (const waiter of waiters) waiter();\n};\n\nconst waitForWake = (s: Session) => new Promise<void>((r) => s.waiters.push(r));\n\nconst sleepUntilWake = (s: Session, delayMs: number) =>\n new Promise<void>((resolve) => {\n const waiter = () => {\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(() => {\n s.waiters = s.waiters.filter((w) => w !== waiter);\n resolve();\n }, delayMs);\n s.waiters.push(waiter);\n });\n\nconst setRecord = (s: Session, record: StatewireSessionRecord) => {\n s.record = record;\n if (!s.ephemeral) s.store.save(record);\n};\n\nconst setIdle = (s: Session, level: boolean) => {\n if (level === s.idle) return;\n s.idle = level;\n s.notify();\n if (level) s.onDone?.();\n};\n\nconst cover = (s: Session, entry: Pending) => {\n if (entry.applied) return;\n entry.applied = true;\n s.lifecycle?.onApplied(entry.inv);\n s.lifecycle?.onCovered?.(entry.inv);\n};\n\nconst settleEntry = (\n s: Session,\n entry: Pending,\n outcome:\n | { ok: true; payload: unknown }\n | { ok: false; failure: StatewireClient.SendFailure },\n) => {\n s.pending = s.pending.filter((p) => p !== entry);\n if (outcome.ok) {\n entry.resolve(outcome.payload);\n s.lifecycle?.onSettle(entry.inv, {\n type: \"accepted\",\n payload: outcome.payload,\n });\n } else {\n entry.reject(new StatewireSendError(outcome.failure));\n s.lifecycle?.onSettle(entry.inv, {\n type: \"rejected\",\n error: new StatewireSendError(outcome.failure),\n });\n }\n};\n\nconst settleAll = (s: Session, detach: \"unmount\" | \"gone\" | \"superseded\") => {\n const cause = (\n {\n unmount: \"unmount\",\n gone: \"stream-gone\",\n superseded: \"superseded\",\n } as const\n )[detach];\n const batch = s.pending;\n const detachFailure = (entry: Pending): StatewireClient.SendFailure => {\n if (!entry.attempted) {\n const predecessorLost = batch.some(\n (p) => p.seq < entry.seq && p.attempted,\n );\n return predecessorLost\n ? { fate: \"aborted\", cause, predecessorLost }\n : { fate: \"aborted\", cause };\n }\n return { fate: \"lost\", cause };\n };\n for (const entry of [...batch]) {\n s.lifecycle?.onCovered?.(entry.inv);\n settleEntry(s, entry, { ok: false, failure: detachFailure(entry) });\n }\n};\n\nconst restateContext = (s: Session) => {\n s.ctxPending = [];\n if (s.ctxOps === undefined) return;\n const seq = s.record.ctxNextSeq;\n setRecord(s, { ...s.record, ctxNextSeq: seq + 1 });\n s.ctxPending.push({ seq, ops: s.ctxOps, posted: false });\n};\n\n// The server-side record's dedup memory is gone: history that may have\n// reached a server settles lost — the new hello's snapshot is the only\n// truth about what survived — and never-attempted statements re-stamp\n// from 1 on the reset lane clocks.\nconst resetRecord = (s: Session, clientId: string) => {\n const survivors: Pending[] = [];\n for (const entry of [...s.pending]) {\n if (entry.attempted || entry.applied) {\n s.lifecycle?.onCovered?.(entry.inv);\n settleEntry(s, entry, {\n ok: false,\n failure: { fate: \"lost\", cause: \"session-lost\" },\n });\n } else {\n survivors.push(entry);\n }\n }\n s.pending = [];\n s.durableSeq = 0;\n setRecord(s, { clientId, nextSeq: 1, ctxNextSeq: 1 });\n for (const old of survivors) {\n s.lifecycle?.onCovered?.(old.inv);\n enqueue(s, old.command, old.inv.params, old.resolve, old.reject);\n }\n restateContext(s);\n publish(s);\n wake(s);\n};\n\n// The record died with the attach: mint a fresh id for the next one.\nconst ephemeralDetach = (s: Session) => {\n s.ephemeral = false;\n s.sessionKnown = false;\n resetRecord(s, newClientId());\n};\n\nconst rejectedFailure = (cmd: StatewireCmd): StatewireClient.SendFailure => {\n return {\n fate: \"rejected\",\n cause: \"server\",\n ...(cmd.code !== undefined && { code: cmd.code }),\n ...(cmd.message !== undefined && { message: cmd.message }),\n ...(cmd.payload !== undefined && { payload: cmd.payload }),\n };\n};\n\nconst handleCmd = (s: Session, cmd: StatewireCmd) => {\n if (!Number.isSafeInteger(cmd.seq) || cmd.seq <= 0) {\n protocolError(\"cmd.seq must be a positive safe integer\");\n }\n if (cmd.dur === true) {\n s.durableSeq = Math.max(s.durableSeq, cmd.seq);\n for (const entry of s.pending) {\n if (entry.seq <= s.durableSeq) entry.posted = true;\n }\n }\n if (cmd.type === undefined) return;\n const entry = s.pending.find((p) => p.seq === cmd.seq);\n if (cmd.type === \"applied\") {\n if (entry) cover(s, entry);\n return;\n }\n if (!entry) return;\n cover(s, entry);\n const outcome =\n cmd.type === \"result\"\n ? { ok: true as const, payload: reviveResponse(cmd).payload }\n : cmd.type === \"rejected\"\n ? { ok: false as const, failure: rejectedFailure(reviveResponse(cmd)) }\n : cmd.type === \"failed\"\n ? {\n ok: false as const,\n failure: {\n fate: \"failed\" as const,\n cause: \"server\" as const,\n ...(cmd.message !== undefined && { message: cmd.message }),\n },\n }\n : cmd.type === \"crashed\"\n ? {\n ok: false as const,\n failure: { fate: \"crashed\" as const, cause: \"server\" as const },\n }\n : cmd.type === \"expired\"\n ? {\n ok: false as const,\n failure: {\n fate: \"expired\" as const,\n cause: \"server\" as const,\n },\n }\n : protocolError(`unknown cmd type: ${String(cmd.type)}`);\n settleEntry(s, entry, outcome);\n};\n\nconst handleCmds = (s: Session, cmds: StatewireCmd[]) => {\n for (const cmd of cmds) handleCmd(s, cmd);\n wake(s);\n};\n\nconst ingestOps = (s: Session, ops: unknown[]) => {\n const applied = applyOps(s.canonical, ops);\n s.canonical = applied.state;\n s.changed.push(...applied.changedPaths);\n};\n\nconst publishIngested = (s: Session) => {\n publish(s);\n wake(s);\n};\n\nconst RECORDS = [\"fresh\", \"resumed\", \"ephemeral\"];\n\n// Snap a resumed session's lane clocks onto the record: seqs above the stated\n// watermark were never admitted, so a stale restored clock re-stamps its\n// never-admitted statements consecutively after the watermark.\nconst snapClocks = (s: Session, seqWm: number, ctxWm: number) => {\n const tail = s.pending.filter((p) => p.seq > seqWm);\n const cmdAligned =\n tail.every((p, i) => p.seq === seqWm + 1 + i) &&\n s.record.nextSeq === seqWm + tail.length + 1;\n if (!cmdAligned) {\n s.pending = s.pending.filter((p) => p.seq <= seqWm);\n setRecord(s, { ...s.record, nextSeq: seqWm + 1 });\n for (const old of tail) {\n s.lifecycle?.onCovered?.(old.inv);\n enqueue(s, old.command, old.inv.params, old.resolve, old.reject);\n }\n }\n const ctxAligned =\n s.ctxPending.every((c, i) => c.seq === ctxWm + 1 + i) &&\n s.record.ctxNextSeq === ctxWm + s.ctxPending.length + 1;\n if (!ctxAligned) {\n setRecord(s, { ...s.record, ctxNextSeq: ctxWm + 1 });\n restateContext(s);\n }\n};\n\nconst handleHello = (\n s: Session,\n { ops, syn }: { ops: unknown[]; syn: StatewireSyn },\n) => {\n const record = syn.record ?? \"fresh\";\n if (!RECORDS.includes(record)) {\n protocolError(`unknown record: ${String(record)}`);\n }\n ingestOps(s, ops);\n s.attach = \"attached\";\n s.attachEpoch += 1;\n s.frameFailures = 0;\n s.resumeAt = 0;\n s.ephemeral = record === \"ephemeral\";\n const [attachCmd, attachCtx] = s.attachLaneSeqs;\n s.attachLaneSeqs = [new Set(), new Set()];\n if (record === \"resumed\") {\n // Resending unsettled statements is exactly-once-safe: absorbed replays\n // re-emit their stored verdicts (applied while still in flight).\n for (const entry of s.pending) {\n entry.posted = attachCmd.has(entry.seq);\n }\n const ctxWatermark = syn.ctxSeq ?? 0;\n s.ctxPending = s.ctxPending.filter((c) => c.seq > ctxWatermark);\n for (const c of s.ctxPending) c.posted = attachCtx.has(c.seq);\n snapClocks(s, syn.seq ?? 0, ctxWatermark);\n } else {\n resetRecord(s, s.record.clientId);\n }\n s.sessionKnown = true;\n publishIngested(s);\n void pump(s);\n};\n\nconst handleOps = (\n s: Session,\n { ops, cmds }: { ops: unknown[]; cmds: StatewireCmd[] },\n) => {\n ingestOps(s, ops);\n for (const cmd of cmds) handleCmd(s, cmd);\n publishIngested(s);\n};\n\n// A {syn} refusal never settles: reconcile the resend queues against the\n// stated watermarks; retry present means wait, absent means resend now.\nconst handleRefusal = (s: Session, syn: StatewireSyn) => {\n const { seq, ctxSeq } = syn;\n if (typeof seq === \"number\") {\n const watermark = Math.max(seq, s.durableSeq);\n for (const entry of s.pending) entry.posted = entry.seq <= watermark;\n }\n if (typeof ctxSeq === \"number\") {\n s.ctxPending = s.ctxPending.filter((c) => c.seq > ctxSeq);\n for (const c of s.ctxPending) c.posted = false;\n }\n if (typeof syn.retry === \"number\") {\n s.resumeAt = Date.now() + syn.retry;\n }\n const firstCmd = s.pending.find((p) => !p.posted);\n const firstCtx = s.ctxPending.find((c) => !c.posted);\n const clocksAhead =\n (typeof syn.seq === \"number\" &&\n firstCmd !== undefined &&\n firstCmd.seq > Math.max(syn.seq, s.durableSeq) + 1) ||\n (typeof syn.ctxSeq === \"number\" &&\n firstCtx !== undefined &&\n firstCtx.seq > syn.ctxSeq + 1);\n // Clocks ahead of a record that cannot admit them: reattach first and let\n // the hello's record arbitrate.\n if (clocksAhead) s.transport?.connection.reconnect();\n wake(s);\n void pump(s);\n};\n\nconst handleDetach = (s: Session) => {\n if (s.attach === \"attached\") s.attach = \"detached\";\n if (s.ephemeral) ephemeralDetach(s);\n wake(s);\n};\n\nconst handleFinish = (s: Session, { reason }: { reason: string }) => {\n if (reason === \"evicted\" || reason === \"error\") return;\n s.attach = \"finished\";\n settleAll(s, reason === \"superseded\" ? \"superseded\" : \"gone\");\n publish(s);\n wake(s);\n};\n\nconst isFinished = (s: Session) => s.attach === \"finished\";\n\ntype Lanes = {\n frame: StatewireFrame;\n cmdEntries: Pending[];\n ctxEntries: CtxPending[];\n};\n\n// A lane must be strictly consecutive within a frame: the first unposted run\n// per lane rides now, later runs ride follow-up frames.\nconst buildLanes = (s: Session): Lanes | null => {\n const ctxEntries: CtxPending[] = [];\n for (const entry of s.ctxPending) {\n if (entry.posted) continue;\n if (ctxEntries.length > 0 && entry.seq !== ctxEntries.at(-1)!.seq + 1)\n break;\n ctxEntries.push(entry);\n }\n const cmdEntries: Pending[] = [];\n for (const entry of s.pending) {\n if (entry.posted) continue;\n if (cmdEntries.length > 0 && entry.seq !== cmdEntries.at(-1)!.seq + 1)\n break;\n cmdEntries.push(entry);\n }\n if (ctxEntries.length === 0 && cmdEntries.length === 0) return null;\n return {\n frame: {\n ...(ctxEntries.length > 0 && {\n ctx: ctxEntries.map((c) => ({ ops: c.ops, seq: c.seq })),\n }),\n ...(cmdEntries.length > 0 && {\n cmd: cmdEntries.map((p) => ({ ...p.command, seq: p.seq })),\n }),\n },\n cmdEntries,\n ctxEntries,\n };\n};\n\nconst takeAttachLanes = (s: Session): StatewireFrame | null => {\n s.attachLaneSeqs = [new Set(), new Set()];\n const wanted = s.lanesOnAttach;\n s.lanesOnAttach = false;\n if (!wanted || !s.sessionKnown) return null;\n const lanes = buildLanes(s);\n if (!lanes) return null;\n s.attachLaneSeqs = [\n new Set(lanes.cmdEntries.map((p) => p.seq)),\n new Set(lanes.ctxEntries.map((c) => c.seq)),\n ];\n for (const entry of lanes.cmdEntries) entry.attempted = true;\n return lanes.frame;\n};\n\nconst pump = async (s: Session) => {\n if (s.pumping) return;\n s.pumping = true;\n try {\n while (s.running && !isFinished(s)) {\n const transport = s.transport;\n if (buildLanes(s) === null) return;\n if (s.attach !== \"attached\" || !transport) {\n if (transport?.connection.status === \"idle\") {\n transport.connection.reconnect();\n }\n await waitForWake(s);\n continue;\n }\n const resumeDelay = s.resumeAt - Date.now();\n if (resumeDelay > 0) {\n await sleepUntilWake(s, resumeDelay);\n continue;\n }\n const lanes = buildLanes(s);\n if (!lanes) continue;\n const epoch = s.attachEpoch;\n for (const entry of lanes.cmdEntries) entry.attempted = true;\n let result;\n try {\n result = await transport.send(lanes.frame);\n } catch {\n if (!s.running || isFinished(s)) return;\n s.frameFailures += 1;\n await sleepUntilWake(s, backoff(s.frameFailures));\n continue;\n }\n if (!s.running) return;\n s.frameFailures = 0;\n if (result.type === \"ok\") {\n if (epoch === s.attachEpoch) {\n for (const entry of lanes.cmdEntries) {\n if (s.pending.includes(entry)) {\n entry.posted = true;\n s.lifecycle?.onPosted?.(entry.inv);\n }\n }\n for (const entry of lanes.ctxEntries) entry.posted = true;\n }\n } else if (result.type === \"refusal\") {\n if (epoch === s.attachEpoch) handleRefusal(s, result.syn);\n } else if (result.type === \"stale-lease\") {\n // A POST outlived its attach: reattach first, the hello arbitrates.\n if (epoch === s.attachEpoch) {\n transport.connection.reconnect();\n await waitForWake(s);\n }\n } else if (result.type === \"no-lease\") {\n // No out-of-band write channel: the frame rides a fresh attach.\n if (epoch === s.attachEpoch) {\n s.lanesOnAttach = true;\n transport.connection.reconnect();\n while (s.running && !isFinished(s) && epoch === s.attachEpoch) {\n await waitForWake(s);\n }\n }\n }\n }\n } finally {\n s.pumping = false;\n }\n};\n\nconst start = (s: Session) => {\n if (!s.recordPersisted) {\n s.recordPersisted = true;\n s.store.save(s.record);\n }\n s.running = true;\n void pump(s);\n};\n\nconst stop = (s: Session) => {\n s.running = false;\n wake(s);\n settleAll(s, \"unmount\");\n};\n\nconst setTransport = (s: Session, transport: RemoteLink) => {\n if (s.transport === transport) return;\n s.transport = transport;\n wake(s);\n};\n\nconst enqueue = (\n s: Session,\n command: WireCommand,\n params: readonly unknown[],\n resolve: (payload: unknown) => void,\n reject: (error: StatewireSendError) => void,\n) => {\n const seq = s.record.nextSeq;\n setRecord(s, { ...s.record, nextSeq: seq + 1 });\n const entry: Pending = {\n seq,\n command,\n inv: {\n method: command.method,\n params,\n ts: Date.now(),\n seq,\n clientId: s.record.clientId,\n },\n attempted: false,\n posted: false,\n applied: false,\n resolve,\n reject,\n };\n s.pending.push(entry);\n s.lifecycle?.onStart(entry.inv);\n void pump(s);\n};\n\nconst sendCommand = (\n s: Session,\n method: string,\n params: readonly unknown[],\n): Promise<unknown> => {\n if (!s.running) {\n return rejectedSend({ fate: \"aborted\", cause: \"unmount\" });\n }\n if (isFinished(s)) {\n return rejectedSend({ fate: \"aborted\", cause: \"stream-gone\" });\n }\n const result = new Promise<unknown>((resolve, reject) => {\n const { params: encoded, meta } = encodeParams(params);\n enqueue(\n s,\n { method, params: encoded, ...(meta !== undefined && { meta }) },\n params,\n resolve,\n reject,\n );\n });\n result.catch(() => {});\n return result;\n};\n\nconst setContext = (s: Session, value: Record<string, unknown>): void => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new Error(\"statewire: context must be a plain object\");\n }\n const { value: encoded, meta } = encodeValue(value);\n s.ctxOps = [\n {\n op: \"replace\",\n path: [],\n value: encoded,\n ...(meta !== undefined && { meta }),\n },\n ];\n const seq = s.record.ctxNextSeq;\n setRecord(s, { ...s.record, ctxNextSeq: seq + 1 });\n s.ctxPending.push({ seq, ops: s.ctxOps, posted: false });\n wake(s);\n void pump(s);\n};\n\nexport const useStatewireSession = (\n options: StatewireSessionOptions,\n): Session => {\n const [defaultStore] = useState(createMemorySessionStore);\n const store = options.sessionStore ?? defaultStore;\n const [s] = useState((): Session => {\n const stored = store.load();\n const record = stored ?? {\n clientId: newClientId(),\n nextSeq: 1,\n ctxNextSeq: 1,\n };\n const session: Session = {\n record,\n ctx: {\n get clientId() {\n return session.record.clientId;\n },\n takeAttachLanes: () => takeAttachLanes(session),\n onHello: (args) => handleHello(session, args),\n onOps: (args) => handleOps(session, args),\n onCmds: (cmds) => handleCmds(session, cmds),\n onRefusal: (syn) => handleRefusal(session, syn),\n onIdle: (level) => setIdle(session, level),\n onDetach: () => handleDetach(session),\n onFinish: (args) => handleFinish(session, args),\n },\n recordPersisted: stored !== null,\n store,\n ephemeral: false,\n sessionKnown: false,\n durableSeq: 0,\n resumeAt: 0,\n idle: false,\n onDone: undefined,\n ctxOps: undefined,\n ctxPending: [],\n lanesOnAttach: false,\n attachLaneSeqs: [new Set(), new Set()],\n frameFailures: 0,\n pending: [],\n canonical: undefined,\n lastPublished: undefined,\n changed: [],\n source: {\n snapshot: () => session.canonical,\n takeChanged: () => {\n const changed = session.changed;\n session.changed = [];\n return changed;\n },\n setOnChange: (listener) => {\n session.notify = listener ?? (() => {});\n },\n },\n attach: \"detached\",\n attachEpoch: 0,\n running: false,\n pumping: false,\n transport: null,\n waiters: [],\n lifecycle: null,\n notify: () => {},\n commands: createMethodProxy((method, params) =>\n sendCommand(session, method, params),\n ),\n };\n bindCommandsHost(session.commands, {\n setListener: (listener) => {\n session.lifecycle = listener;\n },\n });\n return session;\n });\n s.store = store;\n s.onDone = options.onDone;\n useEffect(() => {\n start(s);\n return () => stop(s);\n }, [s]);\n return s;\n};\n\nexport { setContext, setTransport };\n"],"mappings":"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"}
1
+ {"version":3,"file":"session.js","names":["useContext","useEffect","useState","applyOps","StatewirePath","StatewireCmd","StatewireSyn","encodeParams","encodeValue","reviveResponse","reviveValue","bindCommandsHost","CommandsInvocation","CommandsListener","Statewire","StatewireClient","SessionStorageContext","createMemorySessionStore","backoff","createMethodProxy","randomId","StatewireSendError","RemoteLink","StatewireFrame","StatewireRemoteProps","WireCommand","method","params","meta","Pending","seq","command","inv","attempted","posted","applied","resolve","payload","reject","error","CtxPending","ops","protocolError","message","Error","newClientId","rejectedSend","failure","SendFailure","Promise","result","catch","AttachState","StatewireSessionOptions","sessionStore","SessionStorage","onDone","Session","record","SessionRecord","ctx","recordPersisted","store","ephemeral","deactivated","sessionKnown","durableSeq","resumeAt","idle","ctxOps","ctxPending","lanesOnAttach","attachLaneSeqs","ReadonlySet","frameFailures","pending","canonical","lastPublished","changed","source","StateSource","attach","attachEpoch","running","pumping","transport","waiters","lifecycle","notify","commands","Record","publish","s","wake","waiter","waitForWake","r","push","sleepUntilWake","delayMs","clearTimeout","timer","setTimeout","filter","w","setRecord","save","backlog","SessionCommand","p","map","syncBacklog","unchanged","length","every","c","i","setIdle","level","cover","entry","onApplied","onCovered","settleEntry","outcome","ok","onSettle","type","settleAll","detach","cause","unmount","gone","superseded","const","batch","detachFailure","predecessorLost","some","fate","restateContext","undefined","ctxNextSeq","resetRecord","clientId","survivors","nextSeq","old","enqueue","ephemeralDetach","rejectedFailure","cmd","code","handleCmd","Number","isSafeInteger","dur","Math","max","find","String","handleCmds","cmds","ingestOps","state","changedPaths","publishIngested","RECORDS","snapClocks","seqWm","ctxWm","tail","cmdAligned","ctxAligned","handleHello","syn","includes","attachCmd","attachCtx","Set","has","ctxWatermark","ctxSeq","pump","handleOps","handleRefusal","watermark","retry","Date","now","firstCmd","firstCtx","clocksAhead","connection","reconnect","handleDetach","handleFinish","reason","isFinished","Lanes","frame","cmdEntries","ctxEntries","buildLanes","at","takeAttachLanes","wanted","lanes","status","resumeDelay","epoch","send","onPosted","start","resume","stop","setTransport","ts","onStart","stored","sort","a","b","sendCommand","encoded","setContext","value","Array","isArray","op","path","useStatewireSession","options","defaultStore","mounted","load","session","onHello","args","onOps","onCmds","onRefusal","onIdle","onDetach","onFinish","snapshot","takeChanged","setOnChange","listener","setListener"],"sources":["../../src/client/session.ts"],"sourcesContent":["import { useContext, useEffect, useState } from \"react\";\nimport { applyOps } from \"../wire/ops\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport type { StatewireCmd, StatewireSyn } from \"./connection\";\nimport {\n encodeParams,\n encodeValue,\n reviveResponse,\n reviveValue,\n} from \"../wire/meta\";\nimport { bindCommandsHost } from \"../host/host\";\nimport type { CommandsInvocation, CommandsListener } from \"../host/host\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\nimport {\n SessionStorageContext,\n createMemorySessionStore,\n} from \"./sessionStore\";\nimport { backoff } from \"./timing\";\nimport { createMethodProxy } from \"../util/methodProxy\";\nimport { randomId } from \"../util/randomId\";\nimport { StatewireSendError } from \"../types\";\nimport type {\n RemoteLink,\n StatewireFrame,\n StatewireRemoteProps,\n} from \"../transports/sse\";\n\ntype WireCommand = {\n method: string;\n params: unknown[];\n meta?: unknown;\n};\n\ntype Pending = {\n readonly seq: number;\n readonly command: WireCommand;\n readonly inv: CommandsInvocation;\n /** A send carrying this statement may have reached the server. */\n attempted: boolean;\n /** In the resend queue when false. */\n posted: boolean;\n /** The server acknowledged admission; the terminal verdict is still due. */\n applied: boolean;\n resolve: (payload: unknown) => void;\n reject: (error: StatewireSendError) => void;\n};\n\ntype CtxPending = {\n readonly seq: number;\n readonly ops: unknown[];\n posted: boolean;\n};\n\nconst protocolError = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nconst newClientId = () => `c-${randomId()}`;\n\nconst rejectedSend = (\n failure: StatewireClient.SendFailure,\n): Promise<unknown> => {\n const result = Promise.reject<unknown>(new StatewireSendError(failure));\n result.catch(() => {});\n return result;\n};\n\ntype AttachState = \"detached\" | \"attached\" | \"finished\";\n\nexport type StatewireSessionOptions = {\n sessionStore?: StatewireClient.SessionStorage | undefined;\n onDone?: (() => void) | undefined;\n};\n\ntype Session = {\n record: StatewireClient.SessionRecord;\n ctx: StatewireRemoteProps;\n recordPersisted: boolean;\n store: StatewireClient.SessionStorage;\n ephemeral: boolean;\n /** An ephemeral record died with its attach: the storage is off for good. */\n deactivated: boolean;\n sessionKnown: boolean;\n durableSeq: number;\n resumeAt: number;\n idle: boolean;\n onDone: (() => void) | undefined;\n ctxOps: unknown[] | undefined;\n ctxPending: CtxPending[];\n lanesOnAttach: boolean;\n attachLaneSeqs: readonly [ReadonlySet<number>, ReadonlySet<number>];\n frameFailures: number;\n pending: Pending[];\n canonical: unknown;\n lastPublished: unknown;\n changed: StatewirePath[];\n source: Statewire.StateSource;\n attach: AttachState;\n attachEpoch: number;\n running: boolean;\n pumping: boolean;\n transport: RemoteLink | null;\n waiters: (() => void)[];\n lifecycle: CommandsListener | null;\n notify: () => void;\n commands: Record<string, (...params: unknown[]) => Promise<unknown>>;\n};\n\nconst publish = (s: Session) => {\n if (s.canonical === s.lastPublished) return;\n s.lastPublished = s.canonical;\n s.notify();\n};\n\nconst wake = (s: Session) => {\n const waiters = s.waiters;\n s.waiters = [];\n for (const waiter of waiters) waiter();\n};\n\nconst waitForWake = (s: Session) => new Promise<void>((r) => s.waiters.push(r));\n\nconst sleepUntilWake = (s: Session, delayMs: number) =>\n new Promise<void>((resolve) => {\n const waiter = () => {\n clearTimeout(timer);\n resolve();\n };\n const timer = setTimeout(() => {\n s.waiters = s.waiters.filter((w) => w !== waiter);\n resolve();\n }, delayMs);\n s.waiters.push(waiter);\n });\n\nconst setRecord = (s: Session, record: StatewireClient.SessionRecord) => {\n s.record = record;\n if (!s.deactivated) s.store.save(record);\n};\n\nconst backlog = (s: Session): StatewireClient.SessionCommand[] =>\n s.pending\n .filter((p) => p.seq > s.durableSeq)\n .map((p) => ({ seq: p.seq, ...p.command }));\n\n// Storage holds what a reload must resend: a command leaves at its dur, at a\n// server verdict, or at a record reset — never at a local channel death.\nconst syncBacklog = (s: Session) => {\n const commands = backlog(s);\n const unchanged =\n commands.length === s.record.commands.length &&\n commands.every((c, i) => c.seq === s.record.commands[i]!.seq);\n if (unchanged) return;\n setRecord(s, { ...s.record, commands });\n};\n\nconst setIdle = (s: Session, level: boolean) => {\n if (level === s.idle) return;\n s.idle = level;\n s.notify();\n if (level) s.onDone?.();\n};\n\nconst cover = (s: Session, entry: Pending) => {\n if (entry.applied) return;\n entry.applied = true;\n s.lifecycle?.onApplied(entry.inv);\n s.lifecycle?.onCovered?.(entry.inv);\n};\n\nconst settleEntry = (\n s: Session,\n entry: Pending,\n outcome:\n | { ok: true; payload: unknown }\n | { ok: false; failure: StatewireClient.SendFailure },\n) => {\n s.pending = s.pending.filter((p) => p !== entry);\n if (outcome.ok) {\n entry.resolve(outcome.payload);\n s.lifecycle?.onSettle(entry.inv, {\n type: \"accepted\",\n payload: outcome.payload,\n });\n } else {\n entry.reject(new StatewireSendError(outcome.failure));\n s.lifecycle?.onSettle(entry.inv, {\n type: \"rejected\",\n error: new StatewireSendError(outcome.failure),\n });\n }\n};\n\nconst settleAll = (s: Session, detach: \"unmount\" | \"gone\" | \"superseded\") => {\n const cause = (\n {\n unmount: \"unmount\",\n gone: \"stream-gone\",\n superseded: \"superseded\",\n } as const\n )[detach];\n const batch = s.pending;\n const detachFailure = (entry: Pending): StatewireClient.SendFailure => {\n if (!entry.attempted) {\n const predecessorLost = batch.some(\n (p) => p.seq < entry.seq && p.attempted,\n );\n return predecessorLost\n ? { fate: \"aborted\", cause, predecessorLost }\n : { fate: \"aborted\", cause };\n }\n return { fate: \"lost\", cause };\n };\n for (const entry of [...batch]) {\n s.lifecycle?.onCovered?.(entry.inv);\n settleEntry(s, entry, { ok: false, failure: detachFailure(entry) });\n }\n};\n\nconst restateContext = (s: Session) => {\n s.ctxPending = [];\n if (s.ctxOps === undefined) return;\n const seq = s.record.ctxNextSeq;\n setRecord(s, { ...s.record, ctxNextSeq: seq + 1 });\n s.ctxPending.push({ seq, ops: s.ctxOps, posted: false });\n};\n\n// The server-side record's dedup memory is gone: history that may have\n// reached a server settles lost — the new hello's snapshot is the only\n// truth about what survived — and never-attempted statements re-stamp\n// from 1 on the reset lane clocks.\nconst resetRecord = (s: Session, clientId: string) => {\n const survivors: Pending[] = [];\n for (const entry of [...s.pending]) {\n if (entry.attempted || entry.applied) {\n s.lifecycle?.onCovered?.(entry.inv);\n settleEntry(s, entry, {\n ok: false,\n failure: { fate: \"lost\", cause: \"session-lost\" },\n });\n } else {\n survivors.push(entry);\n }\n }\n s.pending = [];\n s.durableSeq = 0;\n setRecord(s, { clientId, nextSeq: 1, ctxNextSeq: 1, commands: [] });\n for (const old of survivors) {\n s.lifecycle?.onCovered?.(old.inv);\n enqueue(s, old.command, old.inv.params, old.resolve, old.reject);\n }\n restateContext(s);\n publish(s);\n wake(s);\n};\n\n// The record died with the attach: mint a fresh id for the next one.\nconst ephemeralDetach = (s: Session) => {\n s.ephemeral = false;\n s.sessionKnown = false;\n resetRecord(s, newClientId());\n};\n\nconst rejectedFailure = (cmd: StatewireCmd): StatewireClient.SendFailure => {\n return {\n fate: \"rejected\",\n cause: \"server\",\n ...(cmd.code !== undefined && { code: cmd.code }),\n ...(cmd.message !== undefined && { message: cmd.message }),\n ...(cmd.payload !== undefined && { payload: cmd.payload }),\n };\n};\n\nconst handleCmd = (s: Session, cmd: StatewireCmd) => {\n if (!Number.isSafeInteger(cmd.seq) || cmd.seq <= 0) {\n protocolError(\"cmd.seq must be a positive safe integer\");\n }\n if (cmd.dur === true) {\n s.durableSeq = Math.max(s.durableSeq, cmd.seq);\n for (const entry of s.pending) {\n if (entry.seq <= s.durableSeq) entry.posted = true;\n }\n }\n if (cmd.type === undefined) return;\n const entry = s.pending.find((p) => p.seq === cmd.seq);\n if (cmd.type === \"applied\") {\n if (entry) cover(s, entry);\n return;\n }\n if (!entry) return;\n cover(s, entry);\n const outcome =\n cmd.type === \"result\"\n ? { ok: true as const, payload: reviveResponse(cmd).payload }\n : cmd.type === \"rejected\"\n ? { ok: false as const, failure: rejectedFailure(reviveResponse(cmd)) }\n : cmd.type === \"failed\"\n ? {\n ok: false as const,\n failure: {\n fate: \"failed\" as const,\n cause: \"server\" as const,\n ...(cmd.message !== undefined && { message: cmd.message }),\n },\n }\n : cmd.type === \"crashed\"\n ? {\n ok: false as const,\n failure: { fate: \"crashed\" as const, cause: \"server\" as const },\n }\n : cmd.type === \"expired\"\n ? {\n ok: false as const,\n failure: {\n fate: \"expired\" as const,\n cause: \"server\" as const,\n },\n }\n : protocolError(`unknown cmd type: ${String(cmd.type)}`);\n settleEntry(s, entry, outcome);\n};\n\nconst handleCmds = (s: Session, cmds: StatewireCmd[]) => {\n for (const cmd of cmds) handleCmd(s, cmd);\n syncBacklog(s);\n wake(s);\n};\n\nconst ingestOps = (s: Session, ops: unknown[]) => {\n const applied = applyOps(s.canonical, ops);\n s.canonical = applied.state;\n s.changed.push(...applied.changedPaths);\n};\n\nconst publishIngested = (s: Session) => {\n publish(s);\n wake(s);\n};\n\nconst RECORDS = [\"fresh\", \"resumed\", \"ephemeral\"];\n\n// Snap a resumed session's lane clocks onto the record: seqs above the stated\n// watermark were never admitted, so a stale restored clock re-stamps its\n// never-admitted statements consecutively after the watermark.\nconst snapClocks = (s: Session, seqWm: number, ctxWm: number) => {\n const tail = s.pending.filter((p) => p.seq > seqWm);\n const cmdAligned =\n tail.every((p, i) => p.seq === seqWm + 1 + i) &&\n s.record.nextSeq === seqWm + tail.length + 1;\n if (!cmdAligned) {\n s.pending = s.pending.filter((p) => p.seq <= seqWm);\n setRecord(s, { ...s.record, nextSeq: seqWm + 1 });\n for (const old of tail) {\n s.lifecycle?.onCovered?.(old.inv);\n enqueue(s, old.command, old.inv.params, old.resolve, old.reject);\n }\n }\n const ctxAligned =\n s.ctxPending.every((c, i) => c.seq === ctxWm + 1 + i) &&\n s.record.ctxNextSeq === ctxWm + s.ctxPending.length + 1;\n if (!ctxAligned) {\n setRecord(s, { ...s.record, ctxNextSeq: ctxWm + 1 });\n restateContext(s);\n }\n};\n\nconst handleHello = (\n s: Session,\n { ops, syn }: { ops: unknown[]; syn: StatewireSyn },\n) => {\n const record = syn.record ?? \"fresh\";\n if (!RECORDS.includes(record)) {\n protocolError(`unknown record: ${String(record)}`);\n }\n ingestOps(s, ops);\n s.attach = \"attached\";\n s.attachEpoch += 1;\n s.frameFailures = 0;\n s.resumeAt = 0;\n s.ephemeral = record === \"ephemeral\";\n if (s.ephemeral) s.deactivated = true;\n const [attachCmd, attachCtx] = s.attachLaneSeqs;\n s.attachLaneSeqs = [new Set(), new Set()];\n if (record === \"resumed\") {\n // Resending unsettled statements is exactly-once-safe: absorbed replays\n // re-emit their stored verdicts (applied while still in flight).\n for (const entry of s.pending) {\n entry.posted = attachCmd.has(entry.seq);\n }\n const ctxWatermark = syn.ctxSeq ?? 0;\n s.ctxPending = s.ctxPending.filter((c) => c.seq > ctxWatermark);\n for (const c of s.ctxPending) c.posted = attachCtx.has(c.seq);\n snapClocks(s, syn.seq ?? 0, ctxWatermark);\n syncBacklog(s);\n } else {\n resetRecord(s, s.record.clientId);\n }\n s.sessionKnown = true;\n publishIngested(s);\n void pump(s);\n};\n\nconst handleOps = (\n s: Session,\n { ops, cmds }: { ops: unknown[]; cmds: StatewireCmd[] },\n) => {\n ingestOps(s, ops);\n for (const cmd of cmds) handleCmd(s, cmd);\n syncBacklog(s);\n publishIngested(s);\n};\n\n// A {syn} refusal never settles: reconcile the resend queues against the\n// stated watermarks; retry present means wait, absent means resend now.\nconst handleRefusal = (s: Session, syn: StatewireSyn) => {\n const { seq, ctxSeq } = syn;\n if (typeof seq === \"number\") {\n const watermark = Math.max(seq, s.durableSeq);\n for (const entry of s.pending) entry.posted = entry.seq <= watermark;\n }\n if (typeof ctxSeq === \"number\") {\n s.ctxPending = s.ctxPending.filter((c) => c.seq > ctxSeq);\n for (const c of s.ctxPending) c.posted = false;\n }\n if (typeof syn.retry === \"number\") {\n s.resumeAt = Date.now() + syn.retry;\n }\n const firstCmd = s.pending.find((p) => !p.posted);\n const firstCtx = s.ctxPending.find((c) => !c.posted);\n const clocksAhead =\n (typeof syn.seq === \"number\" &&\n firstCmd !== undefined &&\n firstCmd.seq > Math.max(syn.seq, s.durableSeq) + 1) ||\n (typeof syn.ctxSeq === \"number\" &&\n firstCtx !== undefined &&\n firstCtx.seq > syn.ctxSeq + 1);\n // Clocks ahead of a record that cannot admit them: reattach first and let\n // the hello's record arbitrate.\n if (clocksAhead) s.transport?.connection.reconnect();\n wake(s);\n void pump(s);\n};\n\nconst handleDetach = (s: Session) => {\n if (s.attach === \"attached\") s.attach = \"detached\";\n if (s.ephemeral) ephemeralDetach(s);\n wake(s);\n};\n\nconst handleFinish = (s: Session, { reason }: { reason: string }) => {\n if (reason === \"evicted\" || reason === \"error\") return;\n s.attach = \"finished\";\n settleAll(s, reason === \"superseded\" ? \"superseded\" : \"gone\");\n publish(s);\n wake(s);\n};\n\nconst isFinished = (s: Session) => s.attach === \"finished\";\n\ntype Lanes = {\n frame: StatewireFrame;\n cmdEntries: Pending[];\n ctxEntries: CtxPending[];\n};\n\n// A lane must be strictly consecutive within a frame: the first unposted run\n// per lane rides now, later runs ride follow-up frames.\nconst buildLanes = (s: Session): Lanes | null => {\n const ctxEntries: CtxPending[] = [];\n for (const entry of s.ctxPending) {\n if (entry.posted) continue;\n if (ctxEntries.length > 0 && entry.seq !== ctxEntries.at(-1)!.seq + 1)\n break;\n ctxEntries.push(entry);\n }\n const cmdEntries: Pending[] = [];\n for (const entry of s.pending) {\n if (entry.posted) continue;\n if (cmdEntries.length > 0 && entry.seq !== cmdEntries.at(-1)!.seq + 1)\n break;\n cmdEntries.push(entry);\n }\n if (ctxEntries.length === 0 && cmdEntries.length === 0) return null;\n return {\n frame: {\n ...(ctxEntries.length > 0 && {\n ctx: ctxEntries.map((c) => ({ ops: c.ops, seq: c.seq })),\n }),\n ...(cmdEntries.length > 0 && {\n cmd: cmdEntries.map((p) => ({ ...p.command, seq: p.seq })),\n }),\n },\n cmdEntries,\n ctxEntries,\n };\n};\n\nconst takeAttachLanes = (s: Session): StatewireFrame | null => {\n s.attachLaneSeqs = [new Set(), new Set()];\n const wanted = s.lanesOnAttach;\n s.lanesOnAttach = false;\n if (!wanted || !s.sessionKnown) return null;\n const lanes = buildLanes(s);\n if (!lanes) return null;\n s.attachLaneSeqs = [\n new Set(lanes.cmdEntries.map((p) => p.seq)),\n new Set(lanes.ctxEntries.map((c) => c.seq)),\n ];\n for (const entry of lanes.cmdEntries) entry.attempted = true;\n return lanes.frame;\n};\n\nconst pump = async (s: Session) => {\n if (s.pumping) return;\n s.pumping = true;\n try {\n while (s.running && !isFinished(s)) {\n const transport = s.transport;\n if (buildLanes(s) === null) return;\n if (s.attach !== \"attached\" || !transport) {\n if (transport?.connection.status === \"idle\") {\n transport.connection.reconnect();\n }\n await waitForWake(s);\n continue;\n }\n const resumeDelay = s.resumeAt - Date.now();\n if (resumeDelay > 0) {\n await sleepUntilWake(s, resumeDelay);\n continue;\n }\n const lanes = buildLanes(s);\n if (!lanes) continue;\n const epoch = s.attachEpoch;\n for (const entry of lanes.cmdEntries) entry.attempted = true;\n let result;\n try {\n result = await transport.send(lanes.frame);\n } catch {\n if (!s.running || isFinished(s)) return;\n s.frameFailures += 1;\n await sleepUntilWake(s, backoff(s.frameFailures));\n continue;\n }\n if (!s.running) return;\n s.frameFailures = 0;\n if (result.type === \"ok\") {\n if (epoch === s.attachEpoch) {\n for (const entry of lanes.cmdEntries) {\n if (s.pending.includes(entry)) {\n entry.posted = true;\n s.lifecycle?.onPosted?.(entry.inv);\n }\n }\n for (const entry of lanes.ctxEntries) entry.posted = true;\n }\n } else if (result.type === \"refusal\") {\n if (epoch === s.attachEpoch) handleRefusal(s, result.syn);\n } else if (result.type === \"stale-lease\") {\n // A POST outlived its attach: reattach first, the hello arbitrates.\n if (epoch === s.attachEpoch) {\n transport.connection.reconnect();\n await waitForWake(s);\n }\n } else if (result.type === \"no-lease\") {\n // No out-of-band write channel: the frame rides a fresh attach.\n if (epoch === s.attachEpoch) {\n s.lanesOnAttach = true;\n transport.connection.reconnect();\n while (s.running && !isFinished(s) && epoch === s.attachEpoch) {\n await waitForWake(s);\n }\n }\n }\n }\n } finally {\n s.pumping = false;\n }\n};\n\nconst start = (s: Session) => {\n if (!s.recordPersisted) {\n s.recordPersisted = true;\n s.store.save(s.record);\n }\n resume(s);\n s.running = true;\n void pump(s);\n};\n\nconst stop = (s: Session) => {\n s.running = false;\n wake(s);\n settleAll(s, \"unmount\");\n};\n\nconst setTransport = (s: Session, transport: RemoteLink) => {\n if (s.transport === transport) return;\n s.transport = transport;\n wake(s);\n};\n\nconst enqueue = (\n s: Session,\n command: WireCommand,\n params: readonly unknown[],\n resolve: (payload: unknown) => void,\n reject: (error: StatewireSendError) => void,\n) => {\n const seq = s.record.nextSeq;\n const entry: Pending = {\n seq,\n command,\n inv: {\n method: command.method,\n params,\n ts: Date.now(),\n seq,\n clientId: s.record.clientId,\n },\n attempted: false,\n posted: false,\n applied: false,\n resolve,\n reject,\n };\n s.pending.push(entry);\n setRecord(s, { ...s.record, nextSeq: seq + 1, commands: backlog(s) });\n s.lifecycle?.onStart(entry.inv);\n void pump(s);\n};\n\n// A stored command cannot be told from one that reached the server: attempted\n// keeps a fresh record settling it lost instead of replaying it blind.\nconst resume = (s: Session) => {\n const stored = [...s.record.commands].sort((a, b) => a.seq - b.seq);\n for (const { seq, ...command } of stored) {\n const params =\n command.meta === undefined\n ? command.params\n : (reviveValue([...command.params], command.meta) as unknown[]);\n const entry: Pending = {\n seq,\n command,\n inv: {\n method: command.method,\n params,\n ts: Date.now(),\n seq,\n clientId: s.record.clientId,\n },\n attempted: true,\n posted: false,\n applied: false,\n resolve: () => {},\n reject: () => {},\n };\n s.pending.push(entry);\n s.lifecycle?.onStart(entry.inv);\n }\n};\n\nconst sendCommand = (\n s: Session,\n method: string,\n params: readonly unknown[],\n): Promise<unknown> => {\n if (!s.running) {\n return rejectedSend({ fate: \"aborted\", cause: \"unmount\" });\n }\n if (isFinished(s)) {\n return rejectedSend({ fate: \"aborted\", cause: \"stream-gone\" });\n }\n const result = new Promise<unknown>((resolve, reject) => {\n const { params: encoded, meta } = encodeParams(params);\n enqueue(\n s,\n { method, params: encoded, ...(meta !== undefined && { meta }) },\n params,\n resolve,\n reject,\n );\n });\n result.catch(() => {});\n return result;\n};\n\nconst setContext = (s: Session, value: Record<string, unknown>): void => {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new Error(\"statewire: context must be a plain object\");\n }\n const { value: encoded, meta } = encodeValue(value);\n s.ctxOps = [\n {\n op: \"replace\",\n path: [],\n value: encoded,\n ...(meta !== undefined && { meta }),\n },\n ];\n const seq = s.record.ctxNextSeq;\n setRecord(s, { ...s.record, ctxNextSeq: seq + 1 });\n s.ctxPending.push({ seq, ops: s.ctxOps, posted: false });\n wake(s);\n void pump(s);\n};\n\nexport const useStatewireSession = (\n options: StatewireSessionOptions,\n): Session => {\n const [defaultStore] = useState(createMemorySessionStore);\n const mounted = useContext(SessionStorageContext);\n if (options.sessionStore !== undefined && mounted !== undefined) {\n throw new Error(\n \"statewire: session storage is set twice — drop the transport's sessionStore or the client's storage.session\",\n );\n }\n const store = options.sessionStore ?? mounted ?? defaultStore;\n const [s] = useState((): Session => {\n const stored = store.load();\n if (stored !== null && !Array.isArray(stored.commands)) {\n throw new Error(\n \"statewire: session storage loaded a record without a commands array\",\n );\n }\n const record = stored ?? {\n clientId: newClientId(),\n nextSeq: 1,\n ctxNextSeq: 1,\n commands: [],\n };\n const session: Session = {\n record,\n ctx: {\n get clientId() {\n return session.record.clientId;\n },\n takeAttachLanes: () => takeAttachLanes(session),\n onHello: (args) => handleHello(session, args),\n onOps: (args) => handleOps(session, args),\n onCmds: (cmds) => handleCmds(session, cmds),\n onRefusal: (syn) => handleRefusal(session, syn),\n onIdle: (level) => setIdle(session, level),\n onDetach: () => handleDetach(session),\n onFinish: (args) => handleFinish(session, args),\n },\n recordPersisted: stored !== null,\n store,\n ephemeral: false,\n deactivated: false,\n sessionKnown: false,\n durableSeq: 0,\n resumeAt: 0,\n idle: false,\n onDone: undefined,\n ctxOps: undefined,\n ctxPending: [],\n lanesOnAttach: false,\n attachLaneSeqs: [new Set(), new Set()],\n frameFailures: 0,\n pending: [],\n canonical: undefined,\n lastPublished: undefined,\n changed: [],\n source: {\n snapshot: () => session.canonical,\n takeChanged: () => {\n const changed = session.changed;\n session.changed = [];\n return changed;\n },\n setOnChange: (listener) => {\n session.notify = listener ?? (() => {});\n },\n },\n attach: \"detached\",\n attachEpoch: 0,\n running: false,\n pumping: false,\n transport: null,\n waiters: [],\n lifecycle: null,\n notify: () => {},\n commands: createMethodProxy((method, params) =>\n sendCommand(session, method, params),\n ),\n };\n bindCommandsHost(session.commands, {\n setListener: (listener) => {\n session.lifecycle = listener;\n },\n });\n return session;\n });\n s.store = store;\n s.onDone = options.onDone;\n useEffect(() => {\n start(s);\n return () => stop(s);\n }, [s]);\n return s;\n};\n\nexport { setContext, setTransport };\n"],"mappings":"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"}