statewire 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/session.d.ts +6 -0
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +213 -64
- package/dist/client/session.js.map +1 -1
- package/dist/statewire.d.ts +15 -0
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js.map +1 -1
- package/package.json +1 -1
- package/src/client/session.ts +275 -63
- package/src/statewire.ts +16 -0
|
@@ -1 +1 @@
|
|
|
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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"}
|
|
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","Shared","txq","parked","SessionVerdict","unsubscribe","Session","record","SessionRecord","ctx","recordPersisted","store","shared","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","mergeBacklog","own","known","Set","foreign","c","has","sort","a","b","MAX_PARKED_VERDICTS","syncBacklogInner","splice","parkedSeqs","v","verdicts","length","slice","unchanged","every","i","undefined","syncBacklog","transact","fn","run","then","lock","stored","load","clientId","adoptReset","setIdle","level","cover","entry","onApplied","onCovered","settleEntry","outcome","ok","onSettle","type","settleAll","detach","cause","unmount","gone","superseded","const","batch","detachFailure","predecessorLost","some","fate","restateContext","ctxNextSeq","resetRecord","survivors","nextSeq","old","enqueueInner","pump","ephemeralDetach","rejectedFailure","cmd","code","outcomeOf","String","TERMINAL_CMD_TYPES","parkVerdict","handleCmd","Number","isSafeInteger","dur","Math","max","find","consumeVerdicts","consumed","verdict","add","size","handleCmds","cmds","ingestOps","state","changedPaths","publishIngested","RECORDS","snapClocks","seqWm","ctxWm","tail","cmdAligned","ctxAligned","handleHello","syn","includes","attachCmd","attachCtx","reconcile","adoptStored","ctxWatermark","ctxSeq","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","subscribe","stop","setTransport","ts","onStart","enqueue","sendCommand","encoded","setContext","value","Array","isArray","op","path","mint","useStatewireSession","options","defaultStore","mounted","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 Shared = {\n txq: Promise<void>;\n parked: StatewireClient.SessionVerdict[];\n unsubscribe: (() => void) | null;\n};\n\ntype Session = {\n record: StatewireClient.SessionRecord;\n ctx: StatewireRemoteProps;\n recordPersisted: boolean;\n store: StatewireClient.SessionStorage;\n shared: Shared | false;\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\nconst mergeBacklog = (s: Session): StatewireClient.SessionCommand[] => {\n const own = backlog(s);\n if (!s.shared) return own;\n const known = new Set(s.pending.map((p) => p.seq));\n const foreign = s.record.commands.filter(\n (c) => !known.has(c.seq) && c.seq > s.durableSeq,\n );\n return [...foreign, ...own].sort((a, b) => a.seq - b.seq);\n};\n\nconst MAX_PARKED_VERDICTS = 64;\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 syncBacklogInner = (s: Session) => {\n const parked = s.shared ? s.shared.parked.splice(0) : [];\n const parkedSeqs = new Set(parked.map((v) => v.seq));\n const commands = mergeBacklog(s).filter((c) => !parkedSeqs.has(c.seq));\n const verdicts =\n parked.length > 0\n ? [...(s.record.verdicts ?? []), ...parked].slice(-MAX_PARKED_VERDICTS)\n : s.record.verdicts;\n const unchanged =\n verdicts === s.record.verdicts &&\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, {\n ...s.record,\n commands,\n ...(verdicts !== undefined && { verdicts }),\n });\n};\n\nconst syncBacklog = (s: Session) => {\n if (!s.shared) return syncBacklogInner(s);\n void transact(s, () => syncBacklogInner(s));\n};\n\n// Every record mutation over shared storage is a locked read-modify-write.\nconst transact = (s: Session, fn: () => void): Promise<void> => {\n if (!s.shared || s.deactivated) {\n fn();\n return Promise.resolve();\n }\n const shared = s.shared;\n const run = shared.txq.then(() =>\n s.store.lock!(async () => {\n const stored = s.store.load();\n if (stored !== null && stored.clientId !== s.record.clientId) {\n adoptReset(s, stored);\n } else if (stored !== null) {\n s.record = stored;\n }\n fn();\n }),\n );\n shared.txq = run.then(\n () => {},\n () => {},\n );\n return run;\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 enqueueInner(s, old.command, old.inv.params, old.resolve, old.reject);\n }\n restateContext(s);\n publish(s);\n wake(s);\n void pump(s);\n};\n\n// Another sharer replaced the record's identity: their reset settles our\n// attempted history and our survivors re-stamp on the stored clocks.\nconst adoptReset = (s: Session, stored: StatewireClient.SessionRecord) => {\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 s.record = stored;\n for (const old of survivors) {\n s.lifecycle?.onCovered?.(old.inv);\n enqueueInner(s, old.command, old.inv.params, old.resolve, old.reject);\n }\n restateContext(s);\n publish(s);\n wake(s);\n void pump(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 outcomeOf = (\n cmd: StatewireCmd,\n):\n | { ok: true; payload: unknown }\n | { ok: false; failure: StatewireClient.SendFailure } =>\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\nconst TERMINAL_CMD_TYPES = new Set([\n \"result\",\n \"rejected\",\n \"failed\",\n \"crashed\",\n \"expired\",\n]);\n\nconst parkVerdict = (s: Session, cmd: StatewireCmd) => {\n if (!s.shared || !TERMINAL_CMD_TYPES.has(cmd.type!)) return;\n s.shared.parked.push({\n seq: cmd.seq,\n type: cmd.type as StatewireClient.SessionVerdict[\"type\"],\n ...(cmd.code !== undefined && { code: cmd.code }),\n ...(cmd.message !== undefined && { message: cmd.message }),\n ...(cmd.payload !== undefined && { payload: cmd.payload }),\n ...(cmd.meta !== undefined && { meta: cmd.meta }),\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 parkVerdict(s, cmd);\n if (!entry) return;\n cover(s, entry);\n settleEntry(s, entry, outcomeOf(cmd));\n};\n\nconst consumeVerdicts = (s: Session) => {\n const verdicts = s.record.verdicts ?? [];\n const consumed = new Set<number>();\n for (const verdict of verdicts) {\n const entry = s.pending.find((p) => p.seq === verdict.seq);\n if (!entry) continue;\n consumed.add(verdict.seq);\n cover(s, entry);\n settleEntry(s, entry, outcomeOf(verdict as StatewireCmd));\n }\n if (consumed.size === 0) return;\n setRecord(s, {\n ...s.record,\n commands: s.record.commands.filter((c) => !consumed.has(c.seq)),\n verdicts: verdicts.filter((v) => !consumed.has(v.seq)),\n });\n publish(s);\n wake(s);\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 enqueueInner(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 const reconcile = () => {\n if (record === \"resumed\") {\n if (s.shared) adoptStored(s);\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 syncBacklogInner(s);\n } else {\n resetRecord(s, s.record.clientId);\n }\n s.sessionKnown = true;\n };\n if (!s.shared || s.deactivated) {\n reconcile();\n publishIngested(s);\n void pump(s);\n return;\n }\n void transact(s, reconcile).then(() => {\n publishIngested(s);\n void pump(s);\n });\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 // Superseded over shared storage: the superseder resends our backlog and\n // parks the verdicts; our promises settle from the observed record.\n if (!(s.shared && reason === \"superseded\")) {\n settleAll(s, reason === \"superseded\" ? \"superseded\" : \"gone\");\n }\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 // Shared storage: the lock across the send keeps per-lane arrival\n // ordered across sharers during attach handover.\n const send = () => transport.send(lanes.frame);\n result = await (s.shared && !s.deactivated\n ? s.store.lock!(send)\n : send());\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.shared) {\n s.shared.unsubscribe = s.store.subscribe!(() => {\n void transact(s, () => consumeVerdicts(s));\n });\n s.running = true;\n void transact(s, () => {\n if (s.store.load() === null) s.store.save(s.record);\n s.recordPersisted = true;\n adoptStored(s);\n consumeVerdicts(s);\n }).then(() => void pump(s));\n return;\n }\n if (!s.recordPersisted) {\n s.recordPersisted = true;\n s.store.save(s.record);\n }\n adoptStored(s);\n s.running = true;\n void pump(s);\n};\n\nconst stop = (s: Session) => {\n s.running = false;\n if (s.shared) {\n s.shared.unsubscribe?.();\n s.shared.unsubscribe = null;\n }\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 enqueueInner = (\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: mergeBacklog(s) });\n s.lifecycle?.onStart(entry.inv);\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 if (!s.shared) {\n enqueueInner(s, command, params, resolve, reject);\n void pump(s);\n return;\n }\n void transact(s, () =>\n enqueueInner(s, command, params, resolve, reject),\n ).then(() => 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 adoptStored = (s: Session) => {\n const known = new Set(s.pending.map((p) => p.seq));\n const stored = s.record.commands.filter((c) => !known.has(c.seq));\n if (stored.length === 0) return;\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 s.pending.sort((a, b) => a.seq - b.seq);\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 if (!s.running || isFinished(s)) return;\n const { value: encoded, meta } = encodeValue(value);\n const ops = [\n {\n op: \"replace\",\n path: [],\n value: encoded,\n ...(meta !== undefined && { meta }),\n },\n ];\n s.ctxOps = ops;\n const mint = () => {\n const seq = s.record.ctxNextSeq;\n setRecord(s, { ...s.record, ctxNextSeq: seq + 1 });\n s.ctxPending.push({ seq, ops, posted: false });\n };\n if (!s.shared) {\n mint();\n wake(s);\n void pump(s);\n return;\n }\n void transact(s, mint).then(() => {\n wake(s);\n void pump(s);\n });\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 if ((store.lock === undefined) !== (store.subscribe === undefined)) {\n throw new Error(\n \"statewire: session storage must provide lock and subscribe together\",\n );\n }\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 shared:\n store.lock !== undefined\n ? { txq: Promise.resolve(), parked: [], unsubscribe: null }\n : false,\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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"}
|
package/dist/statewire.d.ts
CHANGED
|
@@ -133,11 +133,26 @@ declare namespace StatewireClient {
|
|
|
133
133
|
nextSeq: number;
|
|
134
134
|
ctxNextSeq: number;
|
|
135
135
|
commands: readonly SessionCommand[];
|
|
136
|
+
/** Terminal verdicts parked for the sharer that minted the seq (shared storage only). */
|
|
137
|
+
verdicts?: readonly SessionVerdict[];
|
|
138
|
+
};
|
|
139
|
+
/** A terminal verdict one sharer's connection carried, parked for the sharer awaiting the seq. */
|
|
140
|
+
type SessionVerdict = {
|
|
141
|
+
seq: number;
|
|
142
|
+
type: "result" | "rejected" | "failed" | "crashed" | "expired";
|
|
143
|
+
code?: string;
|
|
144
|
+
message?: string;
|
|
145
|
+
payload?: unknown;
|
|
146
|
+
meta?: unknown;
|
|
136
147
|
};
|
|
137
148
|
/** Session storage seam; `save` must persist synchronously in the caller's flow. */
|
|
138
149
|
type SessionStorage = {
|
|
139
150
|
load: () => SessionRecord | null;
|
|
140
151
|
save: (record: SessionRecord) => void;
|
|
152
|
+
/** Serializes record mutations across sharers; presence marks the storage shared. */
|
|
153
|
+
lock?: <T>(fn: () => T | Promise<T>) => Promise<T>;
|
|
154
|
+
/** Notifies of record saves by other sharers; returns unsubscribe. Required alongside `lock`. */
|
|
155
|
+
subscribe?: (listener: () => void) => () => void;
|
|
141
156
|
};
|
|
142
157
|
/** Static headers, or a resolver invoked per request/attach; `staleAuth` is true right after an auth rejection. */
|
|
143
158
|
type HeadersOption = HeadersInit | ((ctx: {
|
package/dist/statewire.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statewire.d.ts","names":[],"sources":["../src/statewire.ts"],"mappings":";;;cA+Ba,eACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,QAAQ,QAAQ;cA8CtB,oBACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,gBAAgB,QAAQ,QAAQ;cAGtC,gBACX,QACA,kBAAkB,UAAU,WAAW,UAAU;mBAEhC;UACT;EAEI,YAAA,SAAS,gBAAgB,QAAQ,QAAQ;MAKjD,SAAS;MAIT,cAAc,gBAAgB;MAI9B,YAAY,UAAU,cAAc;MAIpC;EAIJ,WAAW,OAAO;EAIlB,UAAU;EAIV;;kBAOe;OACH,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;IAEjD,WAAW,gBAAgB,UAAU,QAAQ;;IAE7C;MACM,UAAU,gBAAgB;;;IAGhC,eAAe;IACf,aAAa,WAAW,YAAY,SAAS;IAC7C,cAAc,YAAY,YAAY;IACtC,iBACE,OAAO,YAAY,SACnB;MAAO,SAAS,UAAU;;IAE5B,mBACE,QAAQ,UAAU,cAAc,YAChC;MAAO,OAAO,YAAY;;IAE5B,sBAAsB,YAAY;;OAGxB,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;;IAGjD,OAAO;;IAEP,gBAAgB;IAChB,YAAY;IACZ,UAAU,UAAU,cAAc;;IAElC;;IAEA,aAAa,OAAO;;OAGV;IACN;;IACA;;IACA;;IAEA;IACA;IACA;IACA;IACA;IACA;;IAEA;IAAgB;IAAkB;;OAC5B,aAAa;IAAoB;;OACjC,mBAAmB;;;;;OAMnB,WACV,QACA,kBAAkB,UAAU,WAAW,UAAU,aAEjD,OAAO,QACP,SAAS,UAAU,QAAQ,YAC3B,KAAK;OAGK;IACV;IACA;IACA;;;;;;;OAQU,YAAY,WAAW,OAAO;;;;;;;;;;;;;OAc9B;IAEN;IACA;IACA;IACA;IACA;;IAEA;IAAgB;IAAiB;;IACjC;IAAiB;;IACjB;IAAiB;;IAEjB;IACA;IACA;;IAGA;IACA;;;OAIM;IACV;IACA;IACA;IACA;;;OAIU;IACV;IACA;IACA;IACA,mBAAmB;;;
|
|
1
|
+
{"version":3,"file":"statewire.d.ts","names":[],"sources":["../src/statewire.ts"],"mappings":";;;cA+Ba,eACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,QAAQ,QAAQ;cA8CtB,oBACX,QACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,QAAQ,QAAQ,eACxC,gBAAgB,gBAAgB,QAAQ,QAAQ;cAGtC,gBACX,QACA,kBAAkB,UAAU,WAAW,UAAU;mBAEhC;UACT;EAEI,YAAA,SAAS,gBAAgB,QAAQ,QAAQ;MAKjD,SAAS;MAIT,cAAc,gBAAgB;MAI9B,YAAY,UAAU,cAAc;MAIpC;EAIJ,WAAW,OAAO;EAIlB,UAAU;EAIV;;kBAOe;OACH,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;IAEjD,WAAW,gBAAgB,UAAU,QAAQ;;IAE7C;MACM,UAAU,gBAAgB;;;IAGhC,eAAe;IACf,aAAa,WAAW,YAAY,SAAS;IAC7C,cAAc,YAAY,YAAY;IACtC,iBACE,OAAO,YAAY,SACnB;MAAO,SAAS,UAAU;;IAE5B,mBACE,QAAQ,UAAU,cAAc,YAChC;MAAO,OAAO,YAAY;;IAE5B,sBAAsB,YAAY;;OAGxB,QACV,QACA,kBAAkB,UAAU,WAAW,UAAU;;IAGjD,OAAO;;IAEP,gBAAgB;IAChB,YAAY;IACZ,UAAU,UAAU,cAAc;;IAElC;;IAEA,aAAa,OAAO;;OAGV;IACN;;IACA;;IACA;;IAEA;IACA;IACA;IACA;IACA;IACA;;IAEA;IAAgB;IAAkB;;OAC5B,aAAa;IAAoB;;OACjC,mBAAmB;;;;;OAMnB,WACV,QACA,kBAAkB,UAAU,WAAW,UAAU,aAEjD,OAAO,QACP,SAAS,UAAU,QAAQ,YAC3B,KAAK;OAGK;IACV;IACA;IACA;;;;;;;OAQU,YAAY,WAAW,OAAO;;;;;;;;;;;;;OAc9B;IAEN;IACA;IACA;IACA;IACA;;IAEA;IAAgB;IAAiB;;IACjC;IAAiB;;IACjB;IAAiB;;IAEjB;IACA;IACA;;IAGA;IACA;;;OAIM;IACV;IACA;IACA;IACA;;;OAIU;IACV;IACA;IACA;IACA,mBAAmB;;IAEnB,oBAAoB;;;OAIV;IACV;IACA;IACA;IACA;IACA;IACA;;;OAIU;IACV,YAAY;IACZ,OAAO,QAAQ;;IAEf,QAAQ,GAAG,UAAU,IAAI,QAAQ,OAAO,QAAQ;;IAEhD,aAAa;;;OAIH,gBACR,gBACE;IAAO;QAAyB,cAAc,QAAQ;OAEhD;IACV,eAAe;IACf;IACA,UAAU;IACV,eAAe,WAAW;IAC1B,YAAY,YAAY;;IAExB;;OAGU;IACV,eAAe;IACf;IACA,UAAU;IACV;IACA,QACI,gCACO,yBAAyB,QAAQ;IAC5C,iBAAiB,aAAa,kCAAkC;IAChE,YAAY,YAAY;;IAExB"}
|
package/dist/statewire.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statewire.js","names":["useMemo","useRef","useState","useSyncExternalStore","createTapRoot","flushTapSync","resource","useContextProvider","useResource","useResources","withKey","ResourceElement","LIVE_CONNECTION","useStatewireCore","Statewire","SessionStorageContext","useSessionTransport","transport","session","StatewireClient","SessionStorage","SessionTransport","useStatewire","Commands","options","Options","TState","TCommands","Helpers","latest","current","storage","undefined","value","core","subscribe","listener","state","getState","isBusy","getBusy","connection","commands","CommandsProxy","setContext","contextValue","Record","Error","StatewireResource","root","disposed","constructor","ClientRoot","getValue","Connection","dispose","unmount","initialState","optimistic","Optimistic","NonNullable","materialize","Materialize","onStateChange","ctx","changes","Changes","onCommandChange","update","CommandUpdate","onConnectionChange","ConnectionState","status","cause","attempt","nextRetryAt","lastError","message","payload","reconnect","ConnectionStatus","draft","command","Command","OptimisticContext","ts","seq","clientId","SendFailure","fate","code","predecessorLost","SessionCommand","method","params","meta","SessionRecord","nextSeq","ctxNextSeq","load","save","record","HeadersOption","HeadersInit","staleAuth","Promise","SSEOptions","sessionStore","url","headers","fetch","globalThis","onChange","onDone","WSOptions","protocols","query","webSocket","WebSocket"],"sources":["../src/statewire.ts"],"sourcesContent":["import { useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport {\n createTapRoot,\n flushTapSync,\n resource,\n useContextProvider,\n useResource,\n useResources,\n withKey,\n} from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { LIVE_CONNECTION, useStatewireCore } from \"./client/core\";\nimport type { Statewire } from \"./types\";\nimport { SessionStorageContext } from \"./client/sessionStore\";\n\nconst useSessionTransport = ({\n transport,\n session,\n}: {\n transport: ResourceElement<Statewire<any, any>>;\n session: StatewireClient.SessionStorage | undefined;\n}): Statewire<unknown> =>\n useContextProvider(SessionStorageContext, session, () =>\n // oxlint-disable-next-line react-hooks/rules-of-hooks\n useResource(transport),\n );\n\n// The transport owns the session; it reads the storage off the context this\n// wrapper's own fiber provides, so plain-React callers get a provider too.\nconst SessionTransport = resource(useSessionTransport);\n\nexport const useStatewire = <\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.Options<TState, TCommands>,\n): StatewireClient.Helpers<TState, TCommands> => {\n const latest = useRef(options);\n latest.current = options;\n\n const session = useResources(\n options.storage?.session !== undefined\n ? [withKey(\"session\", options.storage.session)]\n : [],\n )[0];\n const value = useResource(\n SessionTransport({ transport: options.transport, session }),\n );\n const core = useStatewireCore(() => latest.current, value);\n const [subscribe] = useState(\n () => (listener: () => void) =>\n core.subscribe(() => flushTapSync(listener)),\n );\n\n const state = useSyncExternalStore(\n subscribe,\n core.getState,\n core.getState,\n ) as TState;\n const isBusy = useSyncExternalStore(subscribe, core.getBusy, core.getBusy);\n const connection = value.connection ?? LIVE_CONNECTION;\n\n return useMemo(\n () => ({\n state,\n getState: core.getState as () => TState,\n connection,\n commands: core.commands as Statewire.CommandsProxy<TCommands>,\n isBusy,\n setContext: (contextValue: Record<string, unknown>) => {\n if (!value.setContext) {\n throw new Error(\n \"statewire: this transport has no client context channel\",\n );\n }\n value.setContext(contextValue);\n },\n }),\n [state, isBusy, connection, core, value],\n );\n};\n\nexport const StatewireResource = <\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.Options<TState, TCommands>,\n): ResourceElement<StatewireClient.Helpers<TState, TCommands>> =>\n resource(useStatewire<TState, TCommands>)(options);\n\nexport class StatewireClient<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n> {\n private readonly root;\n private disposed = false;\n\n constructor(options: StatewireClient.Options<TState, TCommands>) {\n const ClientRoot = () => useStatewire<TState, TCommands>(options);\n this.root = createTapRoot(ClientRoot);\n }\n\n get state(): TState {\n return this.root.getValue().getState();\n }\n\n get connection(): StatewireClient.Connection {\n return this.root.getValue().connection;\n }\n\n get commands(): Statewire.CommandsProxy<TCommands> {\n return this.root.getValue().commands;\n }\n\n get isBusy(): boolean {\n return this.root.getValue().isBusy;\n }\n\n setContext(value: Record<string, unknown>): void {\n this.root.getValue().setContext(value);\n }\n\n subscribe(listener: () => void): () => void {\n return this.root.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.root.unmount();\n }\n}\n\nexport namespace StatewireClient {\n export type Options<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n > = {\n transport: ResourceElement<Statewire<TState, TCommands>>;\n /** Durable session: the mounted storage holds this client's lane identity and its un-durable commands, which resend on the next attach. */\n storage?:\n | { session?: ResourceElement<SessionStorage> | undefined }\n | undefined;\n /** Served as the canonical state until the attach snapshot; own commands fold over it. */\n initialState?: TState;\n optimistic?: Optimistic<NonNullable<TState>, TCommands>;\n materialize?: Materialize<NonNullable<TState>>;\n onStateChange?: (\n state: NonNullable<TState>,\n ctx: { changes: Statewire.Changes },\n ) => void;\n onCommandChange?: (\n update: Statewire.CommandUpdate<TCommands>,\n ctx: { state: NonNullable<TState> },\n ) => void;\n onConnectionChange?: (connection: Connection) => void;\n };\n\n export type Helpers<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n > = {\n /** The statewire's state type — remote statewires include `undefined` until the first attach snapshot applies. */\n state: TState;\n /** Identity-stable across renders; reads the current canonical state without subscribing the caller. */\n getState: () => TState;\n connection: Connection;\n commands: Statewire.CommandsProxy<TCommands>;\n /** Negation of the server's broadcast idle level (a transport without idle is always busy). */\n isBusy: boolean;\n /** Replace this client's ambient context on the server; throws on transports without a client context channel. */\n setContext: (value: Record<string, unknown>) => void;\n };\n\n export type ConnectionState =\n | { status: \"connecting\" }\n | { status: \"live\" }\n | { status: \"idle\" }\n | {\n status: \"reconnecting\";\n cause: \"dropped\" | \"evicted\" | \"error\" | \"unauthorized\";\n attempt: number;\n nextRetryAt: number;\n lastError?: string;\n message?: string;\n }\n | { status: \"gone\"; message?: string; payload?: unknown };\n export type Connection = ConnectionState & { reconnect: () => void };\n export type ConnectionStatus = Connection[\"status\"];\n\n /**\n * Mutate the draft in place; the client records the next state plus the exact\n * changed paths. Re-run against the new base on every rebase.\n */\n export type Optimistic<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n > = (\n draft: TState,\n command: Statewire.Command<TCommands>,\n ctx: OptimisticContext,\n ) => void;\n\n export type OptimisticContext = {\n ts: number;\n seq: number;\n clientId?: string;\n };\n\n /**\n * Mutate the draft to make server-accepted, still-uncommitted intents in\n * the state concrete (e.g. dispatch records into messages). Runs after the\n * optimistic folds on every published state.\n */\n export type Materialize<TState> = (draft: TState) => void;\n\n /**\n * fate: \"aborted\" = never sent, \"rejected\" = the server refused it\n * (`code` \"unknown-command\" | \"invalid-params\" for the static rejects,\n * code-less for handler rejects), \"lost\" = sent but no verdict will ever\n * arrive — the record is gone (`record: \"fresh\"`) or the channel died: it\n * may or may not have run, \"failed\" = the handler ran and threw,\n * \"crashed\" = the handler died involuntarily, \"expired\" = settled —\n * result, rejected, failed, or crashed — but the verdict outlived the\n * server's retention.\n * cause is which channel settled it: \"server\" = the server's answer;\n * the rest are channel deaths the client settled locally.\n */\n export type SendFailure =\n | {\n fate: \"rejected\";\n cause: \"server\";\n code?: string;\n message?: string;\n payload?: unknown;\n }\n | { fate: \"failed\"; cause: \"server\"; message?: string }\n | { fate: \"crashed\"; cause: \"server\" }\n | { fate: \"expired\"; cause: \"server\" }\n | {\n fate: \"aborted\";\n cause: \"unmount\" | \"stream-gone\" | \"session-lost\" | \"superseded\";\n predecessorLost?: true;\n }\n | {\n fate: \"lost\";\n cause: \"unmount\" | \"stream-gone\" | \"session-lost\" | \"superseded\";\n };\n\n /** A command as persisted while un-durable: its lane seq plus the wire statement. */\n export type SessionCommand = {\n seq: number;\n method: string;\n params: unknown[];\n meta?: unknown;\n };\n\n /** The persisted session: the lane identity, the lane clocks, and the commands the server has not marked durable. */\n export type SessionRecord = {\n clientId: string;\n nextSeq: number;\n ctxNextSeq: number;\n commands: readonly SessionCommand[];\n };\n\n /** Session storage seam; `save` must persist synchronously in the caller's flow. */\n export type SessionStorage = {\n load: () => SessionRecord | null;\n save: (record: SessionRecord) => void;\n };\n\n /** Static headers, or a resolver invoked per request/attach; `staleAuth` is true right after an auth rejection. */\n export type HeadersOption =\n | HeadersInit\n | ((ctx: { staleAuth: boolean }) => HeadersInit | Promise<HeadersInit>);\n\n export type SSEOptions = {\n sessionStore?: SessionStorage | undefined;\n url: string;\n headers?: HeadersOption;\n fetch?: typeof globalThis.fetch;\n onChange?: (connection: Connection) => void;\n /** The broadcast idle flag's rising edge: the instance went quiet. */\n onDone?: () => void;\n };\n\n export type WSOptions = {\n sessionStore?: SessionStorage | undefined;\n url: string;\n headers?: HeadersOption;\n protocols?: string | string[];\n query?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n webSocket?: new (url: string, protocols?: string | string[]) => WebSocket;\n onChange?: (connection: Connection) => void;\n /** The broadcast idle flag's rising edge: the instance went quiet. */\n onDone?: () => void;\n };\n}\n"],"mappings":";;;;;AAeA,MAAMgB,uBAAuB,EAC3BC,WACAC,cAKAX,mBAAmBQ,uBAAuBG,eAExCV,YAAYS,SAAS,CACvB;AAIF,MAAMI,mBAAmBf,SAASU,mBAAmB;AAErD,MAAaM,gBAIXE,YAC+C;CAC/C,MAAMK,SAAS5B,OAAOuB,OAAO;CAC7BK,OAAOC,UAAUN;CAEjB,MAAMN,UAAUT,aACde,QAAQO,SAASb,YAAYc,KAAAA,IACzB,CAACtB,QAAQ,WAAWc,QAAQO,QAAQb,OAAO,CAAC,IAC5C,CAAA,CACN,CAAC,CAAC;CACF,MAAMe,QAAQzB,YACZa,iBAAiB;EAAEJ,WAAWO,QAAQP;EAAWC;CAAQ,CAAC,CAC5D;CACA,MAAMgB,OAAOrB,uBAAuBgB,OAAOC,SAASG,KAAK;CACzD,MAAM,CAACE,aAAajC,gBACXkC,aACLF,KAAKC,gBAAgB9B,aAAa+B,QAAQ,CAAC,CAC/C;CAEA,MAAMC,QAAQlC,qBACZgC,WACAD,KAAKI,UACLJ,KAAKI,QACP;CACA,MAAMC,SAASpC,qBAAqBgC,WAAWD,KAAKM,SAASN,KAAKM,OAAO;CACzE,MAAMC,aAAaR,MAAMQ,cAAc7B;CAEvC,OAAOZ,eACE;EACLqC;EACAC,UAAUJ,KAAKI;EACfG;EACAC,UAAUR,KAAKQ;EACfH;EACAK,aAAaC,iBAA0C;GACrD,IAAI,CAACZ,MAAMW,YACT,MAAM,IAAIG,MACR,yDACF;GAEFd,MAAMW,WAAWC,YAAY;EAC/B;CACF,IACA;EAACR;EAAOE;EAAQE;EAAYP;EAAMD;CAAK,CACzC;AACF;AAEA,MAAae,qBAIXxB,YAEAlB,SAASgB,YAA+B,CAAC,CAACE,OAAO;AAEnD,IAAaL,kBAAb,MAGE;CACA;CACA,WAAmB;CAEnBgC,YAAY3B,SAAqD;EAC/D,MAAM4B,mBAAmB9B,aAAgCE,OAAO;EAChE,KAAKyB,OAAO7C,cAAcgD,UAAU;CACtC;CAEA,IAAIf,QAAgB;EAClB,OAAO,KAAKY,KAAKI,SAAS,CAAC,CAACf,SAAS;CACvC;CAEA,IAAIG,aAAyC;EAC3C,OAAO,KAAKQ,KAAKI,SAAS,CAAC,CAACZ;CAC9B;CAEA,IAAIC,WAA+C;EACjD,OAAO,KAAKO,KAAKI,SAAS,CAAC,CAACX;CAC9B;CAEA,IAAIH,SAAkB;EACpB,OAAO,KAAKU,KAAKI,SAAS,CAAC,CAACd;CAC9B;CAEAK,WAAWX,OAAsC;EAC/C,KAAKgB,KAAKI,SAAS,CAAC,CAACT,WAAWX,KAAK;CACvC;CAEAE,UAAUC,UAAkC;EAC1C,OAAO,KAAKa,KAAKd,UAAUC,QAAQ;CACrC;CAEAmB,UAAgB;EACd,IAAI,KAAKL,UAAU;EACnB,KAAKA,WAAW;EAChB,KAAKD,KAAKO,QAAQ;CACpB;AACF"}
|
|
1
|
+
{"version":3,"file":"statewire.js","names":["useMemo","useRef","useState","useSyncExternalStore","createTapRoot","flushTapSync","resource","useContextProvider","useResource","useResources","withKey","ResourceElement","LIVE_CONNECTION","useStatewireCore","Statewire","SessionStorageContext","useSessionTransport","transport","session","StatewireClient","SessionStorage","SessionTransport","useStatewire","Commands","options","Options","TState","TCommands","Helpers","latest","current","storage","undefined","value","core","subscribe","listener","state","getState","isBusy","getBusy","connection","commands","CommandsProxy","setContext","contextValue","Record","Error","StatewireResource","root","disposed","constructor","ClientRoot","getValue","Connection","dispose","unmount","initialState","optimistic","Optimistic","NonNullable","materialize","Materialize","onStateChange","ctx","changes","Changes","onCommandChange","update","CommandUpdate","onConnectionChange","ConnectionState","status","cause","attempt","nextRetryAt","lastError","message","payload","reconnect","ConnectionStatus","draft","command","Command","OptimisticContext","ts","seq","clientId","SendFailure","fate","code","predecessorLost","SessionCommand","method","params","meta","SessionRecord","nextSeq","ctxNextSeq","verdicts","SessionVerdict","type","load","save","record","lock","fn","T","Promise","HeadersOption","HeadersInit","staleAuth","SSEOptions","sessionStore","url","headers","fetch","globalThis","onChange","onDone","WSOptions","protocols","query","webSocket","WebSocket"],"sources":["../src/statewire.ts"],"sourcesContent":["import { useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport {\n createTapRoot,\n flushTapSync,\n resource,\n useContextProvider,\n useResource,\n useResources,\n withKey,\n} from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { LIVE_CONNECTION, useStatewireCore } from \"./client/core\";\nimport type { Statewire } from \"./types\";\nimport { SessionStorageContext } from \"./client/sessionStore\";\n\nconst useSessionTransport = ({\n transport,\n session,\n}: {\n transport: ResourceElement<Statewire<any, any>>;\n session: StatewireClient.SessionStorage | undefined;\n}): Statewire<unknown> =>\n useContextProvider(SessionStorageContext, session, () =>\n // oxlint-disable-next-line react-hooks/rules-of-hooks\n useResource(transport),\n );\n\n// The transport owns the session; it reads the storage off the context this\n// wrapper's own fiber provides, so plain-React callers get a provider too.\nconst SessionTransport = resource(useSessionTransport);\n\nexport const useStatewire = <\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.Options<TState, TCommands>,\n): StatewireClient.Helpers<TState, TCommands> => {\n const latest = useRef(options);\n latest.current = options;\n\n const session = useResources(\n options.storage?.session !== undefined\n ? [withKey(\"session\", options.storage.session)]\n : [],\n )[0];\n const value = useResource(\n SessionTransport({ transport: options.transport, session }),\n );\n const core = useStatewireCore(() => latest.current, value);\n const [subscribe] = useState(\n () => (listener: () => void) =>\n core.subscribe(() => flushTapSync(listener)),\n );\n\n const state = useSyncExternalStore(\n subscribe,\n core.getState,\n core.getState,\n ) as TState;\n const isBusy = useSyncExternalStore(subscribe, core.getBusy, core.getBusy);\n const connection = value.connection ?? LIVE_CONNECTION;\n\n return useMemo(\n () => ({\n state,\n getState: core.getState as () => TState,\n connection,\n commands: core.commands as Statewire.CommandsProxy<TCommands>,\n isBusy,\n setContext: (contextValue: Record<string, unknown>) => {\n if (!value.setContext) {\n throw new Error(\n \"statewire: this transport has no client context channel\",\n );\n }\n value.setContext(contextValue);\n },\n }),\n [state, isBusy, connection, core, value],\n );\n};\n\nexport const StatewireResource = <\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.Options<TState, TCommands>,\n): ResourceElement<StatewireClient.Helpers<TState, TCommands>> =>\n resource(useStatewire<TState, TCommands>)(options);\n\nexport class StatewireClient<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n> {\n private readonly root;\n private disposed = false;\n\n constructor(options: StatewireClient.Options<TState, TCommands>) {\n const ClientRoot = () => useStatewire<TState, TCommands>(options);\n this.root = createTapRoot(ClientRoot);\n }\n\n get state(): TState {\n return this.root.getValue().getState();\n }\n\n get connection(): StatewireClient.Connection {\n return this.root.getValue().connection;\n }\n\n get commands(): Statewire.CommandsProxy<TCommands> {\n return this.root.getValue().commands;\n }\n\n get isBusy(): boolean {\n return this.root.getValue().isBusy;\n }\n\n setContext(value: Record<string, unknown>): void {\n this.root.getValue().setContext(value);\n }\n\n subscribe(listener: () => void): () => void {\n return this.root.subscribe(listener);\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.root.unmount();\n }\n}\n\nexport namespace StatewireClient {\n export type Options<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n > = {\n transport: ResourceElement<Statewire<TState, TCommands>>;\n /** Durable session: the mounted storage holds this client's lane identity and its un-durable commands, which resend on the next attach. */\n storage?:\n | { session?: ResourceElement<SessionStorage> | undefined }\n | undefined;\n /** Served as the canonical state until the attach snapshot; own commands fold over it. */\n initialState?: TState;\n optimistic?: Optimistic<NonNullable<TState>, TCommands>;\n materialize?: Materialize<NonNullable<TState>>;\n onStateChange?: (\n state: NonNullable<TState>,\n ctx: { changes: Statewire.Changes },\n ) => void;\n onCommandChange?: (\n update: Statewire.CommandUpdate<TCommands>,\n ctx: { state: NonNullable<TState> },\n ) => void;\n onConnectionChange?: (connection: Connection) => void;\n };\n\n export type Helpers<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n > = {\n /** The statewire's state type — remote statewires include `undefined` until the first attach snapshot applies. */\n state: TState;\n /** Identity-stable across renders; reads the current canonical state without subscribing the caller. */\n getState: () => TState;\n connection: Connection;\n commands: Statewire.CommandsProxy<TCommands>;\n /** Negation of the server's broadcast idle level (a transport without idle is always busy). */\n isBusy: boolean;\n /** Replace this client's ambient context on the server; throws on transports without a client context channel. */\n setContext: (value: Record<string, unknown>) => void;\n };\n\n export type ConnectionState =\n | { status: \"connecting\" }\n | { status: \"live\" }\n | { status: \"idle\" }\n | {\n status: \"reconnecting\";\n cause: \"dropped\" | \"evicted\" | \"error\" | \"unauthorized\";\n attempt: number;\n nextRetryAt: number;\n lastError?: string;\n message?: string;\n }\n | { status: \"gone\"; message?: string; payload?: unknown };\n export type Connection = ConnectionState & { reconnect: () => void };\n export type ConnectionStatus = Connection[\"status\"];\n\n /**\n * Mutate the draft in place; the client records the next state plus the exact\n * changed paths. Re-run against the new base on every rebase.\n */\n export type Optimistic<\n TState,\n TCommands extends Statewire.Commands = Statewire.Commands,\n > = (\n draft: TState,\n command: Statewire.Command<TCommands>,\n ctx: OptimisticContext,\n ) => void;\n\n export type OptimisticContext = {\n ts: number;\n seq: number;\n clientId?: string;\n };\n\n /**\n * Mutate the draft to make server-accepted, still-uncommitted intents in\n * the state concrete (e.g. dispatch records into messages). Runs after the\n * optimistic folds on every published state.\n */\n export type Materialize<TState> = (draft: TState) => void;\n\n /**\n * fate: \"aborted\" = never sent, \"rejected\" = the server refused it\n * (`code` \"unknown-command\" | \"invalid-params\" for the static rejects,\n * code-less for handler rejects), \"lost\" = sent but no verdict will ever\n * arrive — the record is gone (`record: \"fresh\"`) or the channel died: it\n * may or may not have run, \"failed\" = the handler ran and threw,\n * \"crashed\" = the handler died involuntarily, \"expired\" = settled —\n * result, rejected, failed, or crashed — but the verdict outlived the\n * server's retention.\n * cause is which channel settled it: \"server\" = the server's answer;\n * the rest are channel deaths the client settled locally.\n */\n export type SendFailure =\n | {\n fate: \"rejected\";\n cause: \"server\";\n code?: string;\n message?: string;\n payload?: unknown;\n }\n | { fate: \"failed\"; cause: \"server\"; message?: string }\n | { fate: \"crashed\"; cause: \"server\" }\n | { fate: \"expired\"; cause: \"server\" }\n | {\n fate: \"aborted\";\n cause: \"unmount\" | \"stream-gone\" | \"session-lost\" | \"superseded\";\n predecessorLost?: true;\n }\n | {\n fate: \"lost\";\n cause: \"unmount\" | \"stream-gone\" | \"session-lost\" | \"superseded\";\n };\n\n /** A command as persisted while un-durable: its lane seq plus the wire statement. */\n export type SessionCommand = {\n seq: number;\n method: string;\n params: unknown[];\n meta?: unknown;\n };\n\n /** The persisted session: the lane identity, the lane clocks, and the commands the server has not marked durable. */\n export type SessionRecord = {\n clientId: string;\n nextSeq: number;\n ctxNextSeq: number;\n commands: readonly SessionCommand[];\n /** Terminal verdicts parked for the sharer that minted the seq (shared storage only). */\n verdicts?: readonly SessionVerdict[];\n };\n\n /** A terminal verdict one sharer's connection carried, parked for the sharer awaiting the seq. */\n export type SessionVerdict = {\n seq: number;\n type: \"result\" | \"rejected\" | \"failed\" | \"crashed\" | \"expired\";\n code?: string;\n message?: string;\n payload?: unknown;\n meta?: unknown;\n };\n\n /** Session storage seam; `save` must persist synchronously in the caller's flow. */\n export type SessionStorage = {\n load: () => SessionRecord | null;\n save: (record: SessionRecord) => void;\n /** Serializes record mutations across sharers; presence marks the storage shared. */\n lock?: <T>(fn: () => T | Promise<T>) => Promise<T>;\n /** Notifies of record saves by other sharers; returns unsubscribe. Required alongside `lock`. */\n subscribe?: (listener: () => void) => () => void;\n };\n\n /** Static headers, or a resolver invoked per request/attach; `staleAuth` is true right after an auth rejection. */\n export type HeadersOption =\n | HeadersInit\n | ((ctx: { staleAuth: boolean }) => HeadersInit | Promise<HeadersInit>);\n\n export type SSEOptions = {\n sessionStore?: SessionStorage | undefined;\n url: string;\n headers?: HeadersOption;\n fetch?: typeof globalThis.fetch;\n onChange?: (connection: Connection) => void;\n /** The broadcast idle flag's rising edge: the instance went quiet. */\n onDone?: () => void;\n };\n\n export type WSOptions = {\n sessionStore?: SessionStorage | undefined;\n url: string;\n headers?: HeadersOption;\n protocols?: string | string[];\n query?:\n | Record<string, string>\n | (() => Record<string, string> | Promise<Record<string, string>>);\n webSocket?: new (url: string, protocols?: string | string[]) => WebSocket;\n onChange?: (connection: Connection) => void;\n /** The broadcast idle flag's rising edge: the instance went quiet. */\n onDone?: () => void;\n };\n}\n"],"mappings":";;;;;AAeA,MAAMgB,uBAAuB,EAC3BC,WACAC,cAKAX,mBAAmBQ,uBAAuBG,eAExCV,YAAYS,SAAS,CACvB;AAIF,MAAMI,mBAAmBf,SAASU,mBAAmB;AAErD,MAAaM,gBAIXE,YAC+C;CAC/C,MAAMK,SAAS5B,OAAOuB,OAAO;CAC7BK,OAAOC,UAAUN;CAEjB,MAAMN,UAAUT,aACde,QAAQO,SAASb,YAAYc,KAAAA,IACzB,CAACtB,QAAQ,WAAWc,QAAQO,QAAQb,OAAO,CAAC,IAC5C,CAAA,CACN,CAAC,CAAC;CACF,MAAMe,QAAQzB,YACZa,iBAAiB;EAAEJ,WAAWO,QAAQP;EAAWC;CAAQ,CAAC,CAC5D;CACA,MAAMgB,OAAOrB,uBAAuBgB,OAAOC,SAASG,KAAK;CACzD,MAAM,CAACE,aAAajC,gBACXkC,aACLF,KAAKC,gBAAgB9B,aAAa+B,QAAQ,CAAC,CAC/C;CAEA,MAAMC,QAAQlC,qBACZgC,WACAD,KAAKI,UACLJ,KAAKI,QACP;CACA,MAAMC,SAASpC,qBAAqBgC,WAAWD,KAAKM,SAASN,KAAKM,OAAO;CACzE,MAAMC,aAAaR,MAAMQ,cAAc7B;CAEvC,OAAOZ,eACE;EACLqC;EACAC,UAAUJ,KAAKI;EACfG;EACAC,UAAUR,KAAKQ;EACfH;EACAK,aAAaC,iBAA0C;GACrD,IAAI,CAACZ,MAAMW,YACT,MAAM,IAAIG,MACR,yDACF;GAEFd,MAAMW,WAAWC,YAAY;EAC/B;CACF,IACA;EAACR;EAAOE;EAAQE;EAAYP;EAAMD;CAAK,CACzC;AACF;AAEA,MAAae,qBAIXxB,YAEAlB,SAASgB,YAA+B,CAAC,CAACE,OAAO;AAEnD,IAAaL,kBAAb,MAGE;CACA;CACA,WAAmB;CAEnBgC,YAAY3B,SAAqD;EAC/D,MAAM4B,mBAAmB9B,aAAgCE,OAAO;EAChE,KAAKyB,OAAO7C,cAAcgD,UAAU;CACtC;CAEA,IAAIf,QAAgB;EAClB,OAAO,KAAKY,KAAKI,SAAS,CAAC,CAACf,SAAS;CACvC;CAEA,IAAIG,aAAyC;EAC3C,OAAO,KAAKQ,KAAKI,SAAS,CAAC,CAACZ;CAC9B;CAEA,IAAIC,WAA+C;EACjD,OAAO,KAAKO,KAAKI,SAAS,CAAC,CAACX;CAC9B;CAEA,IAAIH,SAAkB;EACpB,OAAO,KAAKU,KAAKI,SAAS,CAAC,CAACd;CAC9B;CAEAK,WAAWX,OAAsC;EAC/C,KAAKgB,KAAKI,SAAS,CAAC,CAACT,WAAWX,KAAK;CACvC;CAEAE,UAAUC,UAAkC;EAC1C,OAAO,KAAKa,KAAKd,UAAUC,QAAQ;CACrC;CAEAmB,UAAgB;EACd,IAAI,KAAKL,UAAU;EACnB,KAAKA,WAAW;EAChB,KAAKD,KAAKO,QAAQ;CACpB;AACF"}
|