statewire 0.15.0 → 0.16.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/README.md CHANGED
@@ -11,7 +11,7 @@ pnpm add statewire react
11
11
  ## Use
12
12
 
13
13
  ```tsx
14
- import { StatewireSSE, useStatewire } from "statewire";
14
+ import { StatewireHttp, useStatewire } from "statewire";
15
15
 
16
16
  type CounterState = { count: number };
17
17
  type CounterCommands = { increment(): void; reset(): void };
@@ -20,7 +20,7 @@ export const App = () => {
20
20
  const { state, connection, commands } = useStatewire<
21
21
  CounterState | undefined,
22
22
  CounterCommands
23
- >({ transport: StatewireSSE({ url: "/threads/main" }) });
23
+ >({ transport: StatewireHttp({ url: "/threads/main" }) });
24
24
  return (
25
25
  <main>
26
26
  <p>{connection.status}</p>
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":";;;;;;;KAgCK;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,gBAAgB,gBAAgB;EAChC;;KAGG;EACH,KAAK;EACL,QAAQ,gBAAgB;EACxB;;KAGG;EACH,QAAQ,gBAAgB;EACxB,KAAK;EACL;EACA,OAAO,gBAAgB;EACvB,QAAQ;EACR;;EAEA;EACA;EACA;EACA;EACA;EACA,eAAe,gBAAgB;EAC/B;EACA;EACA,YAAY;EACZ;EACA,0BAA0B,qBAAqB;EAC/C;EACA,SAAS;EACT;EACA,WAAW,mBAAmB;EAC9B;EACA,SAAS;EACT,QAAQ,UAAU;EAClB,QAAQ;EACR;EACA;EACA;EACA,WAAW;EACX;EACA,WAAW;EACX;EACA,UAAU,mBAAmB,sBAAsB;;cAwHxC,iBACX,GAAG,qBACO,gBAAgB;cAklBtB,eAAgB,GAAG,SAAS,WAAW;cAkJhC,gBACX,GAAG,SACH,OAAO,gBAAgB;cAYZ,cACX,GAAG,SACH,OAAO,gBAAgB,kBACtB;cA0DG,aAAc,GAAG,SAAS,OAAO;cAmC1B,sBACX,SAAS,4BACR"}
1
+ {"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":";;;;;;;KAgCK;EACH;EACA;EACA;;KAGG;WACM;WACA,SAAS;WACT,KAAK;;EAEd;;EAEA;;EAEA;EACA,UAAU;EACV,SAAS,OAAO;;KAGb;WACM;WACA;EACT;;KAeG;KAEO;EACV,eAAe,gBAAgB;EAC/B,gBAAgB,gBAAgB;EAChC;;KAGG;EACH,KAAK;EACL,QAAQ,gBAAgB;EACxB;;KAGG;EACH,QAAQ,gBAAgB;EACxB,KAAK;EACL;EACA,OAAO,gBAAgB;EACvB,QAAQ;EACR;;EAEA;EACA;EACA;EACA;EACA;EACA,eAAe,gBAAgB;EAC/B;EACA;EACA,YAAY;EACZ;EACA,0BAA0B,qBAAqB;EAC/C;EACA,SAAS;EACT;EACA,WAAW,mBAAmB;EAC9B;EACA,SAAS;EACT,QAAQ,UAAU;EAClB,QAAQ;EACR;EACA;EACA;EACA,WAAW;EACX;EACA,WAAW;EACX;EACA,UAAU,mBAAmB,sBAAsB;;cAwHxC,iBACX,GAAG,qBACO,gBAAgB;cAklBtB,eAAgB,GAAG,SAAS,WAAW;cAkJhC,gBACX,GAAG,SACH,OAAO,gBAAgB;cAYZ,cACX,GAAG,SACH,OAAO,gBAAgB,kBACtB;cA0DG,aAAc,GAAG,SAAS,OAAO;cAmC1B,sBACX,SAAS,4BACR"}
@@ -13,7 +13,6 @@ import { useContext, useEffect, useState } from "@assistant-ui/tap/react-shim";
13
13
  const protocolError = (message) => {
14
14
  throw new Error(`statewire: protocol error: ${message}`);
15
15
  };
16
- const newClientId = () => `c-${randomId()}`;
17
16
  const rejectedSend = (failure) => {
18
17
  const result = Promise.reject(new StatewireSendError(failure));
19
18
  result.catch(() => {});
@@ -225,7 +224,7 @@ const adoptReset = (s, stored) => rebaseRecord(s, () => {
225
224
  const ephemeralDetach = (s) => {
226
225
  s.ephemeral = false;
227
226
  s.sessionKnown = false;
228
- resetRecord(s, newClientId());
227
+ resetRecord(s, randomId());
229
228
  };
230
229
  const rejectedFailure = (cmd) => {
231
230
  return {
@@ -813,7 +812,7 @@ const useStatewireSession = (options) => {
813
812
  if (stored !== null && !Array.isArray(stored.commands)) throw new Error("statewire: session storage loaded a record without a commands array");
814
813
  const session = {
815
814
  record: stored ?? {
816
- clientId: newClientId(),
815
+ clientId: randomId(),
817
816
  nextSeq: 1,
818
817
  ctxNextSeq: 1,
819
818
  commands: []
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":["applyDocumentOps","StatewireDocuments","useContext","useEffect","useState","StatewirePath","MAX_COMMANDS_PER_FRAME","TERMINAL","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","onSessionLost","OnSessionLost","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","documents","State","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","NO_FAILED","FailedCommand","failedCommands","failed","retainFailedInner","ts","retainFailed","settleEntry","outcome","ok","onSettle","type","rides","cause","settleAll","detach","const","batch","detachFailure","predecessorLost","some","fate","restateContext","ctxNextSeq","settleLost","entries","rebaseRecord","adopt","held","survivors","old","enqueueInner","pump","resetRecord","nextSeq","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","get","value","changedPaths","publishIngested","snapCtxClock","ctxWm","ctxAligned","sessionLostInner","seqWm","handleHello","syn","mode","Map","attachCmd","attachCtx","reconcile","adoptStored","ctxWatermark","ctxSeq","handleOps","handleRefusal","watermark","retry","Date","now","firstCmd","firstCtx","cmdGap","ctxGap","handleDetach","handleFinish","reason","isFinished","Lanes","frame","cmdEntries","ctxEntries","buildLanes","at","takeAttachLanes","wanted","lanes","connection","status","reconnect","resumeDelay","epoch","send","includes","onPosted","start","subscribe","stop","setTransport","onStart","enqueue","sendCommand","encoded","findFailed","f","unknownFailed","takeFailed","found","discardFailed","retryFailed","current","setContext","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 { applyDocumentOps } from \"../wire/documents\";\nimport type { StatewireDocuments } from \"../wire/documents\";\nimport { useContext, useEffect, useState } from \"react\";\n\nimport type { StatewirePath } from \"../wire/ops\";\nimport { MAX_COMMANDS_PER_FRAME } from \"../wire/limits\";\nimport { TERMINAL } from \"./connection\";\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 onSessionLost?: StatewireClient.OnSessionLost | 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 onSessionLost: StatewireClient.OnSessionLost | undefined;\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 documents: StatewireDocuments.State;\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 NO_FAILED: readonly StatewireClient.FailedCommand[] = [];\n\nexport const failedCommands = (\n s: Session,\n): readonly StatewireClient.FailedCommand[] => s.record.failed ?? NO_FAILED;\n\nconst retainFailedInner = (\n s: Session,\n entry: Pending,\n failure: StatewireClient.SendFailure,\n) => {\n setRecord(s, {\n ...s.record,\n failed: [\n ...(s.record.failed ?? []),\n {\n command: entry.command.method,\n params: entry.command.params,\n ...(entry.command.meta !== undefined && { meta: entry.command.meta }),\n failure,\n ts: entry.inv.ts,\n seq: entry.seq,\n },\n ],\n });\n s.notify();\n};\n\nconst retainFailed = (\n s: Session,\n entry: Pending,\n failure: StatewireClient.SendFailure,\n) => {\n if (!s.shared) {\n retainFailedInner(s, entry, failure);\n return;\n }\n void transact(s, () => retainFailedInner(s, entry, failure));\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 // A statement the record still carries resends on the next attach; only\n // invocations the record no longer owns become failed history.\n const rides =\n (outcome.failure.cause === \"unmount\" ||\n outcome.failure.cause === \"stream-gone\") &&\n entry.seq > s.durableSeq;\n if (!rides) retainFailed(s, entry, outcome.failure);\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\") => {\n const cause =\n detach === \"unmount\" ? (\"unmount\" as const) : (\"stream-gone\" as const);\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\nconst settleLost = (s: Session, entries: Pending[]) => {\n for (const entry of entries) {\n s.lifecycle?.onCovered?.(entry.inv);\n settleEntry(s, entry, {\n ok: false,\n failure: { fate: \"lost\", cause: \"session-lost\" },\n });\n }\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// on the adopted lane clocks.\nconst rebaseRecord = (s: Session, adopt: () => void) => {\n const held = [...s.pending];\n const survivors = held.filter((p) => !p.attempted && !p.applied);\n settleLost(\n s,\n held.filter((p) => p.attempted || p.applied),\n );\n s.pending = [];\n s.durableSeq = 0;\n // Failed entries are user-owned history: they ride through every record replacement.\n const failed = s.record.failed;\n adopt();\n if (failed !== undefined && s.record.failed !== failed) {\n setRecord(s, {\n ...s.record,\n failed: [...(s.record.failed ?? []), ...failed],\n });\n }\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\nconst resetRecord = (s: Session, clientId: string) =>\n rebaseRecord(s, () =>\n setRecord(s, { clientId, nextSeq: 1, ctxNextSeq: 1, commands: [] }),\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 rebaseRecord(s, () => {\n s.record = stored;\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 switch (cmd.type) {\n case \"result\":\n return { ok: true, payload: reviveResponse(cmd).payload };\n case \"rejected\":\n return { ok: false, failure: rejectedFailure(reviveResponse(cmd)) };\n case \"failed\":\n return {\n ok: false,\n failure: {\n fate: \"failed\",\n cause: \"server\",\n ...(cmd.message !== undefined && { message: cmd.message }),\n },\n };\n case \"crashed\":\n return { ok: false, failure: { fate: \"crashed\", cause: \"server\" } };\n case \"expired\":\n return { ok: false, failure: { fate: \"expired\", cause: \"server\" } };\n default:\n return protocolError(`unknown cmd type: ${String(cmd.type)}`);\n }\n};\n\nconst TERMINAL_CMD_TYPES: ReadonlySet<string> = new Set(TERMINAL);\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 = applyDocumentOps(s.documents, ops);\n s.documents = applied;\n s.canonical = applied.documents.get(0)?.value;\n s.changed.push(...applied.changedPaths);\n};\n\nconst publishIngested = (s: Session) => {\n publish(s);\n wake(s);\n};\n\n// A hello's cmd watermark may understate a durable record (cold host, tray\n// unloaded): held seqs resend as-is and the frame's answer arbitrates —\n// absorption where the record survived, a gap refusal where it did not.\nconst snapCtxClock = (s: Session, ctxWm: number) => {\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\n// The refusal's watermarks are exact: every held statement above them was\n// never admitted by the live record, and the first unposted seq being beyond\n// watermark+1 proves the record that admitted the missing prefix is gone —\n// its history settles lost and the lane clocks restart at the watermarks.\nconst sessionLostInner = (s: Session, seqWm: number, ctxWm: number) => {\n const held = [...s.pending];\n settleLost(s, held);\n s.pending = [];\n s.durableSeq = seqWm;\n setRecord(s, {\n clientId: s.record.clientId,\n nextSeq: seqWm + 1,\n ctxNextSeq: ctxWm + 1,\n commands: [],\n ...(s.record.failed !== undefined && { failed: s.record.failed }),\n });\n restateContext(s);\n if (\n held.length > 0 &&\n s.onSessionLost?.(held.map((p) => p.inv)) === \"requeue\"\n ) {\n for (const old of held) {\n enqueueInner(\n s,\n old.command,\n old.inv.params,\n () => {},\n () => {},\n );\n }\n }\n publish(s);\n wake(s);\n};\n\nconst handleHello = (\n s: Session,\n { ops, syn }: { ops: unknown[]; syn: StatewireSyn },\n) => {\n if (syn.record !== undefined && syn.record !== \"ephemeral\") {\n protocolError(`unknown record: ${String(syn.record)}`);\n }\n s.documents = { mode: null, documents: new Map() };\n ingestOps(s, ops);\n s.attach = \"attached\";\n s.attachEpoch += 1;\n s.frameFailures = 0;\n s.resumeAt = 0;\n s.ephemeral = syn.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 (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 s.durableSeq = syn.seq ?? 0;\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 snapCtxClock(s, ctxWatermark);\n syncBacklogInner(s);\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 retry-less {syn} refusal is the one session-loss verdict: a cmd gap\n// against its exact watermark settles the held history lost; a pushback\n// (retry present) or a gapless refusal only reconciles the resend queues.\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 wake(s);\n void pump(s);\n return;\n }\n const firstCmd = s.pending.find((p) => !p.posted);\n const firstCtx = s.ctxPending.find((c) => !c.posted);\n const cmdGap =\n typeof seq === \"number\" &&\n firstCmd !== undefined &&\n firstCmd.seq > Math.max(seq, s.durableSeq) + 1;\n const ctxGap =\n typeof ctxSeq === \"number\" &&\n firstCtx !== undefined &&\n firstCtx.seq > ctxSeq + 1;\n if (cmdGap || ctxGap) {\n void transact(s, () => {\n if (cmdGap) sessionLostInner(s, seq!, ctxSeq ?? 0);\n else snapCtxClock(s, ctxSeq!);\n }).then(() => {\n wake(s);\n void pump(s);\n });\n return;\n }\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 === \"reconnect\" || reason === \"error\") return;\n s.attach = \"finished\";\n settleAll(s, \"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 >= MAX_COMMANDS_PER_FRAME) break;\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 >= MAX_COMMANDS_PER_FRAME) break;\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 (\n (transport?.connection.status === \"disconnected\" &&\n transport.connection.reason === \"idle\") ||\n (transport?.parked && s.pending.length > 0)\n ) {\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 wake(s);\n void pump(s);\n return;\n }\n void transact(s, () => {\n if (!s.running) {\n reject(new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }));\n return;\n }\n if (isFinished(s)) {\n reject(new StatewireSendError({ fate: \"aborted\", cause: \"stream-gone\" }));\n return;\n }\n enqueueInner(s, command, params, resolve, reject);\n }).then(() => {\n wake(s);\n void pump(s);\n });\n};\n\n// A stored command may have reached a server: attempted settles it lost,\n// never aborted, when a channel death ends the session.\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 findFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\n): StatewireClient.FailedCommand | undefined =>\n (s.record.failed ?? []).find(\n (f) =>\n f.seq === entry.seq && f.ts === entry.ts && f.command === entry.command,\n );\n\nconst unknownFailed = (entry: StatewireClient.FailedCommand) =>\n new Error(`statewire: unknown failed command \"${entry.command}\"`);\n\nconst takeFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\n): StatewireClient.FailedCommand => {\n const failed = s.record.failed ?? [];\n const found = findFailed(s, entry);\n if (found === undefined) throw unknownFailed(entry);\n setRecord(s, { ...s.record, failed: failed.filter((f) => f !== found) });\n s.notify();\n return found;\n};\n\nexport const discardFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\n): void => {\n if (!s.shared) {\n takeFailed(s, entry);\n return;\n }\n if (findFailed(s, entry) === undefined) throw unknownFailed(entry);\n void transact(s, () => {\n if (findFailed(s, entry) !== undefined) takeFailed(s, entry);\n });\n};\n\nexport const retryFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\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 found = findFailed(s, entry);\n if (found === undefined) throw unknownFailed(entry);\n const params =\n found.meta === undefined\n ? found.params\n : (reviveValue([...found.params], found.meta) as unknown[]);\n const result = new Promise<unknown>((resolve, reject) => {\n const retry = () => {\n if (!s.running) {\n reject(new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }));\n return;\n }\n if (isFinished(s)) {\n reject(\n new StatewireSendError({ fate: \"aborted\", cause: \"stream-gone\" }),\n );\n return;\n }\n const current = findFailed(s, entry);\n if (current === undefined) {\n reject(unknownFailed(entry));\n return;\n }\n takeFailed(s, current);\n enqueueInner(\n s,\n {\n method: current.command,\n params: [...current.params],\n ...(current.meta !== undefined && { meta: current.meta }),\n },\n params,\n resolve,\n reject,\n );\n };\n if (!s.shared) {\n retry();\n wake(s);\n void pump(s);\n return;\n }\n void transact(s, retry).then(() => {\n wake(s);\n void pump(s);\n }, reject);\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, () => {\n if (!s.running || isFinished(s)) return;\n mint();\n }).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 onSessionLost: undefined,\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 documents: { mode: null, documents: new Map() },\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 if ((store.lock !== undefined) !== (s.shared !== false)) {\n throw new Error(\n \"statewire: session storage changed sharedness across renders — lock/subscribe must be present from the first render or never\",\n );\n }\n s.store = store;\n s.onSessionLost = options.onSessionLost;\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":";;;;;;;;;;;;AA0DA,MAAM6C,iBAAiBC,YAA2B;CAChD,MAAM,IAAIC,MAAM,8BAA8BD,SAAS;AACzD;AAEA,MAAME,oBAAoB,KAAKzB,SAAS;AAExC,MAAM0B,gBACJC,YACqB;CACrB,MAAMG,SAASD,QAAQX,OAAgB,IAAIjB,mBAAmB0B,OAAO,CAAC;CACtEG,OAAOC,YAAY,CAAC,CAAC;CACrB,OAAOD;AACT;AAqDA,MAAMmD,WAAWC,MAAe;CAC9B,IAAIA,EAAElB,cAAckB,EAAEf,eAAe;CACrCe,EAAEf,gBAAgBe,EAAElB;CACpBkB,EAAEJ,OAAO;AACX;AAEA,MAAMK,QAAQD,MAAe;CAC3B,MAAMN,UAAUM,EAAEN;CAClBM,EAAEN,UAAU,CAAA;CACZ,KAAK,MAAMQ,UAAUR,SAASQ,OAAO;AACvC;AAEA,MAAMC,eAAeH,MAAe,IAAIrD,SAAeyD,MAAMJ,EAAEN,QAAQW,KAAKD,CAAC,CAAC;AAE9E,MAAME,kBAAkBN,GAAYO,YAClC,IAAI5D,SAAeb,YAAY;CAC7B,MAAMoE,eAAe;EACnBM,aAAaC,KAAK;EAClB3E,QAAQ;CACV;CACA,MAAM2E,QAAQC,iBAAiB;EAC7BV,EAAEN,UAAUM,EAAEN,QAAQiB,QAAQC,MAAMA,MAAMV,MAAM;EAChDpE,QAAQ;CACV,GAAGyE,OAAO;CACVP,EAAEN,QAAQW,KAAKH,MAAM;AACvB,CAAC;AAEH,MAAMW,aAAab,GAAYrC,WAA0C;CACvEqC,EAAErC,SAASA;CACX,IAAI,CAACqC,EAAE9B,aAAa8B,EAAEjC,MAAM+C,KAAKnD,MAAM;AACzC;AAEA,MAAMoD,WAAWf,MACfA,EAAEnB,QACC8B,QAAQM,MAAMA,EAAEzF,MAAMwE,EAAE5B,UAAU,CAAC,CACnC8C,KAAKD,OAAO;CAAEzF,KAAKyF,EAAEzF;CAAK,GAAGyF,EAAExF;AAAQ,EAAE;AAE9C,MAAM0F,gBAAgBnB,MAAiD;CACrE,MAAMoB,MAAML,QAAQf,CAAC;CACrB,IAAI,CAACA,EAAEhC,QAAQ,OAAOoD;CACtB,MAAMC,QAAQ,IAAIC,IAAItB,EAAEnB,QAAQqC,KAAKD,MAAMA,EAAEzF,GAAG,CAAC;CAIjD,OAAO,CAAC,GAHQwE,EAAErC,OAAOkC,SAASc,QAC/Ba,MAAM,CAACH,MAAMI,IAAID,EAAEhG,GAAG,KAAKgG,EAAEhG,MAAMwE,EAAE5B,UAE7BmD,GAAS,GAAGH,GAAG,CAAC,CAACM,MAAMC,GAAGC,MAAMD,EAAEnG,MAAMoG,EAAEpG,GAAG;AAC1D;AAMA,MAAMsG,oBAAoB9B,MAAe;CACvC,MAAMzC,SAASyC,EAAEhC,SAASgC,EAAEhC,OAAOT,OAAOwE,OAAO,CAAC,IAAI,CAAA;CACtD,MAAMC,aAAa,IAAIV,IAAI/D,OAAO2D,KAAKe,MAAMA,EAAEzG,GAAG,CAAC;CACnD,MAAMqE,WAAWsB,aAAanB,CAAC,CAAC,CAACW,QAAQa,MAAM,CAACQ,WAAWP,IAAID,EAAEhG,GAAG,CAAC;CACrE,MAAM0G,WACJ3E,OAAO4E,SAAS,IACZ,CAAC,GAAInC,EAAErC,OAAOuE,YAAY,CAAA,GAAK,GAAG3E,MAAM,CAAC,CAAC6E,MAAM,GAAoB,IACpEpC,EAAErC,OAAOuE;CAKf,IAHEA,aAAalC,EAAErC,OAAOuE,YACtBrC,SAASsC,WAAWnC,EAAErC,OAAOkC,SAASsC,UACtCtC,SAASyC,OAAOd,GAAGe,MAAMf,EAAEhG,QAAQwE,EAAErC,OAAOkC,SAAS0C,EAAE,CAAE/G,GAAG,GAC/C;CACfqF,UAAUb,GAAG;EACX,GAAGA,EAAErC;EACLkC;EACA,GAAIqC,aAAaM,KAAAA,KAAa,EAAEN,SAAS;CAC3C,CAAC;AACH;AAEA,MAAMO,eAAezC,MAAe;CAClC,IAAI,CAACA,EAAEhC,QAAQ,OAAO8D,iBAAiB9B,CAAC;CACxC,SAAcA,SAAS8B,iBAAiB9B,CAAC,CAAC;AAC5C;AAGA,MAAM0C,YAAY1C,GAAY2C,OAAkC;CAC9D,IAAI,CAAC3C,EAAEhC,UAAUgC,EAAE9B,aAAa;EAC9ByE,GAAG;EACH,OAAOhG,QAAQb,QAAQ;CACzB;CACA,MAAMkC,SAASgC,EAAEhC;CACjB,MAAM4E,MAAM5E,OAAOV,IAAIuF,WACrB7C,EAAEjC,MAAM+E,KAAM,YAAY;EACxB,MAAMC,SAAS/C,EAAEjC,MAAMiF,KAAK;EAC5B,IAAID,WAAW,QAAQA,OAAOE,aAAajD,EAAErC,OAAOsF,UAClDC,WAAWlD,GAAG+C,MAAM;OACf,IAAIA,WAAW,MACpB/C,EAAErC,SAASoF;EAEbJ,GAAG;CACL,CAAC,CACH;CACA3E,OAAOV,MAAMsF,IAAIC,WACT,CAAC,SACD,CAAC,CACT;CACA,OAAOD;AACT;AAEA,MAAMO,WAAWnD,GAAYoD,UAAmB;CAC9C,IAAIA,UAAUpD,EAAE1B,MAAM;CACtB0B,EAAE1B,OAAO8E;CACTpD,EAAEJ,OAAO;CACT,IAAIwD,OAAOpD,EAAE5C,SAAS;AACxB;AAEA,MAAMiG,SAASrD,GAAYsD,UAAmB;CAC5C,IAAIA,MAAMzH,SAAS;CACnByH,MAAMzH,UAAU;CAChBmE,EAAEL,WAAW4D,UAAUD,MAAM5H,GAAG;CAChCsE,EAAEL,WAAW6D,YAAYF,MAAM5H,GAAG;AACpC;AAEA,MAAM+H,YAAsD,CAAA;AAE5D,MAAaE,kBACX3D,MAC6CA,EAAErC,OAAOiG,UAAUH;AAElE,MAAMI,qBACJ7D,GACAsD,OACA7G,YACG;CACHoE,UAAUb,GAAG;EACX,GAAGA,EAAErC;EACLiG,QAAQ,CACN,GAAI5D,EAAErC,OAAOiG,UAAU,CAAA,GACvB;GACEnI,SAAS6H,MAAM7H,QAAQL;GACvBC,QAAQiI,MAAM7H,QAAQJ;GACtB,GAAIiI,MAAM7H,QAAQH,SAASkH,KAAAA,KAAa,EAAElH,MAAMgI,MAAM7H,QAAQH,KAAK;GACnEmB;GACAqH,IAAIR,MAAM5H,IAAIoI;GACdtI,KAAK8H,MAAM9H;EACb,CAAC;CAEL,CAAC;CACDwE,EAAEJ,OAAO;AACX;AAEA,MAAMmE,gBACJ/D,GACAsD,OACA7G,YACG;CACH,IAAI,CAACuD,EAAEhC,QAAQ;EACb6F,kBAAkB7D,GAAGsD,OAAO7G,OAAO;EACnC;CACF;CACA,SAAcuD,SAAS6D,kBAAkB7D,GAAGsD,OAAO7G,OAAO,CAAC;AAC7D;AAEA,MAAMuH,eACJhE,GACAsD,OACAW,YAGG;CACHjE,EAAEnB,UAAUmB,EAAEnB,QAAQ8B,QAAQM,MAAMA,MAAMqC,KAAK;CAC/C,IAAIW,QAAQC,IAAI;EACdZ,MAAMxH,QAAQmI,QAAQlI,OAAO;EAC7BiE,EAAEL,WAAWwE,SAASb,MAAM5H,KAAK;GAC/B0I,MAAM;GACNrI,SAASkI,QAAQlI;EACnB,CAAC;CACH,OAAO;EAOL,IAAI,GAHDkI,QAAQxH,QAAQ6H,UAAU,aACzBL,QAAQxH,QAAQ6H,UAAU,kBAC5BhB,MAAM9H,MAAMwE,EAAE5B,aACJ2F,aAAa/D,GAAGsD,OAAOW,QAAQxH,OAAO;EAClD6G,MAAMtH,OAAO,IAAIjB,mBAAmBkJ,QAAQxH,OAAO,CAAC;EACpDuD,EAAEL,WAAWwE,SAASb,MAAM5H,KAAK;GAC/B0I,MAAM;GACNnI,OAAO,IAAIlB,mBAAmBkJ,QAAQxH,OAAO;EAC/C,CAAC;CACH;AACF;AAEA,MAAM8H,aAAavE,GAAYwE,WAA+B;CAC5D,MAAMF,QACJE,WAAW,YAAa,YAAuB;CACjD,MAAME,QAAQ1E,EAAEnB;CAChB,MAAM8F,iBAAiBrB,UAAgD;EACrE,IAAI,CAACA,MAAM3H,WAAW;GACpB,MAAMiJ,kBAAkBF,MAAMG,MAC3B5D,MAAMA,EAAEzF,MAAM8H,MAAM9H,OAAOyF,EAAEtF,SAChC;GACA,OAAOiJ,kBACH;IAAEE,MAAM;IAAWR;IAAOM;GAAgB,IAC1C;IAAEE,MAAM;IAAWR;GAAM;EAC/B;EACA,OAAO;GAAEQ,MAAM;GAAQR;EAAM;CAC/B;CACA,KAAK,MAAMhB,SAAS,CAAC,GAAGoB,KAAK,GAAG;EAC9B1E,EAAEL,WAAW6D,YAAYF,MAAM5H,GAAG;EAClCsI,YAAYhE,GAAGsD,OAAO;GAAEY,IAAI;GAAOzH,SAASkI,cAAcrB,KAAK;EAAE,CAAC;CACpE;AACF;AAEA,MAAMyB,kBAAkB/E,MAAe;CACrCA,EAAExB,aAAa,CAAA;CACf,IAAIwB,EAAEzB,WAAWiE,KAAAA,GAAW;CAC5B,MAAMhH,MAAMwE,EAAErC,OAAOqH;CACrBnE,UAAUb,GAAG;EAAE,GAAGA,EAAErC;EAAQqH,YAAYxJ,MAAM;CAAE,CAAC;CACjDwE,EAAExB,WAAW6B,KAAK;EAAE7E;EAAKW,KAAK6D,EAAEzB;EAAQ3C,QAAQ;CAAM,CAAC;AACzD;AAEA,MAAMqJ,cAAcjF,GAAYkF,YAAuB;CACrD,KAAK,MAAM5B,SAAS4B,SAAS;EAC3BlF,EAAEL,WAAW6D,YAAYF,MAAM5H,GAAG;EAClCsI,YAAYhE,GAAGsD,OAAO;GACpBY,IAAI;GACJzH,SAAS;IAAEqI,MAAM;IAAQR,OAAO;GAAe;EACjD,CAAC;CACH;AACF;AAMA,MAAMa,gBAAgBnF,GAAYoF,UAAsB;CACtD,MAAMC,OAAO,CAAC,GAAGrF,EAAEnB,OAAO;CAC1B,MAAMyG,YAAYD,KAAK1E,QAAQM,MAAM,CAACA,EAAEtF,aAAa,CAACsF,EAAEpF,OAAO;CAC/DoJ,WACEjF,GACAqF,KAAK1E,QAAQM,MAAMA,EAAEtF,aAAasF,EAAEpF,OAAO,CAC7C;CACAmE,EAAEnB,UAAU,CAAA;CACZmB,EAAE5B,aAAa;CAEf,MAAMwF,SAAS5D,EAAErC,OAAOiG;CACxBwB,MAAM;CACN,IAAIxB,WAAWpB,KAAAA,KAAaxC,EAAErC,OAAOiG,WAAWA,QAC9C/C,UAAUb,GAAG;EACX,GAAGA,EAAErC;EACLiG,QAAQ,CAAC,GAAI5D,EAAErC,OAAOiG,UAAU,CAAA,GAAK,GAAGA,MAAM;CAChD,CAAC;CAEH,KAAK,MAAM2B,OAAOD,WAAW;EAC3BtF,EAAEL,WAAW6D,YAAY+B,IAAI7J,GAAG;EAChC8J,aAAaxF,GAAGuF,IAAI9J,SAAS8J,IAAI7J,IAAIL,QAAQkK,IAAIzJ,SAASyJ,IAAIvJ,MAAM;CACtE;CACA+I,eAAe/E,CAAC;CAChBD,QAAQC,CAAC;CACTC,KAAKD,CAAC;CACN,KAAUA,CAAC;AACb;AAEA,MAAM0F,eAAe1F,GAAYiD,aAC/BkC,aAAanF,SACXa,UAAUb,GAAG;CAAEiD;CAAU0C,SAAS;CAAGX,YAAY;CAAGnF,UAAU,CAAA;AAAG,CAAC,CACpE;AAIF,MAAMqD,cAAclD,GAAY+C,WAC9BoC,aAAanF,SAAS;CACpBA,EAAErC,SAASoF;AACb,CAAC;AAGH,MAAM6C,mBAAmB5F,MAAe;CACtCA,EAAE/B,YAAY;CACd+B,EAAE7B,eAAe;CACjBuH,YAAY1F,GAAGzD,YAAY,CAAC;AAC9B;AAEA,MAAMsJ,mBAAmBC,QAAmD;CAC1E,OAAO;EACLhB,MAAM;EACNR,OAAO;EACP,GAAIwB,IAAIC,SAASvD,KAAAA,KAAa,EAAEuD,MAAMD,IAAIC,KAAK;EAC/C,GAAID,IAAIzJ,YAAYmG,KAAAA,KAAa,EAAEnG,SAASyJ,IAAIzJ,QAAQ;EACxD,GAAIyJ,IAAI/J,YAAYyG,KAAAA,KAAa,EAAEzG,SAAS+J,IAAI/J,QAAQ;CAC1D;AACF;AAEA,MAAMiK,aACJF,QAGyD;CACzD,QAAQA,IAAI1B,MAAZ;EACE,KAAK,UACH,OAAO;GAAEF,IAAI;GAAMnI,SAAS5B,eAAe2L,GAAG,CAAC,CAAC/J;EAAQ;EAC1D,KAAK,YACH,OAAO;GAAEmI,IAAI;GAAOzH,SAASoJ,gBAAgB1L,eAAe2L,GAAG,CAAC;EAAE;EACpE,KAAK,UACH,OAAO;GACL5B,IAAI;GACJzH,SAAS;IACPqI,MAAM;IACNR,OAAO;IACP,GAAIwB,IAAIzJ,YAAYmG,KAAAA,KAAa,EAAEnG,SAASyJ,IAAIzJ,QAAQ;GAC1D;EACF;EACF,KAAK,WACH,OAAO;GAAE6H,IAAI;GAAOzH,SAAS;IAAEqI,MAAM;IAAWR,OAAO;GAAS;EAAE;EACpE,KAAK,WACH,OAAO;GAAEJ,IAAI;GAAOzH,SAAS;IAAEqI,MAAM;IAAWR,OAAO;GAAS;EAAE;EACpE,SACE,OAAOlI,cAAc,qBAAqB6J,OAAOH,IAAI1B,IAAI,GAAG;CAChE;AACF;AAEA,MAAM8B,qBAA0C,IAAI5E,IAAIxH,QAAQ;AAEhE,MAAMqM,eAAenG,GAAY8F,QAAsB;CACrD,IAAI,CAAC9F,EAAEhC,UAAU,CAACkI,mBAAmBzE,IAAIqE,IAAI1B,IAAK,GAAG;CACrDpE,EAAEhC,OAAOT,OAAO8C,KAAK;EACnB7E,KAAKsK,IAAItK;EACT4I,MAAM0B,IAAI1B;EACV,GAAI0B,IAAIC,SAASvD,KAAAA,KAAa,EAAEuD,MAAMD,IAAIC,KAAK;EAC/C,GAAID,IAAIzJ,YAAYmG,KAAAA,KAAa,EAAEnG,SAASyJ,IAAIzJ,QAAQ;EACxD,GAAIyJ,IAAI/J,YAAYyG,KAAAA,KAAa,EAAEzG,SAAS+J,IAAI/J,QAAQ;EACxD,GAAI+J,IAAIxK,SAASkH,KAAAA,KAAa,EAAElH,MAAMwK,IAAIxK,KAAK;CACjD,CAAC;AACH;AAEA,MAAM8K,aAAapG,GAAY8F,QAAsB;CACnD,IAAI,CAACO,OAAOC,cAAcR,IAAItK,GAAG,KAAKsK,IAAItK,OAAO,GAC/CY,cAAc,yCAAyC;CAEzD,IAAI0J,IAAIS,QAAQ,MAAM;EACpBvG,EAAE5B,aAAaoI,KAAKC,IAAIzG,EAAE5B,YAAY0H,IAAItK,GAAG;EAC7C,KAAK,MAAM8H,SAAStD,EAAEnB,SACpB,IAAIyE,MAAM9H,OAAOwE,EAAE5B,YAAYkF,MAAM1H,SAAS;CAElD;CACA,IAAIkK,IAAI1B,SAAS5B,KAAAA,GAAW;CAC5B,MAAMc,QAAQtD,EAAEnB,QAAQ6H,MAAMzF,MAAMA,EAAEzF,QAAQsK,IAAItK,GAAG;CACrD,IAAIsK,IAAI1B,SAAS,WAAW;EAC1B,IAAId,OAAOD,MAAMrD,GAAGsD,KAAK;EACzB;CACF;CACA6C,YAAYnG,GAAG8F,GAAG;CAClB,IAAI,CAACxC,OAAO;CACZD,MAAMrD,GAAGsD,KAAK;CACdU,YAAYhE,GAAGsD,OAAO0C,UAAUF,GAAG,CAAC;AACtC;AAEA,MAAMa,mBAAmB3G,MAAe;CACtC,MAAMkC,WAAWlC,EAAErC,OAAOuE,YAAY,CAAA;CACtC,MAAM0E,2BAAW,IAAItF,IAAY;CACjC,KAAK,MAAMuF,WAAW3E,UAAU;EAC9B,MAAMoB,QAAQtD,EAAEnB,QAAQ6H,MAAMzF,MAAMA,EAAEzF,QAAQqL,QAAQrL,GAAG;EACzD,IAAI,CAAC8H,OAAO;EACZsD,SAASE,IAAID,QAAQrL,GAAG;EACxB6H,MAAMrD,GAAGsD,KAAK;EACdU,YAAYhE,GAAGsD,OAAO0C,UAAUa,OAAuB,CAAC;CAC1D;CACA,IAAID,SAASG,SAAS,GAAG;CACzBlG,UAAUb,GAAG;EACX,GAAGA,EAAErC;EACLkC,UAAUG,EAAErC,OAAOkC,SAASc,QAAQa,MAAM,CAACoF,SAASnF,IAAID,EAAEhG,GAAG,CAAC;EAC9D0G,UAAUA,SAASvB,QAAQsB,MAAM,CAAC2E,SAASnF,IAAIQ,EAAEzG,GAAG,CAAC;CACvD,CAAC;CACDuE,QAAQC,CAAC;CACTC,KAAKD,CAAC;AACR;AAEA,MAAMgH,cAAchH,GAAYiH,SAAyB;CACvD,KAAK,MAAMnB,OAAOmB,MAAMb,UAAUpG,GAAG8F,GAAG;CACxCrD,YAAYzC,CAAC;CACbC,KAAKD,CAAC;AACR;AAEA,MAAMkH,aAAalH,GAAY7D,QAAmB;CAChD,MAAMN,UAAUtC,iBAAiByG,EAAEjB,WAAW5C,GAAG;CACjD6D,EAAEjB,YAAYlD;CACdmE,EAAElB,YAAYjD,QAAQkD,UAAUoI,IAAI,CAAC,CAAC,EAAEC;CACxCpH,EAAEd,QAAQmB,KAAK,GAAGxE,QAAQwL,YAAY;AACxC;AAEA,MAAMC,mBAAmBtH,MAAe;CACtCD,QAAQC,CAAC;CACTC,KAAKD,CAAC;AACR;AAKA,MAAMuH,gBAAgBvH,GAAYwH,UAAkB;CAIlD,IAAI,EAFFxH,EAAExB,WAAW8D,OAAOd,GAAGe,MAAMf,EAAEhG,QAAQgM,QAAQ,IAAIjF,CAAC,KACpDvC,EAAErC,OAAOqH,eAAewC,QAAQxH,EAAExB,WAAW2D,SAAS,IACvC;EACftB,UAAUb,GAAG;GAAE,GAAGA,EAAErC;GAAQqH,YAAYwC,QAAQ;EAAE,CAAC;EACnDzC,eAAe/E,CAAC;CAClB;AACF;AAMA,MAAM0H,oBAAoB1H,GAAY2H,OAAeH,UAAkB;CACrE,MAAMnC,OAAO,CAAC,GAAGrF,EAAEnB,OAAO;CAC1BoG,WAAWjF,GAAGqF,IAAI;CAClBrF,EAAEnB,UAAU,CAAA;CACZmB,EAAE5B,aAAauJ;CACf9G,UAAUb,GAAG;EACXiD,UAAUjD,EAAErC,OAAOsF;EACnB0C,SAASgC,QAAQ;EACjB3C,YAAYwC,QAAQ;EACpB3H,UAAU,CAAA;EACV,GAAIG,EAAErC,OAAOiG,WAAWpB,KAAAA,KAAa,EAAEoB,QAAQ5D,EAAErC,OAAOiG,OAAO;CACjE,CAAC;CACDmB,eAAe/E,CAAC;CAChB,IACEqF,KAAKlD,SAAS,KACdnC,EAAE9C,gBAAgBmI,KAAKnE,KAAKD,MAAMA,EAAEvF,GAAG,CAAC,MAAM,WAE9C,KAAK,MAAM6J,OAAOF,MAChBG,aACExF,GACAuF,IAAI9J,SACJ8J,IAAI7J,IAAIL,cACF,CAAC,SACD,CAAC,CACT;CAGJ0E,QAAQC,CAAC;CACTC,KAAKD,CAAC;AACR;AAEA,MAAM4H,eACJ5H,GACA,EAAE7D,KAAK0L,UACJ;CACH,IAAIA,IAAIlK,WAAW6E,KAAAA,KAAaqF,IAAIlK,WAAW,aAC7CvB,cAAc,mBAAmB6J,OAAO4B,IAAIlK,MAAM,GAAG;CAEvDqC,EAAEjB,YAAY;EAAE+I,MAAM;EAAM/I,2BAAW,IAAIgJ,IAAI;CAAE;CACjDb,UAAUlH,GAAG7D,GAAG;CAChB6D,EAAEX,SAAS;CACXW,EAAEV,eAAe;CACjBU,EAAEpB,gBAAgB;CAClBoB,EAAE3B,WAAW;CACb2B,EAAE/B,YAAY4J,IAAIlK,WAAW;CAC7B,IAAIqC,EAAE/B,WAAW+B,EAAE9B,cAAc;CACjC,MAAM,CAAC8J,WAAWC,aAAajI,EAAEtB;CACjCsB,EAAEtB,iBAAiB,iBAAC,IAAI4C,IAAI,mBAAG,IAAIA,IAAI,CAAC;CACxC,MAAM4G,kBAAkB;EACtB,IAAIlI,EAAEhC,QAAQmK,YAAYnI,CAAC;EAG3BA,EAAE5B,aAAayJ,IAAIrM,OAAO;EAC1B,KAAK,MAAM8H,SAAStD,EAAEnB,SACpByE,MAAM1H,SAASoM,UAAUvG,IAAI6B,MAAM9H,GAAG;EAExC,MAAM4M,eAAeP,IAAIQ,UAAU;EACnCrI,EAAExB,aAAawB,EAAExB,WAAWmC,QAAQa,MAAMA,EAAEhG,MAAM4M,YAAY;EAC9D,KAAK,MAAM5G,KAAKxB,EAAExB,YAAYgD,EAAE5F,SAASqM,UAAUxG,IAAID,EAAEhG,GAAG;EAC5D+L,aAAavH,GAAGoI,YAAY;EAC5BtG,iBAAiB9B,CAAC;EAClBA,EAAE7B,eAAe;CACnB;CACA,IAAI,CAAC6B,EAAEhC,UAAUgC,EAAE9B,aAAa;EAC9BgK,UAAU;EACVZ,gBAAgBtH,CAAC;EACjB,KAAUA,CAAC;EACX;CACF;CACA,SAAcA,GAAGkI,SAAS,CAAC,CAACrF,WAAW;EACrCyE,gBAAgBtH,CAAC;EACjB,KAAUA,CAAC;CACb,CAAC;AACH;AAEA,MAAMsI,aACJtI,GACA,EAAE7D,KAAK8K,WACJ;CACHC,UAAUlH,GAAG7D,GAAG;CAChB,KAAK,MAAM2J,OAAOmB,MAAMb,UAAUpG,GAAG8F,GAAG;CACxCrD,YAAYzC,CAAC;CACbsH,gBAAgBtH,CAAC;AACnB;AAKA,MAAMuI,iBAAiBvI,GAAY6H,QAAsB;CACvD,MAAM,EAAErM,KAAK6M,WAAWR;CACxB,IAAI,OAAOrM,QAAQ,UAAU;EAC3B,MAAMgN,YAAYhC,KAAKC,IAAIjL,KAAKwE,EAAE5B,UAAU;EAC5C,KAAK,MAAMkF,SAAStD,EAAEnB,SAASyE,MAAM1H,SAAS0H,MAAM9H,OAAOgN;CAC7D;CACA,IAAI,OAAOH,WAAW,UAAU;EAC9BrI,EAAExB,aAAawB,EAAExB,WAAWmC,QAAQa,MAAMA,EAAEhG,MAAM6M,MAAM;EACxD,KAAK,MAAM7G,KAAKxB,EAAExB,YAAYgD,EAAE5F,SAAS;CAC3C;CACA,IAAI,OAAOiM,IAAIY,UAAU,UAAU;EACjCzI,EAAE3B,WAAWqK,KAAKC,IAAI,IAAId,IAAIY;EAC9BxI,KAAKD,CAAC;EACN,KAAUA,CAAC;EACX;CACF;CACA,MAAM4I,WAAW5I,EAAEnB,QAAQ6H,MAAMzF,MAAM,CAACA,EAAErF,MAAM;CAChD,MAAMiN,WAAW7I,EAAExB,WAAWkI,MAAMlF,MAAM,CAACA,EAAE5F,MAAM;CACnD,MAAMkN,SACJ,OAAOtN,QAAQ,YACfoN,aAAapG,KAAAA,KACboG,SAASpN,MAAMgL,KAAKC,IAAIjL,KAAKwE,EAAE5B,UAAU,IAAI;CAC/C,MAAM2K,SACJ,OAAOV,WAAW,YAClBQ,aAAarG,KAAAA,KACbqG,SAASrN,MAAM6M,SAAS;CAC1B,IAAIS,UAAUC,QAAQ;EACpB,SAAc/I,SAAS;GACrB,IAAI8I,QAAQpB,iBAAiB1H,GAAGxE,KAAM6M,UAAU,CAAC;QAC5Cd,aAAavH,GAAGqI,MAAO;EAC9B,CAAC,CAAC,CAACxF,WAAW;GACZ5C,KAAKD,CAAC;GACN,KAAUA,CAAC;EACb,CAAC;EACD;CACF;CACAC,KAAKD,CAAC;CACN,KAAUA,CAAC;AACb;AAEA,MAAMgJ,gBAAgBhJ,MAAe;CACnC,IAAIA,EAAEX,WAAW,YAAYW,EAAEX,SAAS;CACxC,IAAIW,EAAE/B,WAAW2H,gBAAgB5F,CAAC;CAClCC,KAAKD,CAAC;AACR;AAEA,MAAMiJ,gBAAgBjJ,GAAY,EAAEkJ,aAAiC;CACnE,IAAIA,WAAW,eAAeA,WAAW,SAAS;CAClDlJ,EAAEX,SAAS;CACXkF,UAAUvE,GAAG,MAAM;CACnBD,QAAQC,CAAC;CACTC,KAAKD,CAAC;AACR;AAEA,MAAMmJ,cAAcnJ,MAAeA,EAAEX,WAAW;AAUhD,MAAMmK,cAAcxJ,MAA6B;CAC/C,MAAMuJ,aAA2B,CAAA;CACjC,KAAK,MAAMjG,SAAStD,EAAExB,YAAY;EAChC,IAAI8E,MAAM1H,QAAQ;EAClB,IAAI2N,WAAWpH,UAAAA,KAAkC;EACjD,IAAIoH,WAAWpH,SAAS,KAAKmB,MAAM9H,QAAQ+N,WAAWE,GAAG,EAAE,CAAC,CAAEjO,MAAM,GAClE;EACF+N,WAAWlJ,KAAKiD,KAAK;CACvB;CACA,MAAMgG,aAAwB,CAAA;CAC9B,KAAK,MAAMhG,SAAStD,EAAEnB,SAAS;EAC7B,IAAIyE,MAAM1H,QAAQ;EAClB,IAAI0N,WAAWnH,UAAAA,KAAkC;EACjD,IAAImH,WAAWnH,SAAS,KAAKmB,MAAM9H,QAAQ8N,WAAWG,GAAG,EAAE,CAAC,CAAEjO,MAAM,GAClE;EACF8N,WAAWjJ,KAAKiD,KAAK;CACvB;CACA,IAAIiG,WAAWpH,WAAW,KAAKmH,WAAWnH,WAAW,GAAG,OAAO;CAC/D,OAAO;EACLkH,OAAO;GACL,GAAIE,WAAWpH,SAAS,KAAK,EAC3BtE,KAAK0L,WAAWrI,KAAKM,OAAO;IAAErF,KAAKqF,EAAErF;IAAKX,KAAKgG,EAAEhG;GAAI,EAAE,EACzD;GACA,GAAI8N,WAAWnH,SAAS,KAAK,EAC3B2D,KAAKwD,WAAWpI,KAAKD,OAAO;IAAE,GAAGA,EAAExF;IAASD,KAAKyF,EAAEzF;GAAI,EAAE,EAC3D;EACF;EACA8N;EACAC;CACF;AACF;AAEA,MAAMG,mBAAmB1J,MAAsC;CAC7DA,EAAEtB,iBAAiB,iBAAC,IAAI4C,IAAI,mBAAG,IAAIA,IAAI,CAAC;CACxC,MAAMqI,SAAS3J,EAAEvB;CACjBuB,EAAEvB,gBAAgB;CAClB,IAAI,CAACkL,UAAU,CAAC3J,EAAE7B,cAAc,OAAO;CACvC,MAAMyL,QAAQJ,WAAWxJ,CAAC;CAC1B,IAAI,CAAC4J,OAAO,OAAO;CACnB5J,EAAEtB,iBAAiB,CACjB,IAAI4C,IAAIsI,MAAMN,WAAWpI,KAAKD,MAAMA,EAAEzF,GAAG,CAAC,GAC1C,IAAI8F,IAAIsI,MAAML,WAAWrI,KAAKM,MAAMA,EAAEhG,GAAG,CAAC,CAAC;CAE7C,KAAK,MAAM8H,SAASsG,MAAMN,YAAYhG,MAAM3H,YAAY;CACxD,OAAOiO,MAAMP;AACf;AAEA,MAAM5D,OAAO,OAAOzF,MAAe;CACjC,IAAIA,EAAER,SAAS;CACfQ,EAAER,UAAU;CACZ,IAAI;EACF,OAAOQ,EAAET,WAAW,CAAC4J,WAAWnJ,CAAC,GAAG;GAClC,MAAMP,YAAYO,EAAEP;GACpB,IAAI+J,WAAWxJ,CAAC,MAAM,MAAM;GAC5B,IAAIA,EAAEX,WAAW,cAAc,CAACI,WAAW;IACzC,IACGA,WAAWoK,WAAWC,WAAW,kBAChCrK,UAAUoK,WAAWX,WAAW,UACjCzJ,WAAWlC,UAAUyC,EAAEnB,QAAQsD,SAAS,GAEzC1C,UAAUoK,WAAWE,UAAU;IAEjC,MAAM5J,YAAYH,CAAC;IACnB;GACF;GACA,MAAMgK,cAAchK,EAAE3B,WAAWqK,KAAKC,IAAI;GAC1C,IAAIqB,cAAc,GAAG;IACnB,MAAM1J,eAAeN,GAAGgK,WAAW;IACnC;GACF;GACA,MAAMJ,QAAQJ,WAAWxJ,CAAC;GAC1B,IAAI,CAAC4J,OAAO;GACZ,MAAMK,QAAQjK,EAAEV;GAChB,KAAK,MAAMgE,SAASsG,MAAMN,YAAYhG,MAAM3H,YAAY;GACxD,IAAIiB;GACJ,IAAI;IAGF,MAAMsN,aAAazK,UAAUyK,KAAKN,MAAMP,KAAK;IAC7CzM,SAAS,OAAOoD,EAAEhC,UAAU,CAACgC,EAAE9B,cAC3B8B,EAAEjC,MAAM+E,KAAMoH,IAAI,IAClBA,KAAK;GACX,QAAQ;IACN,IAAI,CAAClK,EAAET,WAAW4J,WAAWnJ,CAAC,GAAG;IACjCA,EAAEpB,iBAAiB;IACnB,MAAM0B,eAAeN,GAAGpF,QAAQoF,EAAEpB,aAAa,CAAC;IAChD;GACF;GACA,IAAI,CAACoB,EAAET,SAAS;GAChBS,EAAEpB,gBAAgB;GAClB,IAAIhC,OAAOwH,SAAS,MACd6F;QAAAA,UAAUjK,EAAEV,aAAa;KAC3B,KAAK,MAAMgE,SAASsG,MAAMN,YACxB,IAAItJ,EAAEnB,QAAQsL,SAAS7G,KAAK,GAAG;MAC7BA,MAAM1H,SAAS;MACfoE,EAAEL,WAAWyK,WAAW9G,MAAM5H,GAAG;KACnC;KAEF,KAAK,MAAM4H,SAASsG,MAAML,YAAYjG,MAAM1H,SAAS;IACvD;UACK,IAAIgB,OAAOwH,SAAS,WACrB6F;QAAAA,UAAUjK,EAAEV,aAAaiJ,cAAcvI,GAAGpD,OAAOiL,GAAG;GAAA,OACnD,IAAIjL,OAAOwH,SAAS,eAErB6F;QAAAA,UAAUjK,EAAEV,aAAa;KAC3BG,UAAUoK,WAAWE,UAAU;KAC/B,MAAM5J,YAAYH,CAAC;IACrB;UACK,IAAIpD,OAAOwH,SAAS,YAErB6F;QAAAA,UAAUjK,EAAEV,aAAa;KAC3BU,EAAEvB,gBAAgB;KAClBgB,UAAUoK,WAAWE,UAAU;KAC/B,OAAO/J,EAAET,WAAW,CAAC4J,WAAWnJ,CAAC,KAAKiK,UAAUjK,EAAEV,aAChD,MAAMa,YAAYH,CAAC;IAEvB;;EAEJ;CACF,UAAU;EACRA,EAAER,UAAU;CACd;AACF;AAEA,MAAM6K,SAASrK,MAAe;CAC5B,IAAIA,EAAEhC,QAAQ;EACZgC,EAAEhC,OAAOP,cAAcuC,EAAEjC,MAAMuM,gBAAiB;GAC9C,SAActK,SAAS2G,gBAAgB3G,CAAC,CAAC;EAC3C,CAAC;EACDA,EAAET,UAAU;EACZ,SAAcS,SAAS;GACrB,IAAIA,EAAEjC,MAAMiF,KAAK,MAAM,MAAMhD,EAAEjC,MAAM+C,KAAKd,EAAErC,MAAM;GAClDqC,EAAElC,kBAAkB;GACpBqK,YAAYnI,CAAC;GACb2G,gBAAgB3G,CAAC;EACnB,CAAC,CAAC,CAAC6C,WAAW,KAAK4C,KAAKzF,CAAC,CAAC;EAC1B;CACF;CACA,IAAI,CAACA,EAAElC,iBAAiB;EACtBkC,EAAElC,kBAAkB;EACpBkC,EAAEjC,MAAM+C,KAAKd,EAAErC,MAAM;CACvB;CACAwK,YAAYnI,CAAC;CACbA,EAAET,UAAU;CACZ,KAAUS,CAAC;AACb;AAEA,MAAMuK,QAAQvK,MAAe;CAC3BA,EAAET,UAAU;CACZ,IAAIS,EAAEhC,QAAQ;EACZgC,EAAEhC,OAAOP,cAAc;EACvBuC,EAAEhC,OAAOP,cAAc;CACzB;CACAwC,KAAKD,CAAC;CACNuE,UAAUvE,GAAG,SAAS;AACxB;AAEA,MAAMwK,gBAAgBxK,GAAYP,cAA0B;CAC1D,IAAIO,EAAEP,cAAcA,WAAW;CAC/BO,EAAEP,YAAYA;CACdQ,KAAKD,CAAC;AACR;AAEA,MAAMwF,gBACJxF,GACAvE,SACAJ,QACAS,SACAE,WACG;CACH,MAAMR,MAAMwE,EAAErC,OAAOgI;CACrB,MAAMrC,QAAiB;EACrB9H;EACAC;EACAC,KAAK;GACHN,QAAQK,QAAQL;GAChBC;GACAyI,IAAI4E,KAAKC,IAAI;GACbnN;GACAyH,UAAUjD,EAAErC,OAAOsF;EACrB;EACAtH,WAAW;EACXC,QAAQ;EACRC,SAAS;EACTC;EACAE;CACF;CACAgE,EAAEnB,QAAQwB,KAAKiD,KAAK;CACpBzC,UAAUb,GAAG;EAAE,GAAGA,EAAErC;EAAQgI,SAASnK,MAAM;EAAGqE,UAAUsB,aAAanB,CAAC;CAAE,CAAC;CACzEA,EAAEL,WAAW8K,QAAQnH,MAAM5H,GAAG;AAChC;AAEA,MAAMgP,WACJ1K,GACAvE,SACAJ,QACAS,SACAE,WACG;CACH,IAAI,CAACgE,EAAEhC,QAAQ;EACbwH,aAAaxF,GAAGvE,SAASJ,QAAQS,SAASE,MAAM;EAChDiE,KAAKD,CAAC;EACN,KAAUA,CAAC;EACX;CACF;CACA,SAAcA,SAAS;EACrB,IAAI,CAACA,EAAET,SAAS;GACdvD,OAAO,IAAIjB,mBAAmB;IAAE+J,MAAM;IAAWR,OAAO;GAAU,CAAC,CAAC;GACpE;EACF;EACA,IAAI6E,WAAWnJ,CAAC,GAAG;GACjBhE,OAAO,IAAIjB,mBAAmB;IAAE+J,MAAM;IAAWR,OAAO;GAAc,CAAC,CAAC;GACxE;EACF;EACAkB,aAAaxF,GAAGvE,SAASJ,QAAQS,SAASE,MAAM;CAClD,CAAC,CAAC,CAAC6G,WAAW;EACZ5C,KAAKD,CAAC;EACN,KAAUA,CAAC;CACb,CAAC;AACH;AAIA,MAAMmI,eAAenI,MAAe;CAClC,MAAMqB,QAAQ,IAAIC,IAAItB,EAAEnB,QAAQqC,KAAKD,MAAMA,EAAEzF,GAAG,CAAC;CACjD,MAAMuH,SAAS/C,EAAErC,OAAOkC,SAASc,QAAQa,MAAM,CAACH,MAAMI,IAAID,EAAEhG,GAAG,CAAC;CAChE,IAAIuH,OAAOZ,WAAW,GAAG;CACzB,KAAK,MAAM,EAAE3G,KAAK,GAAGC,aAAasH,QAAQ;EACxC,MAAM1H,SACJI,QAAQH,SAASkH,KAAAA,IACb/G,QAAQJ,SACPjB,YAAY,CAAC,GAAGqB,QAAQJ,MAAM,GAAGI,QAAQH,IAAI;EACpD,MAAMgI,QAAiB;GACrB9H;GACAC;GACAC,KAAK;IACHN,QAAQK,QAAQL;IAChBC;IACAyI,IAAI4E,KAAKC,IAAI;IACbnN;IACAyH,UAAUjD,EAAErC,OAAOsF;GACrB;GACAtH,WAAW;GACXC,QAAQ;GACRC,SAAS;GACTC,eAAe,CAAC;GAChBE,cAAc,CAAC;EACjB;EACAgE,EAAEnB,QAAQwB,KAAKiD,KAAK;EACpBtD,EAAEL,WAAW8K,QAAQnH,MAAM5H,GAAG;CAChC;CACAsE,EAAEnB,QAAQ6C,MAAMC,GAAGC,MAAMD,EAAEnG,MAAMoG,EAAEpG,GAAG;AACxC;AAEA,MAAMmP,eACJ3K,GACA5E,QACAC,WACqB;CACrB,IAAI,CAAC2E,EAAET,SACL,OAAO/C,aAAa;EAAEsI,MAAM;EAAWR,OAAO;CAAU,CAAC;CAE3D,IAAI6E,WAAWnJ,CAAC,GACd,OAAOxD,aAAa;EAAEsI,MAAM;EAAWR,OAAO;CAAc,CAAC;CAE/D,MAAM1H,SAAS,IAAID,SAAkBb,SAASE,WAAW;EACvD,MAAM,EAAEX,QAAQuP,SAAStP,SAASrB,aAAaoB,MAAM;EACrDqP,QACE1K,GACA;GAAE5E;GAAQC,QAAQuP;GAAS,GAAItP,SAASkH,KAAAA,KAAa,EAAElH,KAAK;EAAG,GAC/DD,QACAS,SACAE,MACF;CACF,CAAC;CACDY,OAAOC,YAAY,CAAC,CAAC;CACrB,OAAOD;AACT;AAEA,MAAMiO,cACJ7K,GACAsD,WAECtD,EAAErC,OAAOiG,UAAU,CAAA,EAAA,CAAI8C,MACrBoE,MACCA,EAAEtP,QAAQ8H,MAAM9H,OAAOsP,EAAEhH,OAAOR,MAAMQ,MAAMgH,EAAErP,YAAY6H,MAAM7H,OACpE;AAEF,MAAMsP,iBAAiBzH,0BACrB,IAAIhH,MAAM,sCAAsCgH,MAAM7H,QAAO,EAAG;AAElE,MAAMuP,cACJhL,GACAsD,UACkC;CAClC,MAAMM,SAAS5D,EAAErC,OAAOiG,UAAU,CAAA;CAClC,MAAMqH,QAAQJ,WAAW7K,GAAGsD,KAAK;CACjC,IAAI2H,UAAUzI,KAAAA,GAAW,MAAMuI,cAAczH,KAAK;CAClDzC,UAAUb,GAAG;EAAE,GAAGA,EAAErC;EAAQiG,QAAQA,OAAOjD,QAAQmK,MAAMA,MAAMG,KAAK;CAAE,CAAC;CACvEjL,EAAEJ,OAAO;CACT,OAAOqL;AACT;AAEA,MAAaC,iBACXlL,GACAsD,UACS;CACT,IAAI,CAACtD,EAAEhC,QAAQ;EACbgN,WAAWhL,GAAGsD,KAAK;EACnB;CACF;CACA,IAAIuH,WAAW7K,GAAGsD,KAAK,MAAMd,KAAAA,GAAW,MAAMuI,cAAczH,KAAK;CACjE,SAActD,SAAS;EACrB,IAAI6K,WAAW7K,GAAGsD,KAAK,MAAMd,KAAAA,GAAWwI,WAAWhL,GAAGsD,KAAK;CAC7D,CAAC;AACH;AAEA,MAAa6H,eACXnL,GACAsD,UACqB;CACrB,IAAI,CAACtD,EAAET,SACL,OAAO/C,aAAa;EAAEsI,MAAM;EAAWR,OAAO;CAAU,CAAC;CAE3D,IAAI6E,WAAWnJ,CAAC,GACd,OAAOxD,aAAa;EAAEsI,MAAM;EAAWR,OAAO;CAAc,CAAC;CAE/D,MAAM2G,QAAQJ,WAAW7K,GAAGsD,KAAK;CACjC,IAAI2H,UAAUzI,KAAAA,GAAW,MAAMuI,cAAczH,KAAK;CAClD,MAAMjI,SACJ4P,MAAM3P,SAASkH,KAAAA,IACXyI,MAAM5P,SACLjB,YAAY,CAAC,GAAG6Q,MAAM5P,MAAM,GAAG4P,MAAM3P,IAAI;CAChD,MAAMsB,SAAS,IAAID,SAAkBb,SAASE,WAAW;EACvD,MAAMyM,cAAc;GAClB,IAAI,CAACzI,EAAET,SAAS;IACdvD,OAAO,IAAIjB,mBAAmB;KAAE+J,MAAM;KAAWR,OAAO;IAAU,CAAC,CAAC;IACpE;GACF;GACA,IAAI6E,WAAWnJ,CAAC,GAAG;IACjBhE,OACE,IAAIjB,mBAAmB;KAAE+J,MAAM;KAAWR,OAAO;IAAc,CAAC,CAClE;IACA;GACF;GACA,MAAM8G,UAAUP,WAAW7K,GAAGsD,KAAK;GACnC,IAAI8H,YAAY5I,KAAAA,GAAW;IACzBxG,OAAO+O,cAAczH,KAAK,CAAC;IAC3B;GACF;GACA0H,WAAWhL,GAAGoL,OAAO;GACrB5F,aACExF,GACA;IACE5E,QAAQgQ,QAAQ3P;IAChBJ,QAAQ,CAAC,GAAG+P,QAAQ/P,MAAM;IAC1B,GAAI+P,QAAQ9P,SAASkH,KAAAA,KAAa,EAAElH,MAAM8P,QAAQ9P,KAAK;GACzD,GACAD,QACAS,SACAE,MACF;EACF;EACA,IAAI,CAACgE,EAAEhC,QAAQ;GACbyK,MAAM;GACNxI,KAAKD,CAAC;GACN,KAAUA,CAAC;GACX;EACF;EACA,SAAcA,GAAGyI,KAAK,CAAC,CAAC5F,WAAW;GACjC5C,KAAKD,CAAC;GACN,KAAUA,CAAC;EACb,GAAGhE,MAAM;CACX,CAAC;CACDY,OAAOC,YAAY,CAAC,CAAC;CACrB,OAAOD;AACT;AAEA,MAAMyO,cAAcrL,GAAYoH,UAAyC;CACvE,IAAI,OAAOA,UAAU,YAAYA,UAAU,QAAQkE,MAAMC,QAAQnE,KAAK,GACpE,MAAM,IAAI9K,MAAM,2CAA2C;CAE7D,IAAI,CAAC0D,EAAET,WAAW4J,WAAWnJ,CAAC,GAAG;CACjC,MAAM,EAAEoH,OAAOwD,SAAStP,SAASpB,YAAYkN,KAAK;CAClD,MAAMjL,MAAM,CACV;EACEqP,IAAI;EACJC,MAAM,CAAA;EACNrE,OAAOwD;EACP,GAAItP,SAASkH,KAAAA,KAAa,EAAElH,KAAK;CACnC,CAAC;CAEH0E,EAAEzB,SAASpC;CACX,MAAMuP,aAAa;EACjB,MAAMlQ,MAAMwE,EAAErC,OAAOqH;EACrBnE,UAAUb,GAAG;GAAE,GAAGA,EAAErC;GAAQqH,YAAYxJ,MAAM;EAAE,CAAC;EACjDwE,EAAExB,WAAW6B,KAAK;GAAE7E;GAAKW;GAAKP,QAAQ;EAAM,CAAC;CAC/C;CACA,IAAI,CAACoE,EAAEhC,QAAQ;EACb0N,KAAK;EACLzL,KAAKD,CAAC;EACN,KAAUA,CAAC;EACX;CACF;CACA,SAAcA,SAAS;EACrB,IAAI,CAACA,EAAET,WAAW4J,WAAWnJ,CAAC,GAAG;EACjC0L,KAAK;CACP,CAAC,CAAC,CAAC7I,WAAW;EACZ5C,KAAKD,CAAC;EACN,KAAUA,CAAC;CACb,CAAC;AACH;AAEA,MAAa2L,uBACXC,YACY;CACZ,MAAM,CAACC,gBAAgBlS,SAASgB,wBAAwB;CACxD,MAAMmR,UAAUrS,WAAWiB,qBAAqB;CAChD,IAAIkR,QAAQ5O,iBAAiBwF,KAAAA,KAAasJ,YAAYtJ,KAAAA,GACpD,MAAM,IAAIlG,MACR,6GACF;CAEF,MAAMyB,QAAQ6N,QAAQ5O,gBAAgB8O,WAAWD;CACjD,IAAK9N,MAAM+E,SAASN,KAAAA,OAAgBzE,MAAMuM,cAAc9H,KAAAA,IACtD,MAAM,IAAIlG,MACR,qEACF;CAEF,MAAM,CAAC0D,KAAKrG,eAAwB;EAClC,MAAMoJ,SAAShF,MAAMiF,KAAK;EAC1B,IAAID,WAAW,QAAQ,CAACuI,MAAMC,QAAQxI,OAAOlD,QAAQ,GACnD,MAAM,IAAIvD,MACR,qEACF;EAQF,MAAMyP,UAAmB;GACvBpO,QAPaoF,UAAU;IACvBE,UAAU1G,YAAY;IACtBoJ,SAAS;IACTX,YAAY;IACZnF,UAAU,CAAA;GACZ;GAGEhC,KAAK;IACH,IAAIoF,WAAW;KACb,OAAO8I,QAAQpO,OAAOsF;IACxB;IACAyG,uBAAuBA,gBAAgBqC,OAAO;IAC9CC,UAAUC,SAASrE,YAAYmE,SAASE,IAAI;IAC5CC,QAAQD,WAAS3D,UAAUyD,SAASE,MAAI;IACxCE,SAASlF,SAASD,WAAW+E,SAAS9E,IAAI;IAC1CmF,YAAYvE,QAAQU,cAAcwD,SAASlE,GAAG;IAC9CwE,SAASjJ,UAAUD,QAAQ4I,SAAS3I,KAAK;IACzCkJ,gBAAgBtD,aAAa+C,OAAO;IACpCQ,WAAWN,WAAShD,aAAa8C,SAASE,MAAI;GAChD;GACAnO,iBAAiBiF,WAAW;GAC5BhF;GACAC,QACED,MAAM+E,SAASN,KAAAA,IACX;IAAElF,KAAKX,QAAQb,QAAQ;IAAGyB,QAAQ,CAAA;IAAIE,aAAa;GAAK,IACxD;GACNQ,WAAW;GACXC,aAAa;GACbC,cAAc;GACdC,YAAY;GACZC,UAAU;GACVC,MAAM;GACNpB,eAAesF,KAAAA;GACfpF,QAAQoF,KAAAA;GACRjE,QAAQiE,KAAAA;GACRhE,YAAY,CAAA;GACZC,eAAe;GACfC,gBAAgB,iBAAC,IAAI4C,IAAI,mBAAG,IAAIA,IAAI,CAAC;GACrC1C,eAAe;GACfC,SAAS,CAAA;GACTC,WAAW0D,KAAAA;GACXzD,WAAW;IAAE+I,MAAM;IAAM/I,2BAAW,IAAIgJ,IAAI;GAAE;GAC9C9I,eAAeuD,KAAAA;GACftD,SAAS,CAAA;GACTC,QAAQ;IACNqN,gBAAgBT,QAAQjN;IACxB2N,mBAAmB;KACjB,MAAMvN,UAAU6M,QAAQ7M;KACxB6M,QAAQ7M,UAAU,CAAA;KAClB,OAAOA;IACT;IACAwN,cAAcC,aAAa;KACzBZ,QAAQnM,SAAS+M,mBAAmB,CAAC;IACvC;GACF;GACAtN,QAAQ;GACRC,aAAa;GACbC,SAAS;GACTC,SAAS;GACTC,WAAW;GACXC,SAAS,CAAA;GACTC,WAAW;GACXC,cAAc,CAAC;GACfC,UAAUhF,mBAAmBO,QAAQC,WACnCsP,YAAYoB,SAAS3Q,QAAQC,MAAM,CACrC;EACF;EACAhB,iBAAiB0R,QAAQlM,UAAU,EACjC+M,cAAcD,eAAa;GACzBZ,QAAQpM,YAAYgN;EACtB,EACF,CAAC;EACD,OAAOZ;CACT,CAAC;CACD,IAAKhO,MAAM+E,SAASN,KAAAA,OAAgBxC,EAAEhC,WAAW,QAC/C,MAAM,IAAI1B,MACR,8HACF;CAEF0D,EAAEjC,QAAQA;CACViC,EAAE9C,gBAAgB0O,QAAQ1O;CAC1B8C,EAAE5C,SAASwO,QAAQxO;CACnB1D,gBAAgB;EACd2Q,MAAMrK,CAAC;EACP,aAAauK,KAAKvK,CAAC;CACrB,GAAG,CAACA,CAAC,CAAC;CACN,OAAOA;AACT"}
1
+ {"version":3,"file":"session.js","names":["applyDocumentOps","StatewireDocuments","useContext","useEffect","useState","StatewirePath","MAX_COMMANDS_PER_FRAME","TERMINAL","StatewireCmd","StatewireSyn","encodeParams","encodeValue","reviveResponse","reviveValue","bindCommandsHost","CommandsInvocation","CommandsListener","Statewire","StatewireClient","SessionStorageContext","createMemorySessionStore","backoff","createMethodProxy","randomId","newClientId","StatewireSendError","RemoteLink","StatewireFrame","StatewireRemoteProps","WireCommand","method","params","meta","Pending","seq","command","inv","attempted","posted","applied","resolve","payload","reject","error","CtxPending","ops","protocolError","message","Error","rejectedSend","failure","SendFailure","Promise","result","catch","AttachState","StatewireSessionOptions","sessionStore","SessionStorage","onSessionLost","OnSessionLost","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","documents","State","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","NO_FAILED","FailedCommand","failedCommands","failed","retainFailedInner","ts","retainFailed","settleEntry","outcome","ok","onSettle","type","rides","cause","settleAll","detach","const","batch","detachFailure","predecessorLost","some","fate","restateContext","ctxNextSeq","settleLost","entries","rebaseRecord","adopt","held","survivors","old","enqueueInner","pump","resetRecord","nextSeq","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","get","value","changedPaths","publishIngested","snapCtxClock","ctxWm","ctxAligned","sessionLostInner","seqWm","handleHello","syn","mode","Map","attachCmd","attachCtx","reconcile","adoptStored","ctxWatermark","ctxSeq","handleOps","handleRefusal","watermark","retry","Date","now","firstCmd","firstCtx","cmdGap","ctxGap","handleDetach","handleFinish","reason","isFinished","Lanes","frame","cmdEntries","ctxEntries","buildLanes","at","takeAttachLanes","wanted","lanes","connection","status","reconnect","resumeDelay","epoch","send","includes","onPosted","start","subscribe","stop","setTransport","onStart","enqueue","sendCommand","encoded","findFailed","f","unknownFailed","takeFailed","found","discardFailed","retryFailed","current","setContext","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 { applyDocumentOps } from \"../wire/documents\";\nimport type { StatewireDocuments } from \"../wire/documents\";\nimport { useContext, useEffect, useState } from \"react\";\n\nimport type { StatewirePath } from \"../wire/ops\";\nimport { MAX_COMMANDS_PER_FRAME } from \"../wire/limits\";\nimport { TERMINAL } from \"./connection\";\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 as newClientId } 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 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 onSessionLost?: StatewireClient.OnSessionLost | 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 onSessionLost: StatewireClient.OnSessionLost | undefined;\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 documents: StatewireDocuments.State;\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 NO_FAILED: readonly StatewireClient.FailedCommand[] = [];\n\nexport const failedCommands = (\n s: Session,\n): readonly StatewireClient.FailedCommand[] => s.record.failed ?? NO_FAILED;\n\nconst retainFailedInner = (\n s: Session,\n entry: Pending,\n failure: StatewireClient.SendFailure,\n) => {\n setRecord(s, {\n ...s.record,\n failed: [\n ...(s.record.failed ?? []),\n {\n command: entry.command.method,\n params: entry.command.params,\n ...(entry.command.meta !== undefined && { meta: entry.command.meta }),\n failure,\n ts: entry.inv.ts,\n seq: entry.seq,\n },\n ],\n });\n s.notify();\n};\n\nconst retainFailed = (\n s: Session,\n entry: Pending,\n failure: StatewireClient.SendFailure,\n) => {\n if (!s.shared) {\n retainFailedInner(s, entry, failure);\n return;\n }\n void transact(s, () => retainFailedInner(s, entry, failure));\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 // A statement the record still carries resends on the next attach; only\n // invocations the record no longer owns become failed history.\n const rides =\n (outcome.failure.cause === \"unmount\" ||\n outcome.failure.cause === \"stream-gone\") &&\n entry.seq > s.durableSeq;\n if (!rides) retainFailed(s, entry, outcome.failure);\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\") => {\n const cause =\n detach === \"unmount\" ? (\"unmount\" as const) : (\"stream-gone\" as const);\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\nconst settleLost = (s: Session, entries: Pending[]) => {\n for (const entry of entries) {\n s.lifecycle?.onCovered?.(entry.inv);\n settleEntry(s, entry, {\n ok: false,\n failure: { fate: \"lost\", cause: \"session-lost\" },\n });\n }\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// on the adopted lane clocks.\nconst rebaseRecord = (s: Session, adopt: () => void) => {\n const held = [...s.pending];\n const survivors = held.filter((p) => !p.attempted && !p.applied);\n settleLost(\n s,\n held.filter((p) => p.attempted || p.applied),\n );\n s.pending = [];\n s.durableSeq = 0;\n // Failed entries are user-owned history: they ride through every record replacement.\n const failed = s.record.failed;\n adopt();\n if (failed !== undefined && s.record.failed !== failed) {\n setRecord(s, {\n ...s.record,\n failed: [...(s.record.failed ?? []), ...failed],\n });\n }\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\nconst resetRecord = (s: Session, clientId: string) =>\n rebaseRecord(s, () =>\n setRecord(s, { clientId, nextSeq: 1, ctxNextSeq: 1, commands: [] }),\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 rebaseRecord(s, () => {\n s.record = stored;\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 switch (cmd.type) {\n case \"result\":\n return { ok: true, payload: reviveResponse(cmd).payload };\n case \"rejected\":\n return { ok: false, failure: rejectedFailure(reviveResponse(cmd)) };\n case \"failed\":\n return {\n ok: false,\n failure: {\n fate: \"failed\",\n cause: \"server\",\n ...(cmd.message !== undefined && { message: cmd.message }),\n },\n };\n case \"crashed\":\n return { ok: false, failure: { fate: \"crashed\", cause: \"server\" } };\n case \"expired\":\n return { ok: false, failure: { fate: \"expired\", cause: \"server\" } };\n default:\n return protocolError(`unknown cmd type: ${String(cmd.type)}`);\n }\n};\n\nconst TERMINAL_CMD_TYPES: ReadonlySet<string> = new Set(TERMINAL);\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 = applyDocumentOps(s.documents, ops);\n s.documents = applied;\n s.canonical = applied.documents.get(0)?.value;\n s.changed.push(...applied.changedPaths);\n};\n\nconst publishIngested = (s: Session) => {\n publish(s);\n wake(s);\n};\n\n// A hello's cmd watermark may understate a durable record (cold host, tray\n// unloaded): held seqs resend as-is and the frame's answer arbitrates —\n// absorption where the record survived, a gap refusal where it did not.\nconst snapCtxClock = (s: Session, ctxWm: number) => {\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\n// The refusal's watermarks are exact: every held statement above them was\n// never admitted by the live record, and the first unposted seq being beyond\n// watermark+1 proves the record that admitted the missing prefix is gone —\n// its history settles lost and the lane clocks restart at the watermarks.\nconst sessionLostInner = (s: Session, seqWm: number, ctxWm: number) => {\n const held = [...s.pending];\n settleLost(s, held);\n s.pending = [];\n s.durableSeq = seqWm;\n setRecord(s, {\n clientId: s.record.clientId,\n nextSeq: seqWm + 1,\n ctxNextSeq: ctxWm + 1,\n commands: [],\n ...(s.record.failed !== undefined && { failed: s.record.failed }),\n });\n restateContext(s);\n if (\n held.length > 0 &&\n s.onSessionLost?.(held.map((p) => p.inv)) === \"requeue\"\n ) {\n for (const old of held) {\n enqueueInner(\n s,\n old.command,\n old.inv.params,\n () => {},\n () => {},\n );\n }\n }\n publish(s);\n wake(s);\n};\n\nconst handleHello = (\n s: Session,\n { ops, syn }: { ops: unknown[]; syn: StatewireSyn },\n) => {\n if (syn.record !== undefined && syn.record !== \"ephemeral\") {\n protocolError(`unknown record: ${String(syn.record)}`);\n }\n s.documents = { mode: null, documents: new Map() };\n ingestOps(s, ops);\n s.attach = \"attached\";\n s.attachEpoch += 1;\n s.frameFailures = 0;\n s.resumeAt = 0;\n s.ephemeral = syn.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 (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 s.durableSeq = syn.seq ?? 0;\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 snapCtxClock(s, ctxWatermark);\n syncBacklogInner(s);\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 retry-less {syn} refusal is the one session-loss verdict: a cmd gap\n// against its exact watermark settles the held history lost; a pushback\n// (retry present) or a gapless refusal only reconciles the resend queues.\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 wake(s);\n void pump(s);\n return;\n }\n const firstCmd = s.pending.find((p) => !p.posted);\n const firstCtx = s.ctxPending.find((c) => !c.posted);\n const cmdGap =\n typeof seq === \"number\" &&\n firstCmd !== undefined &&\n firstCmd.seq > Math.max(seq, s.durableSeq) + 1;\n const ctxGap =\n typeof ctxSeq === \"number\" &&\n firstCtx !== undefined &&\n firstCtx.seq > ctxSeq + 1;\n if (cmdGap || ctxGap) {\n void transact(s, () => {\n if (cmdGap) sessionLostInner(s, seq!, ctxSeq ?? 0);\n else snapCtxClock(s, ctxSeq!);\n }).then(() => {\n wake(s);\n void pump(s);\n });\n return;\n }\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 === \"reconnect\" || reason === \"error\") return;\n s.attach = \"finished\";\n settleAll(s, \"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 >= MAX_COMMANDS_PER_FRAME) break;\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 >= MAX_COMMANDS_PER_FRAME) break;\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 (\n (transport?.connection.status === \"disconnected\" &&\n transport.connection.reason === \"idle\") ||\n (transport?.parked && s.pending.length > 0)\n ) {\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 wake(s);\n void pump(s);\n return;\n }\n void transact(s, () => {\n if (!s.running) {\n reject(new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }));\n return;\n }\n if (isFinished(s)) {\n reject(new StatewireSendError({ fate: \"aborted\", cause: \"stream-gone\" }));\n return;\n }\n enqueueInner(s, command, params, resolve, reject);\n }).then(() => {\n wake(s);\n void pump(s);\n });\n};\n\n// A stored command may have reached a server: attempted settles it lost,\n// never aborted, when a channel death ends the session.\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 findFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\n): StatewireClient.FailedCommand | undefined =>\n (s.record.failed ?? []).find(\n (f) =>\n f.seq === entry.seq && f.ts === entry.ts && f.command === entry.command,\n );\n\nconst unknownFailed = (entry: StatewireClient.FailedCommand) =>\n new Error(`statewire: unknown failed command \"${entry.command}\"`);\n\nconst takeFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\n): StatewireClient.FailedCommand => {\n const failed = s.record.failed ?? [];\n const found = findFailed(s, entry);\n if (found === undefined) throw unknownFailed(entry);\n setRecord(s, { ...s.record, failed: failed.filter((f) => f !== found) });\n s.notify();\n return found;\n};\n\nexport const discardFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\n): void => {\n if (!s.shared) {\n takeFailed(s, entry);\n return;\n }\n if (findFailed(s, entry) === undefined) throw unknownFailed(entry);\n void transact(s, () => {\n if (findFailed(s, entry) !== undefined) takeFailed(s, entry);\n });\n};\n\nexport const retryFailed = (\n s: Session,\n entry: StatewireClient.FailedCommand,\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 found = findFailed(s, entry);\n if (found === undefined) throw unknownFailed(entry);\n const params =\n found.meta === undefined\n ? found.params\n : (reviveValue([...found.params], found.meta) as unknown[]);\n const result = new Promise<unknown>((resolve, reject) => {\n const retry = () => {\n if (!s.running) {\n reject(new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }));\n return;\n }\n if (isFinished(s)) {\n reject(\n new StatewireSendError({ fate: \"aborted\", cause: \"stream-gone\" }),\n );\n return;\n }\n const current = findFailed(s, entry);\n if (current === undefined) {\n reject(unknownFailed(entry));\n return;\n }\n takeFailed(s, current);\n enqueueInner(\n s,\n {\n method: current.command,\n params: [...current.params],\n ...(current.meta !== undefined && { meta: current.meta }),\n },\n params,\n resolve,\n reject,\n );\n };\n if (!s.shared) {\n retry();\n wake(s);\n void pump(s);\n return;\n }\n void transact(s, retry).then(() => {\n wake(s);\n void pump(s);\n }, reject);\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, () => {\n if (!s.running || isFinished(s)) return;\n mint();\n }).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 onSessionLost: undefined,\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 documents: { mode: null, documents: new Map() },\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 if ((store.lock !== undefined) !== (s.shared !== false)) {\n throw new Error(\n \"statewire: session storage changed sharedness across renders — lock/subscribe must be present from the first render or never\",\n );\n }\n s.store = store;\n s.onSessionLost = options.onSessionLost;\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/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { StatewireSSE } from "./transports/sse.js";
1
+ import { StatewireHttp } from "./transports/sse.js";
2
2
  import { StatewireClient, StatewireResource, useStatewire } from "./statewire.js";
3
3
  import { Statewire, StatewireSendError } from "./types.js";
4
- import { StatewireWS } from "./transports/ws.js";
5
- export { type Statewire, StatewireClient, StatewireResource, StatewireSSE, StatewireSendError, StatewireWS, useStatewire };
4
+ import { StatewireWebsocket } from "./transports/ws.js";
5
+ export { type Statewire, StatewireClient, StatewireHttp, StatewireResource, StatewireSendError, StatewireWebsocket, useStatewire };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { StatewireSendError } from "./types.js";
2
2
  import { StatewireClient, StatewireResource, useStatewire } from "./statewire.js";
3
- import { StatewireSSE } from "./transports/sse.js";
4
- import { StatewireWS } from "./transports/ws.js";
5
- export { StatewireClient, StatewireResource, StatewireSSE, StatewireSendError, StatewireWS, useStatewire };
3
+ import { StatewireHttp } from "./transports/sse.js";
4
+ import { StatewireWebsocket } from "./transports/ws.js";
5
+ export { StatewireClient, StatewireHttp, StatewireResource, StatewireSendError, StatewireWebsocket, useStatewire };
@@ -197,7 +197,7 @@ declare namespace StatewireClient {
197
197
  type HeadersOption = HeadersInit | ((ctx: {
198
198
  staleAuth: boolean;
199
199
  }) => HeadersInit | Promise<HeadersInit>);
200
- type SSEOptions = {
200
+ type HttpOptions = {
201
201
  sessionStore?: SessionStorage | undefined;
202
202
  url: string;
203
203
  /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */
@@ -210,7 +210,7 @@ declare namespace StatewireClient {
210
210
  /** The broadcast idle flag's rising edge: the instance went quiet. */
211
211
  onDone?: () => void;
212
212
  };
213
- type WSOptions = {
213
+ type WebsocketOptions = {
214
214
  sessionStore?: SessionStorage | undefined;
215
215
  url: string;
216
216
  /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */
@@ -1 +1 @@
1
- {"version":3,"file":"statewire.js","names":["StatewireHost","useMemo","useRef","useState","useSyncExternalStore","createTapRoot","flushTapSync","resource","useContextProvider","useResource","useResources","withKey","ResourceElement","CONNECTED_CONNECTION","useStatewireCore","Statewire","TERMINAL","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","failed","getFailed","connection","failures","NonNullable","Error","commands","CommandsProxy","setContext","contextValue","Record","retryFailed","entry","FailedCommand","retry","discardFailed","discard","StatewireResource","root","disposed","constructor","ClientRoot","getValue","Connection","Promise","dispose","unmount","initialState","optimistic","Optimistic","materialize","Materialize","onStateChange","ctx","changes","Changes","onCommandChange","update","CommandUpdate","onConnectionChange","onError","error","ConnectionError","failureCovered","ConnectionState","status","reason","message","payload","attempt","cause","code","nextRetryAt","lastError","reconnect","degraded","ConnectionStatus","draft","command","Command","OptimisticContext","ts","seq","clientId","SendFailure","fate","predecessorLost","OnSessionLost","pending","ReadonlyArray","method","params","meta","failure","SessionCommand","SessionRecord","nextSeq","ctxNextSeq","verdicts","SessionVerdict","type","load","save","record","lock","fn","T","fin","Fin","HeadersOption","HeadersInit","staleAuth","SSEOptions","sessionStore","url","isNew","headers","fetch","globalThis","onSessionLost","onChange","onDone","WSOptions","protocols","query","webSocket","WebSocket"],"sources":["../src/statewire.ts"],"sourcesContent":["import type { StatewireHost } from \"./host\";\nimport { 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 { CONNECTED_CONNECTION, useStatewireCore } from \"./client/core\";\nimport type { Statewire } from \"./types\";\nimport type { TERMINAL } from \"./client/connection\";\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 failed = useSyncExternalStore(\n subscribe,\n core.getFailed,\n core.getFailed,\n );\n const connection = value.connection ?? CONNECTED_CONNECTION;\n\n return useMemo(() => {\n const failures = (): NonNullable<typeof value.failures> => {\n if (!value.failures) {\n throw new Error(\"statewire: this transport has no failed-send lane\");\n }\n return value.failures;\n };\n return {\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 failed,\n retryFailed: (entry: StatewireClient.FailedCommand) =>\n failures().retry(entry),\n discardFailed: (entry: StatewireClient.FailedCommand) =>\n failures().discard(entry),\n };\n }, [state, isBusy, failed, connection, core, value]);\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 get failed(): readonly StatewireClient.FailedCommand[] {\n return this.root.getValue().failed;\n }\n\n retryFailed(entry: StatewireClient.FailedCommand): Promise<unknown> {\n return this.root.getValue().retryFailed(entry);\n }\n\n discardFailed(entry: StatewireClient.FailedCommand): void {\n this.root.getValue().discardFailed(entry);\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 onError?: (error: ConnectionError) => void;\n /** Drops a retained failed entry once a canonical snapshot shows its effect landed; checked against each new snapshot. */\n failureCovered?: (\n state: NonNullable<TState>,\n entry: FailedCommand,\n ) => boolean;\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 /** Non-accepted sends retained in the session record; reload with it. */\n failed: readonly FailedCommand[];\n /** Re-enqueues the entry's command on fresh clocks and removes the entry. */\n retryFailed: (entry: FailedCommand) => Promise<unknown>;\n /** Removes the entry. */\n discardFailed: (entry: FailedCommand) => void;\n };\n\n /** `cause`/`nextRetryAt`/`lastError` are present only while waiting out the backoff timer; a dial in flight carries `attempt` alone. */\n export type ConnectionState =\n | {\n status: \"disconnected\";\n reason:\n | \"deferred\"\n | \"idle\"\n | \"gone\"\n | \"forbidden\"\n | \"protocol-error\"\n | \"unauthorized\";\n message?: string;\n payload?: unknown;\n }\n | {\n status: \"connecting\";\n /** 0 = the episode's first dial, >0 = retry. */\n attempt: number;\n cause?: \"dropped\" | \"reconnect\" | \"error\" | \"unauthorized\";\n code?: string;\n nextRetryAt?: number;\n lastError?: string;\n message?: string;\n }\n | { status: \"connected\" };\n export type Connection = ConnectionState & {\n error?: ConnectionError;\n reconnect: () => void;\n /** True while retrying (`connecting` with `attempt > 0`) or parked `gone`. */\n degraded: boolean;\n };\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 (a proven seq gap) 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\";\n predecessorLost?: true;\n }\n | {\n fate: \"lost\";\n cause: \"unmount\" | \"stream-gone\" | \"session-lost\";\n };\n\n /** Held commands a proven record gap settled `{fate: \"lost\", cause: \"session-lost\"}`; return \"requeue\" to re-enqueue them on the reset clocks. */\n export type OnSessionLost = (\n pending: ReadonlyArray<{\n method: string;\n params: readonly unknown[];\n ts: number;\n seq: number;\n clientId?: string;\n }>,\n ) => \"requeue\" | \"drop\";\n\n /** A non-accepted send retained for the user: the wire statement, its failure, and its original clocks. */\n export type FailedCommand = {\n readonly command: string;\n readonly params: readonly unknown[];\n readonly meta?: unknown;\n readonly failure: SendFailure;\n readonly ts: number;\n readonly seq: number;\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 /** Non-accepted sends retained for the user; survive record rebases and resets. */\n failed?: readonly FailedCommand[];\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: (typeof TERMINAL)[number];\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 ConnectionError = Error & { fin: StatewireHost.Fin };\n\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 /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */\n isNew?: boolean;\n headers?: HeadersOption;\n fetch?: typeof globalThis.fetch;\n onSessionLost?: OnSessionLost;\n onChange?: (connection: Connection) => void;\n onError?: (error: ConnectionError) => 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 /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */\n isNew?: boolean;\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 onSessionLost?: OnSessionLost;\n onChange?: (connection: Connection) => void;\n onError?: (error: ConnectionError) => void;\n /** The broadcast idle flag's rising edge: the instance went quiet. */\n onDone?: () => void;\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"statewire.js","names":["StatewireHost","useMemo","useRef","useState","useSyncExternalStore","createTapRoot","flushTapSync","resource","useContextProvider","useResource","useResources","withKey","ResourceElement","CONNECTED_CONNECTION","useStatewireCore","Statewire","TERMINAL","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","failed","getFailed","connection","failures","NonNullable","Error","commands","CommandsProxy","setContext","contextValue","Record","retryFailed","entry","FailedCommand","retry","discardFailed","discard","StatewireResource","root","disposed","constructor","ClientRoot","getValue","Connection","Promise","dispose","unmount","initialState","optimistic","Optimistic","materialize","Materialize","onStateChange","ctx","changes","Changes","onCommandChange","update","CommandUpdate","onConnectionChange","onError","error","ConnectionError","failureCovered","ConnectionState","status","reason","message","payload","attempt","cause","code","nextRetryAt","lastError","reconnect","degraded","ConnectionStatus","draft","command","Command","OptimisticContext","ts","seq","clientId","SendFailure","fate","predecessorLost","OnSessionLost","pending","ReadonlyArray","method","params","meta","failure","SessionCommand","SessionRecord","nextSeq","ctxNextSeq","verdicts","SessionVerdict","type","load","save","record","lock","fn","T","fin","Fin","HeadersOption","HeadersInit","staleAuth","HttpOptions","sessionStore","url","isNew","headers","fetch","globalThis","onSessionLost","onChange","onDone","WebsocketOptions","protocols","query","webSocket","WebSocket"],"sources":["../src/statewire.ts"],"sourcesContent":["import type { StatewireHost } from \"./host\";\nimport { 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 { CONNECTED_CONNECTION, useStatewireCore } from \"./client/core\";\nimport type { Statewire } from \"./types\";\nimport type { TERMINAL } from \"./client/connection\";\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 failed = useSyncExternalStore(\n subscribe,\n core.getFailed,\n core.getFailed,\n );\n const connection = value.connection ?? CONNECTED_CONNECTION;\n\n return useMemo(() => {\n const failures = (): NonNullable<typeof value.failures> => {\n if (!value.failures) {\n throw new Error(\"statewire: this transport has no failed-send lane\");\n }\n return value.failures;\n };\n return {\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 failed,\n retryFailed: (entry: StatewireClient.FailedCommand) =>\n failures().retry(entry),\n discardFailed: (entry: StatewireClient.FailedCommand) =>\n failures().discard(entry),\n };\n }, [state, isBusy, failed, connection, core, value]);\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 get failed(): readonly StatewireClient.FailedCommand[] {\n return this.root.getValue().failed;\n }\n\n retryFailed(entry: StatewireClient.FailedCommand): Promise<unknown> {\n return this.root.getValue().retryFailed(entry);\n }\n\n discardFailed(entry: StatewireClient.FailedCommand): void {\n this.root.getValue().discardFailed(entry);\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 onError?: (error: ConnectionError) => void;\n /** Drops a retained failed entry once a canonical snapshot shows its effect landed; checked against each new snapshot. */\n failureCovered?: (\n state: NonNullable<TState>,\n entry: FailedCommand,\n ) => boolean;\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 /** Non-accepted sends retained in the session record; reload with it. */\n failed: readonly FailedCommand[];\n /** Re-enqueues the entry's command on fresh clocks and removes the entry. */\n retryFailed: (entry: FailedCommand) => Promise<unknown>;\n /** Removes the entry. */\n discardFailed: (entry: FailedCommand) => void;\n };\n\n /** `cause`/`nextRetryAt`/`lastError` are present only while waiting out the backoff timer; a dial in flight carries `attempt` alone. */\n export type ConnectionState =\n | {\n status: \"disconnected\";\n reason:\n | \"deferred\"\n | \"idle\"\n | \"gone\"\n | \"forbidden\"\n | \"protocol-error\"\n | \"unauthorized\";\n message?: string;\n payload?: unknown;\n }\n | {\n status: \"connecting\";\n /** 0 = the episode's first dial, >0 = retry. */\n attempt: number;\n cause?: \"dropped\" | \"reconnect\" | \"error\" | \"unauthorized\";\n code?: string;\n nextRetryAt?: number;\n lastError?: string;\n message?: string;\n }\n | { status: \"connected\" };\n export type Connection = ConnectionState & {\n error?: ConnectionError;\n reconnect: () => void;\n /** True while retrying (`connecting` with `attempt > 0`) or parked `gone`. */\n degraded: boolean;\n };\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 (a proven seq gap) 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\";\n predecessorLost?: true;\n }\n | {\n fate: \"lost\";\n cause: \"unmount\" | \"stream-gone\" | \"session-lost\";\n };\n\n /** Held commands a proven record gap settled `{fate: \"lost\", cause: \"session-lost\"}`; return \"requeue\" to re-enqueue them on the reset clocks. */\n export type OnSessionLost = (\n pending: ReadonlyArray<{\n method: string;\n params: readonly unknown[];\n ts: number;\n seq: number;\n clientId?: string;\n }>,\n ) => \"requeue\" | \"drop\";\n\n /** A non-accepted send retained for the user: the wire statement, its failure, and its original clocks. */\n export type FailedCommand = {\n readonly command: string;\n readonly params: readonly unknown[];\n readonly meta?: unknown;\n readonly failure: SendFailure;\n readonly ts: number;\n readonly seq: number;\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 /** Non-accepted sends retained for the user; survive record rebases and resets. */\n failed?: readonly FailedCommand[];\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: (typeof TERMINAL)[number];\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 ConnectionError = Error & { fin: StatewireHost.Fin };\n\n export type HeadersOption =\n | HeadersInit\n | ((ctx: { staleAuth: boolean }) => HeadersInit | Promise<HeadersInit>);\n\n export type HttpOptions = {\n sessionStore?: SessionStorage | undefined;\n url: string;\n /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */\n isNew?: boolean;\n headers?: HeadersOption;\n fetch?: typeof globalThis.fetch;\n onSessionLost?: OnSessionLost;\n onChange?: (connection: Connection) => void;\n onError?: (error: ConnectionError) => void;\n /** The broadcast idle flag's rising edge: the instance went quiet. */\n onDone?: () => void;\n };\n\n export type WebsocketOptions = {\n sessionStore?: SessionStorage | undefined;\n url: string;\n /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */\n isNew?: boolean;\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 onSessionLost?: OnSessionLost;\n onChange?: (connection: Connection) => void;\n onError?: (error: ConnectionError) => void;\n /** The broadcast idle flag's rising edge: the instance went quiet. */\n onDone?: () => void;\n };\n}\n"],"mappings":";;;;;AAiBA,MAAMkB,uBAAuB,EAC3BC,WACAC,cAKAZ,mBAAmBS,uBAAuBG,eAExCX,YAAYU,SAAS,CACvB;AAIF,MAAMI,mBAAmBhB,SAASW,mBAAmB;AAErD,MAAaM,gBAIXE,YAC+C;CAC/C,MAAMK,SAAS7B,OAAOwB,OAAO;CAC7BK,OAAOC,UAAUN;CAEjB,MAAMN,UAAUV,aACdgB,QAAQO,SAASb,YAAYc,KAAAA,IACzB,CAACvB,QAAQ,WAAWe,QAAQO,QAAQb,OAAO,CAAC,IAC5C,CAAA,CACN,CAAC,CAAC;CACF,MAAMe,QAAQ1B,YACZc,iBAAiB;EAAEJ,WAAWO,QAAQP;EAAWC;CAAQ,CAAC,CAC5D;CACA,MAAMgB,OAAOtB,uBAAuBiB,OAAOC,SAASG,KAAK;CACzD,MAAM,CAACE,aAAalC,gBACXmC,aACLF,KAAKC,gBAAgB/B,aAAagC,QAAQ,CAAC,CAC/C;CAEA,MAAMC,QAAQnC,qBACZiC,WACAD,KAAKI,UACLJ,KAAKI,QACP;CACA,MAAMC,SAASrC,qBAAqBiC,WAAWD,KAAKM,SAASN,KAAKM,OAAO;CACzE,MAAMC,SAASvC,qBACbiC,WACAD,KAAKQ,WACLR,KAAKQ,SACP;CACA,MAAMC,aAAaV,MAAMU,cAAchC;CAEvC,OAAOZ,cAAc;EACnB,MAAM6C,iBAAqD;GACzD,IAAI,CAACX,MAAMW,UACT,MAAM,IAAIE,MAAM,mDAAmD;GAErE,OAAOb,MAAMW;EACf;EACA,OAAO;GACLP;GACAC,UAAUJ,KAAKI;GACfK;GACAI,UAAUb,KAAKa;GACfR;GACAU,aAAaC,iBAA0C;IACrD,IAAI,CAACjB,MAAMgB,YACT,MAAM,IAAIH,MACR,yDACF;IAEFb,MAAMgB,WAAWC,YAAY;GAC/B;GACAT;GACAW,cAAcC,UACZT,SAAS,CAAC,CAACW,MAAMF,KAAK;GACxBG,gBAAgBH,YACdT,SAAS,CAAC,CAACa,QAAQJ,OAAK;EAC5B;CACF,GAAG;EAAChB;EAAOE;EAAQE;EAAQE;EAAYT;EAAMD;CAAK,CAAC;AACrD;AAEA,MAAayB,qBAIXlC,YAEAnB,SAASiB,YAA+B,CAAC,CAACE,OAAO;AAEnD,IAAaL,kBAAb,MAGE;CACA;CACA,WAAmB;CAEnB0C,YAAYrC,SAAqD;EAC/D,MAAMsC,mBAAmBxC,aAAgCE,OAAO;EAChE,KAAKmC,OAAOxD,cAAc2D,UAAU;CACtC;CAEA,IAAIzB,QAAgB;EAClB,OAAO,KAAKsB,KAAKI,SAAS,CAAC,CAACzB,SAAS;CACvC;CAEA,IAAIK,aAAyC;EAC3C,OAAO,KAAKgB,KAAKI,SAAS,CAAC,CAACpB;CAC9B;CAEA,IAAII,WAA+C;EACjD,OAAO,KAAKY,KAAKI,SAAS,CAAC,CAAChB;CAC9B;CAEA,IAAIR,SAAkB;EACpB,OAAO,KAAKoB,KAAKI,SAAS,CAAC,CAACxB;CAC9B;CAEAU,WAAWhB,OAAsC;EAC/C,KAAK0B,KAAKI,SAAS,CAAC,CAACd,WAAWhB,KAAK;CACvC;CAEA,IAAIQ,SAAmD;EACrD,OAAO,KAAKkB,KAAKI,SAAS,CAAC,CAACtB;CAC9B;CAEAW,YAAYC,OAAwD;EAClE,OAAO,KAAKM,KAAKI,SAAS,CAAC,CAACX,YAAYC,KAAK;CAC/C;CAEAG,cAAcH,OAA4C;EACxD,KAAKM,KAAKI,SAAS,CAAC,CAACP,cAAcH,KAAK;CAC1C;CAEAlB,UAAUC,UAAkC;EAC1C,OAAO,KAAKuB,KAAKxB,UAAUC,QAAQ;CACrC;CAEA8B,UAAgB;EACd,IAAI,KAAKN,UAAU;EACnB,KAAKA,WAAW;EAChB,KAAKD,KAAKQ,QAAQ;CACpB;AACF"}
@@ -53,7 +53,7 @@ type RemoteLink = {
53
53
  parked: boolean;
54
54
  send: (frame: StatewireFrame) => Promise<StatewireSubmitResult>;
55
55
  };
56
- declare const StatewireSSE: <TState = any, TCommands extends Statewire.Commands = Statewire.Commands>(options: StatewireClient.SSEOptions) => ResourceElement<Statewire<TState | undefined, TCommands>>;
56
+ declare const StatewireHttp: <TState = any, TCommands extends Statewire.Commands = Statewire.Commands>(options: StatewireClient.HttpOptions) => ResourceElement<Statewire<TState | undefined, TCommands>>;
57
57
  //#endregion
58
- export { ConnectionState, RemoteLink, StatewireFrame, StatewireRemoteProps, StatewireSSE, StatewireSubmitResult };
58
+ export { ConnectionState, RemoteLink, StatewireFrame, StatewireHttp, StatewireRemoteProps, StatewireSubmitResult };
59
59
  //# sourceMappingURL=sse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sse.d.ts","names":[],"sources":["../../src/transports/sse.ts"],"mappings":";;;;;;;KA2BY;EACV;IAAQ;IAAgB;;EACxB;IAAQ;IAAgB;IAAmB;IAAgB;;;KAGjD;EACV;;EAEA,uBAAuB;EACvB,UAAU;IAAQ;IAAgB,KAAK;;EACvC,QAAQ;IAAQ;IAAgB,MAAM;;EACtC,SAAS,MAAM;EACf,YAAY,KAAK;EACjB,SAAS;EACT;EACA,WAAW,MAAM,cAAc;;KAGrB;EACN;;EACA;EAAiB,KAAK;;EACtB;;EACA;;KAEM,kBAAkB,gBAAgB;;KAGlC;EACV,YAAY,gBAAgB;;EAE5B;EACA,OAAO,OAAO,mBAAmB,QAAQ;;cAsO9B,eACX,cACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,eACtB,gBAAgB,UAAU,oBAAoB"}
1
+ {"version":3,"file":"sse.d.ts","names":[],"sources":["../../src/transports/sse.ts"],"mappings":";;;;;;;KA2BY;EACV;IAAQ;IAAgB;;EACxB;IAAQ;IAAgB;IAAmB;IAAgB;;;KAGjD;EACV;;EAEA,uBAAuB;EACvB,UAAU;IAAQ;IAAgB,KAAK;;EACvC,QAAQ;IAAQ;IAAgB,MAAM;;EACtC,SAAS,MAAM;EACf,YAAY,KAAK;EACjB,SAAS;EACT;EACA,WAAW,MAAM,cAAc;;KAGrB;EACN;;EACA;EAAiB,KAAK;;EACtB;;EACA;;KAEM,kBAAkB,gBAAgB;;KAGlC;EACV,YAAY,gBAAgB;;EAE5B;EACA,OAAO,OAAO,mBAAmB,QAAQ;;cAsO9B,gBACX,cACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,gBACtB,gBAAgB,UAAU,oBAAoB"}
@@ -149,9 +149,9 @@ const useSseLink = (options, ctx) => useLink({
149
149
  }
150
150
  }
151
151
  });
152
- const useStatewireSSE = (options) => useStatewireRemote(options, useSseLink);
153
- const StatewireSSE = resource(useStatewireSSE);
152
+ const useStatewireHttp = (options) => useStatewireRemote(options, useSseLink);
153
+ const StatewireHttp = resource(useStatewireHttp);
154
154
  //#endregion
155
- export { StatewireSSE };
155
+ export { StatewireHttp };
156
156
 
157
157
  //# sourceMappingURL=sse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sse.js","names":["flushTapSync","resource","ResourceElement","createSseParser","timing","settleFin","classify","handleEnvelope","resolveHeaders","unsupportedVersion","useLink","validateRefusalSyn","AttemptOutcome","Conn","StatewireCmd","StatewireEnvelope","StatewireSyn","Statewire","StatewireClient","StatewireHost","useStatewireRemote","PROTOCOL_VERSION","VERSION_HEADER","StatewireFrame","ctx","ops","seq","cmd","method","params","meta","StatewireRemoteProps","clientId","takeAttachLanes","onHello","args","syn","onOps","cmds","onCmds","onRefusal","onIdle","level","onDetach","onFinish","Fin","StatewireSubmitResult","type","ConnectionState","RemoteLink","connection","Connection","parked","send","frame","Promise","LEASE_HEADER","baseUrl","options","SSEOptions","url","replace","withExtra","headers","Headers","extra","Record","merged","name","value","Object","entries","set","timedFetch","input","init","RequestInit","signal","AbortSignal","timeout","Response","fetch","globalThis","consume","c","reader","ReadableStreamDefaultReader","Uint8Array","heartbeat","AbortController","dead","decoder","TextDecoder","parse","timer","setTimeout","abort","heartbeatTimeoutMs","result","ReadableStreamReadResult","read","clearTimeout","done","data","decode","stream","env","JSON","attemptStream","lease","authStale","lanes","body","undefined","stringify","headerTimer","res","accept","cache","any","ok","httpFin","Error","version","get","trim","cancel","catch","getReader","aborted","postFrame","lifetime","retryAfterMs","header","test","retry","Number","isSafeInteger","reason","status","message","code","refusalSyn","json","sendFrame","headerRetry","error","useSseLink","attemptOnce","SyntaxError","startsWith","useStatewireSSE","StatewireSSE","Commands","TState","TCommands"],"sources":["../../src/transports/sse.ts"],"sourcesContent":["import { flushTapSync, resource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { createSseParser } from \"./sse-parser\";\nimport { timing } from \"../client/timing\";\nimport {\n settleFin,\n classify,\n handleEnvelope,\n resolveHeaders,\n unsupportedVersion,\n useLink,\n validateRefusalSyn,\n} from \"../client/connection\";\nimport type {\n AttemptOutcome,\n Conn,\n StatewireCmd,\n StatewireEnvelope,\n StatewireSyn,\n} from \"../client/connection\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\nimport { useStatewireRemote } from \"./remote\";\nimport { PROTOCOL_VERSION, VERSION_HEADER } from \"../wire/version\";\n\n/** A client frame's lanes: stamped statements, strictly consecutive per lane. */\nexport type StatewireFrame = {\n ctx?: { ops: unknown[]; seq: number }[];\n cmd?: { method: string; params: unknown[]; meta?: unknown; seq: number }[];\n};\n\nexport type StatewireRemoteProps = {\n clientId: string;\n /** Lanes to ride the attach frame (no-lease supersession only); records the included seqs. */\n takeAttachLanes: () => StatewireFrame | null;\n onHello: (args: { ops: unknown[]; syn: StatewireSyn }) => void;\n onOps: (args: { ops: unknown[]; cmds: StatewireCmd[] }) => void;\n onCmds: (cmds: StatewireCmd[]) => void;\n onRefusal: (syn: StatewireSyn) => void;\n onIdle: (level: boolean) => void;\n onDetach: () => void;\n onFinish: (args: StatewireHost.Fin) => void;\n};\n\nexport type StatewireSubmitResult =\n | { type: \"ok\" }\n | { type: \"refusal\"; syn: StatewireSyn }\n | { type: \"stale-lease\" }\n | { type: \"no-lease\" };\n\nexport type ConnectionState = StatewireClient.ConnectionState;\n\n/** The live wire a remote session drives: connection status plus frame submission. */\nexport type RemoteLink = {\n connection: StatewireClient.Connection;\n /** A deferred first attach still waiting; `reconnect()` releases it. */\n parked: boolean;\n send: (frame: StatewireFrame) => Promise<StatewireSubmitResult>;\n};\n\nconst LEASE_HEADER = \"Statewire-Lease\";\n\nconst baseUrl = (options: StatewireClient.SSEOptions) =>\n options.url.replace(/\\/$/, \"\");\n\nconst withExtra = (headers: Headers, extra: Record<string, string>) => {\n const merged = new Headers(headers);\n for (const [name, value] of Object.entries(extra)) merged.set(name, value);\n return merged;\n};\n\nconst timedFetch = async (\n options: StatewireClient.SSEOptions,\n input: string,\n init: RequestInit & { signal: AbortSignal },\n timeout: AbortSignal,\n): Promise<Response> => {\n try {\n return await (options.fetch ?? globalThis.fetch)(input, init);\n } catch {\n throw classify(timeout);\n }\n};\n\nconst consume = async (\n c: Conn,\n reader: ReadableStreamDefaultReader<Uint8Array>,\n heartbeat: AbortController,\n dead: () => boolean,\n): Promise<AttemptOutcome> => {\n const decoder = new TextDecoder();\n const parse = createSseParser();\n for (;;) {\n const timer = setTimeout(\n () => heartbeat.abort(),\n timing.heartbeatTimeoutMs,\n );\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await reader.read();\n } catch {\n throw classify(heartbeat.signal);\n } finally {\n clearTimeout(timer);\n }\n if (result.done) return \"ended\";\n for (const data of parse(decoder.decode(result.value, { stream: true }))) {\n if (dead()) return \"ended\";\n const env = JSON.parse(data) as StatewireEnvelope;\n const done = flushTapSync(() => handleEnvelope(c, env));\n if (done) return done;\n }\n }\n};\n\nconst attemptStream = async (\n c: Conn,\n options: StatewireClient.SSEOptions,\n abort: AbortController,\n): Promise<AttemptOutcome> => {\n c.lease = null;\n const headers = await resolveHeaders(options.headers, c.authStale);\n c.authStale = false;\n const lanes = flushTapSync(() => c.ctx.takeAttachLanes());\n const body = lanes === null ? undefined : JSON.stringify(lanes);\n const heartbeat = new AbortController();\n const headerTimer = setTimeout(\n () => heartbeat.abort(),\n timing.heartbeatTimeoutMs,\n );\n let res: Response;\n try {\n res = await timedFetch(\n options,\n `${baseUrl(options)}/stream`,\n {\n method: body === undefined ? \"GET\" : \"POST\",\n headers: withExtra(headers, {\n \"content-type\": \"application/json\",\n \"Statewire-Client-Id\": c.ctx.clientId,\n accept: \"text/event-stream\",\n }),\n ...(body === undefined ? {} : { body }),\n cache: \"no-store\",\n signal: AbortSignal.any([abort.signal, heartbeat.signal]),\n },\n heartbeat.signal,\n );\n } finally {\n clearTimeout(headerTimer);\n }\n if (!res.ok) return flushTapSync(() => settleFin(c, httpFin(res)));\n if (!res.body)\n throw new Error(\"statewire: protocol error: stream response has no body\");\n const version = res.headers.get(VERSION_HEADER)?.trim();\n if (version !== undefined && version !== PROTOCOL_VERSION) {\n res.body.cancel().catch(() => {});\n return unsupportedVersion(c, version);\n }\n c.lease = res.headers.get(LEASE_HEADER);\n const reader = res.body.getReader();\n try {\n return await consume(c, reader, heartbeat, () => abort.signal.aborted);\n } finally {\n reader.cancel().catch(() => {});\n }\n};\n\nconst postFrame = async (\n c: Conn,\n options: StatewireClient.SSEOptions,\n lease: string,\n frame: StatewireFrame,\n timeout: AbortSignal,\n): Promise<Response> =>\n timedFetch(\n options,\n `${baseUrl(options)}/frames`,\n {\n method: \"POST\",\n headers: withExtra(new Headers(), {\n \"content-type\": \"application/json\",\n [LEASE_HEADER]: lease,\n }),\n body: JSON.stringify(frame),\n signal: AbortSignal.any([\n c.lifetime?.signal ?? AbortSignal.abort(),\n timeout,\n ]),\n },\n timeout,\n );\n\n// Delta-seconds only; anything else reads as absent.\nconst retryAfterMs = (res: Response): number | null => {\n const header = res.headers.get(\"retry-after\")?.trim();\n if (header === undefined || !/^\\d+$/.test(header)) return null;\n const retry = Number(header) * 1000;\n return Number.isSafeInteger(retry) ? retry : null;\n};\n\nconst httpFin = (res: Response): StatewireHost.Fin => ({\n reason:\n res.status === 401\n ? \"unauthorized\"\n : res.status === 403\n ? \"forbidden\"\n : res.status === 429 || res.status === 503\n ? \"reconnect\"\n : res.status >= 400 && res.status < 500\n ? \"protocol-error\"\n : \"error\",\n status: res.status,\n message: `HTTP ${res.status}`,\n ...(res.status === 429 || res.status === 503 ? { code: \"overloaded\" } : {}),\n ...(retryAfterMs(res) !== null ? { retry: retryAfterMs(res)! } : {}),\n});\n\nconst refusalSyn = async (res: Response): Promise<StatewireSyn> => {\n const body = (await res.json().catch(() => null)) as {\n syn?: StatewireSyn;\n } | null;\n const syn = body?.syn;\n if (typeof syn !== \"object\" || syn === null) {\n throw new Error(`HTTP ${res.status}`);\n }\n return validateRefusalSyn(syn);\n};\n\nconst sendFrame = async (\n c: Conn,\n options: StatewireClient.SSEOptions,\n frame: StatewireFrame,\n): Promise<StatewireSubmitResult> => {\n const lease = c.lease;\n if (lease === null) return { type: \"no-lease\" };\n const timeout = AbortSignal.timeout(timing.heartbeatTimeoutMs);\n const res = await postFrame(c, options, lease, frame, timeout);\n if (res.ok) return { type: \"ok\" };\n if (res.status === 429 || res.status === 409) {\n // The syn body retry wins; Retry-After covers 429s minted below the host.\n const headerRetry = res.status === 429 ? retryAfterMs(res) : null;\n const syn: StatewireSyn = await refusalSyn(res).catch((error: unknown) => {\n if (headerRetry === null) throw error;\n return { retry: headerRetry };\n });\n if (syn.retry === undefined && headerRetry !== null)\n syn.retry = headerRetry;\n return { type: \"refusal\", syn };\n }\n if (res.status === 423) return { type: \"stale-lease\" };\n flushTapSync(() => settleFin(c, httpFin(res)));\n c.abort?.abort();\n throw new Error(`HTTP ${res.status}`);\n};\n\nconst useSseLink = (\n options: StatewireClient.SSEOptions,\n ctx: StatewireRemoteProps,\n): RemoteLink =>\n useLink({\n ...options,\n ctx,\n attemptOnce: (c, abort) => attemptStream(c, options, abort),\n send: async (c, frame) => {\n try {\n return await sendFrame(c, options, frame);\n } catch (error) {\n if (\n error instanceof SyntaxError ||\n (error instanceof Error &&\n error.message.startsWith(\"statewire: protocol error:\"))\n ) {\n flushTapSync(() =>\n settleFin(c, { reason: \"protocol-error\", message: error.message }),\n );\n c.abort?.abort();\n }\n throw error;\n }\n },\n });\n\nconst useStatewireSSE = (\n options: StatewireClient.SSEOptions,\n): Statewire<any, any> => useStatewireRemote(options, useSseLink);\n\nexport const StatewireSSE = resource(useStatewireSSE) as <\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.SSEOptions,\n) => ResourceElement<Statewire<TState | undefined, TCommands>>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"sse.js","names":["flushTapSync","resource","ResourceElement","createSseParser","timing","settleFin","classify","handleEnvelope","resolveHeaders","unsupportedVersion","useLink","validateRefusalSyn","AttemptOutcome","Conn","StatewireCmd","StatewireEnvelope","StatewireSyn","Statewire","StatewireClient","StatewireHost","useStatewireRemote","PROTOCOL_VERSION","VERSION_HEADER","StatewireFrame","ctx","ops","seq","cmd","method","params","meta","StatewireRemoteProps","clientId","takeAttachLanes","onHello","args","syn","onOps","cmds","onCmds","onRefusal","onIdle","level","onDetach","onFinish","Fin","StatewireSubmitResult","type","ConnectionState","RemoteLink","connection","Connection","parked","send","frame","Promise","LEASE_HEADER","baseUrl","options","HttpOptions","url","replace","withExtra","headers","Headers","extra","Record","merged","name","value","Object","entries","set","timedFetch","input","init","RequestInit","signal","AbortSignal","timeout","Response","fetch","globalThis","consume","c","reader","ReadableStreamDefaultReader","Uint8Array","heartbeat","AbortController","dead","decoder","TextDecoder","parse","timer","setTimeout","abort","heartbeatTimeoutMs","result","ReadableStreamReadResult","read","clearTimeout","done","data","decode","stream","env","JSON","attemptStream","lease","authStale","lanes","body","undefined","stringify","headerTimer","res","accept","cache","any","ok","httpFin","Error","version","get","trim","cancel","catch","getReader","aborted","postFrame","lifetime","retryAfterMs","header","test","retry","Number","isSafeInteger","reason","status","message","code","refusalSyn","json","sendFrame","headerRetry","error","useSseLink","attemptOnce","SyntaxError","startsWith","useStatewireHttp","StatewireHttp","Commands","TState","TCommands"],"sources":["../../src/transports/sse.ts"],"sourcesContent":["import { flushTapSync, resource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { createSseParser } from \"./sse-parser\";\nimport { timing } from \"../client/timing\";\nimport {\n settleFin,\n classify,\n handleEnvelope,\n resolveHeaders,\n unsupportedVersion,\n useLink,\n validateRefusalSyn,\n} from \"../client/connection\";\nimport type {\n AttemptOutcome,\n Conn,\n StatewireCmd,\n StatewireEnvelope,\n StatewireSyn,\n} from \"../client/connection\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\nimport { useStatewireRemote } from \"./remote\";\nimport { PROTOCOL_VERSION, VERSION_HEADER } from \"../wire/version\";\n\n/** A client frame's lanes: stamped statements, strictly consecutive per lane. */\nexport type StatewireFrame = {\n ctx?: { ops: unknown[]; seq: number }[];\n cmd?: { method: string; params: unknown[]; meta?: unknown; seq: number }[];\n};\n\nexport type StatewireRemoteProps = {\n clientId: string;\n /** Lanes to ride the attach frame (no-lease supersession only); records the included seqs. */\n takeAttachLanes: () => StatewireFrame | null;\n onHello: (args: { ops: unknown[]; syn: StatewireSyn }) => void;\n onOps: (args: { ops: unknown[]; cmds: StatewireCmd[] }) => void;\n onCmds: (cmds: StatewireCmd[]) => void;\n onRefusal: (syn: StatewireSyn) => void;\n onIdle: (level: boolean) => void;\n onDetach: () => void;\n onFinish: (args: StatewireHost.Fin) => void;\n};\n\nexport type StatewireSubmitResult =\n | { type: \"ok\" }\n | { type: \"refusal\"; syn: StatewireSyn }\n | { type: \"stale-lease\" }\n | { type: \"no-lease\" };\n\nexport type ConnectionState = StatewireClient.ConnectionState;\n\n/** The live wire a remote session drives: connection status plus frame submission. */\nexport type RemoteLink = {\n connection: StatewireClient.Connection;\n /** A deferred first attach still waiting; `reconnect()` releases it. */\n parked: boolean;\n send: (frame: StatewireFrame) => Promise<StatewireSubmitResult>;\n};\n\nconst LEASE_HEADER = \"Statewire-Lease\";\n\nconst baseUrl = (options: StatewireClient.HttpOptions) =>\n options.url.replace(/\\/$/, \"\");\n\nconst withExtra = (headers: Headers, extra: Record<string, string>) => {\n const merged = new Headers(headers);\n for (const [name, value] of Object.entries(extra)) merged.set(name, value);\n return merged;\n};\n\nconst timedFetch = async (\n options: StatewireClient.HttpOptions,\n input: string,\n init: RequestInit & { signal: AbortSignal },\n timeout: AbortSignal,\n): Promise<Response> => {\n try {\n return await (options.fetch ?? globalThis.fetch)(input, init);\n } catch {\n throw classify(timeout);\n }\n};\n\nconst consume = async (\n c: Conn,\n reader: ReadableStreamDefaultReader<Uint8Array>,\n heartbeat: AbortController,\n dead: () => boolean,\n): Promise<AttemptOutcome> => {\n const decoder = new TextDecoder();\n const parse = createSseParser();\n for (;;) {\n const timer = setTimeout(\n () => heartbeat.abort(),\n timing.heartbeatTimeoutMs,\n );\n let result: ReadableStreamReadResult<Uint8Array>;\n try {\n result = await reader.read();\n } catch {\n throw classify(heartbeat.signal);\n } finally {\n clearTimeout(timer);\n }\n if (result.done) return \"ended\";\n for (const data of parse(decoder.decode(result.value, { stream: true }))) {\n if (dead()) return \"ended\";\n const env = JSON.parse(data) as StatewireEnvelope;\n const done = flushTapSync(() => handleEnvelope(c, env));\n if (done) return done;\n }\n }\n};\n\nconst attemptStream = async (\n c: Conn,\n options: StatewireClient.HttpOptions,\n abort: AbortController,\n): Promise<AttemptOutcome> => {\n c.lease = null;\n const headers = await resolveHeaders(options.headers, c.authStale);\n c.authStale = false;\n const lanes = flushTapSync(() => c.ctx.takeAttachLanes());\n const body = lanes === null ? undefined : JSON.stringify(lanes);\n const heartbeat = new AbortController();\n const headerTimer = setTimeout(\n () => heartbeat.abort(),\n timing.heartbeatTimeoutMs,\n );\n let res: Response;\n try {\n res = await timedFetch(\n options,\n `${baseUrl(options)}/stream`,\n {\n method: body === undefined ? \"GET\" : \"POST\",\n headers: withExtra(headers, {\n \"content-type\": \"application/json\",\n \"Statewire-Client-Id\": c.ctx.clientId,\n accept: \"text/event-stream\",\n }),\n ...(body === undefined ? {} : { body }),\n cache: \"no-store\",\n signal: AbortSignal.any([abort.signal, heartbeat.signal]),\n },\n heartbeat.signal,\n );\n } finally {\n clearTimeout(headerTimer);\n }\n if (!res.ok) return flushTapSync(() => settleFin(c, httpFin(res)));\n if (!res.body)\n throw new Error(\"statewire: protocol error: stream response has no body\");\n const version = res.headers.get(VERSION_HEADER)?.trim();\n if (version !== undefined && version !== PROTOCOL_VERSION) {\n res.body.cancel().catch(() => {});\n return unsupportedVersion(c, version);\n }\n c.lease = res.headers.get(LEASE_HEADER);\n const reader = res.body.getReader();\n try {\n return await consume(c, reader, heartbeat, () => abort.signal.aborted);\n } finally {\n reader.cancel().catch(() => {});\n }\n};\n\nconst postFrame = async (\n c: Conn,\n options: StatewireClient.HttpOptions,\n lease: string,\n frame: StatewireFrame,\n timeout: AbortSignal,\n): Promise<Response> =>\n timedFetch(\n options,\n `${baseUrl(options)}/frames`,\n {\n method: \"POST\",\n headers: withExtra(new Headers(), {\n \"content-type\": \"application/json\",\n [LEASE_HEADER]: lease,\n }),\n body: JSON.stringify(frame),\n signal: AbortSignal.any([\n c.lifetime?.signal ?? AbortSignal.abort(),\n timeout,\n ]),\n },\n timeout,\n );\n\n// Delta-seconds only; anything else reads as absent.\nconst retryAfterMs = (res: Response): number | null => {\n const header = res.headers.get(\"retry-after\")?.trim();\n if (header === undefined || !/^\\d+$/.test(header)) return null;\n const retry = Number(header) * 1000;\n return Number.isSafeInteger(retry) ? retry : null;\n};\n\nconst httpFin = (res: Response): StatewireHost.Fin => ({\n reason:\n res.status === 401\n ? \"unauthorized\"\n : res.status === 403\n ? \"forbidden\"\n : res.status === 429 || res.status === 503\n ? \"reconnect\"\n : res.status >= 400 && res.status < 500\n ? \"protocol-error\"\n : \"error\",\n status: res.status,\n message: `HTTP ${res.status}`,\n ...(res.status === 429 || res.status === 503 ? { code: \"overloaded\" } : {}),\n ...(retryAfterMs(res) !== null ? { retry: retryAfterMs(res)! } : {}),\n});\n\nconst refusalSyn = async (res: Response): Promise<StatewireSyn> => {\n const body = (await res.json().catch(() => null)) as {\n syn?: StatewireSyn;\n } | null;\n const syn = body?.syn;\n if (typeof syn !== \"object\" || syn === null) {\n throw new Error(`HTTP ${res.status}`);\n }\n return validateRefusalSyn(syn);\n};\n\nconst sendFrame = async (\n c: Conn,\n options: StatewireClient.HttpOptions,\n frame: StatewireFrame,\n): Promise<StatewireSubmitResult> => {\n const lease = c.lease;\n if (lease === null) return { type: \"no-lease\" };\n const timeout = AbortSignal.timeout(timing.heartbeatTimeoutMs);\n const res = await postFrame(c, options, lease, frame, timeout);\n if (res.ok) return { type: \"ok\" };\n if (res.status === 429 || res.status === 409) {\n // The syn body retry wins; Retry-After covers 429s minted below the host.\n const headerRetry = res.status === 429 ? retryAfterMs(res) : null;\n const syn: StatewireSyn = await refusalSyn(res).catch((error: unknown) => {\n if (headerRetry === null) throw error;\n return { retry: headerRetry };\n });\n if (syn.retry === undefined && headerRetry !== null)\n syn.retry = headerRetry;\n return { type: \"refusal\", syn };\n }\n if (res.status === 423) return { type: \"stale-lease\" };\n flushTapSync(() => settleFin(c, httpFin(res)));\n c.abort?.abort();\n throw new Error(`HTTP ${res.status}`);\n};\n\nconst useSseLink = (\n options: StatewireClient.HttpOptions,\n ctx: StatewireRemoteProps,\n): RemoteLink =>\n useLink({\n ...options,\n ctx,\n attemptOnce: (c, abort) => attemptStream(c, options, abort),\n send: async (c, frame) => {\n try {\n return await sendFrame(c, options, frame);\n } catch (error) {\n if (\n error instanceof SyntaxError ||\n (error instanceof Error &&\n error.message.startsWith(\"statewire: protocol error:\"))\n ) {\n flushTapSync(() =>\n settleFin(c, { reason: \"protocol-error\", message: error.message }),\n );\n c.abort?.abort();\n }\n throw error;\n }\n },\n });\n\nconst useStatewireHttp = (\n options: StatewireClient.HttpOptions,\n): Statewire<any, any> => useStatewireRemote(options, useSseLink);\n\nexport const StatewireHttp = resource(useStatewireHttp) as <\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.HttpOptions,\n) => ResourceElement<Statewire<TState | undefined, TCommands>>;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { applyOptimistic } from "../util/recordMutations.js";
2
- import { StatewireSSE } from "./sse.js";
2
+ import { StatewireHttp } from "./sse.js";
3
3
  import { openSSEStream, sseFrame } from "./fake-sse.js";
4
4
  import { commandFrame, createCounterElement, createSocketRecorder, settle } from "./fixtures.js";
5
5
  //#region src/transports/testing.ts
@@ -71,7 +71,7 @@ const createMockTransport = (initialState) => {
71
71
  return new Response(null, { status: 404 });
72
72
  });
73
73
  return {
74
- transport: StatewireSSE({
74
+ transport: StatewireHttp({
75
75
  url: `http://mock-${++mockCount}/api`,
76
76
  fetch: fakeFetch
77
77
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","names":["ResourceElement","StatewireEnvelope","StatewireSSE","StatewireFrame","Statewire","openSSEStream","sseFrame","FakeStreamHandle","tick","Promise","r","setTimeout","applyOptimistic","MockTransport","transport","TState","commands","method","params","context","setState","state","applied","seq","settle","payload","sendEnvelope","envelope","finish","reason","message","clientId","attached","mockCount","createMockTransport","initialState","finished","clients","Map","ctxSeq","streams","Set","stream","send","admit","id","frame","rec","get","statement","ctx","Math","max","root","ops","value","push","cmd","fakeFetch","input","RequestInfo","URL","init","RequestInit","Response","TypeError","url","String","headers","Headers","endsWith","has","set","JSON","parse","body","handle","op","path","syn","signal","undefined","json","status","fetch","next","type","fin","close","size"],"sources":["../../src/transports/testing.ts"],"sourcesContent":["import type { ResourceElement } from \"@assistant-ui/tap\";\nimport type { StatewireEnvelope } from \"../client/connection\";\nimport { StatewireSSE } from \"./sse\";\nimport type { StatewireFrame } from \"./sse\";\nimport type { Statewire } from \"../types\";\nimport { openSSEStream, sseFrame } from \"./fake-sse\";\nimport type { FakeStreamHandle } from \"./fake-sse\";\n\nexport * from \"./fixtures\";\n\n/** Let queued microtasks and op batches drain through the statewire client. */\nexport const tick = () => new Promise<void>((r) => setTimeout(r, 0));\n\nexport { applyOptimistic } from \"../util/recordMutations\";\n\nexport type MockTransport<TState> = {\n /** Pass as the `transport:` option of useStatewire / Harness. */\n transport: ResourceElement<Statewire<TState | undefined, any>>;\n /** Captured statements in arrival order: cmd as `{method, params}`, ctx as `{context}`. */\n commands: { method?: string; params?: unknown[]; context?: unknown }[];\n /** Replace the replicated state and broadcast it as a root snapshot op. */\n setState: (state: TState) => Promise<void>;\n /** Deliver a bare ack cmd packet on the stream. */\n applied: (seq: number) => Promise<void>;\n /** Deliver a terminal result cmd packet on the stream. */\n settle: (seq: number, payload?: unknown) => Promise<void>;\n /** Deliver an arbitrary envelope on the stream. */\n sendEnvelope: (envelope: StatewireEnvelope) => Promise<void>;\n /** End the stream with a fin; further attaches fail like a dead server. */\n finish: (reason: string, message?: string) => Promise<void>;\n readonly clientId: string;\n readonly attached: boolean;\n};\n\n/**\n * A mock statewire backend: serves `initialState` as the attach snapshot,\n * records submitted frames (receipt only — acks and results are delivered\n * from test code), and exposes the wire as a transport ResourceElement.\n */\nlet mockCount = 0;\n\nexport const createMockTransport = <TState>(\n initialState: TState,\n): MockTransport<TState> => {\n let state: unknown = initialState;\n let clientId = \"\";\n let finished = false;\n const clients = new Map<string, { seq: number; ctxSeq: number }>();\n const streams = new Set<FakeStreamHandle>();\n const commands: MockTransport<unknown>[\"commands\"] = [];\n\n const sendEnvelope = (envelope: StatewireEnvelope) => {\n for (const stream of streams) stream.send(sseFrame(envelope));\n return tick();\n };\n\n const admit = (id: string, frame: StatewireFrame) => {\n const rec = clients.get(id)!;\n for (const statement of frame.ctx ?? []) {\n rec.ctxSeq = Math.max(rec.ctxSeq, statement.seq);\n const root = statement.ops[0] as { value?: unknown } | undefined;\n commands.push({ context: root?.value });\n }\n for (const statement of frame.cmd ?? []) {\n rec.seq = Math.max(rec.seq, statement.seq);\n commands.push({ method: statement.method, params: statement.params });\n }\n };\n\n const fakeFetch = (async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n if (finished) throw new TypeError(\"fetch failed (finished)\");\n const url = String(input);\n const headers = new Headers(init?.headers);\n const id = headers.get(\"Statewire-Client-Id\") ?? \"\";\n if (url.endsWith(\"/stream\")) {\n clientId = id;\n if (!clients.has(id)) clients.set(id, { seq: 0, ctxSeq: 0 });\n const rec = clients.get(id)!;\n const frame = JSON.parse(String(init?.body ?? \"{}\")) as StatewireFrame;\n admit(id, frame);\n return openSSEStream(\n streams,\n id,\n (handle) => {\n handle.send(\n sseFrame({\n ops: [{ op: \"replace\", path: [], value: state }],\n syn: { seq: rec.seq, ctxSeq: rec.ctxSeq },\n }),\n );\n },\n init?.signal ?? undefined,\n { \"Statewire-Lease\": \"mock-lease\" },\n );\n }\n if (url.endsWith(\"/frames\")) {\n admit(clientId, JSON.parse(String(init?.body ?? \"{}\")) as StatewireFrame);\n return Response.json({});\n }\n return new Response(null, { status: 404 });\n }) as typeof fetch;\n\n return {\n transport: StatewireSSE({\n url: `http://mock-${++mockCount}/api`,\n fetch: fakeFetch,\n }),\n commands,\n setState: (next) => {\n state = next;\n return sendEnvelope({ ops: [{ op: \"replace\", path: [], value: next }] });\n },\n applied: (seq) => sendEnvelope({ cmd: [{ seq, type: \"applied\" }] }),\n settle: (seq, payload) =>\n sendEnvelope({\n cmd: [\n {\n seq,\n type: \"result\",\n ...(payload !== undefined && { payload }),\n },\n ],\n }),\n sendEnvelope,\n finish: async (reason, message) => {\n await sendEnvelope({\n fin: { reason, ...(message !== undefined && { message }) },\n });\n finished = true;\n for (const stream of [...streams]) stream.close();\n await tick();\n },\n get clientId() {\n return clientId;\n },\n get attached() {\n return streams.size > 0;\n },\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"testing.js","names":["ResourceElement","StatewireEnvelope","StatewireHttp","StatewireFrame","Statewire","openSSEStream","sseFrame","FakeStreamHandle","tick","Promise","r","setTimeout","applyOptimistic","MockTransport","transport","TState","commands","method","params","context","setState","state","applied","seq","settle","payload","sendEnvelope","envelope","finish","reason","message","clientId","attached","mockCount","createMockTransport","initialState","finished","clients","Map","ctxSeq","streams","Set","stream","send","admit","id","frame","rec","get","statement","ctx","Math","max","root","ops","value","push","cmd","fakeFetch","input","RequestInfo","URL","init","RequestInit","Response","TypeError","url","String","headers","Headers","endsWith","has","set","JSON","parse","body","handle","op","path","syn","signal","undefined","json","status","fetch","next","type","fin","close","size"],"sources":["../../src/transports/testing.ts"],"sourcesContent":["import type { ResourceElement } from \"@assistant-ui/tap\";\nimport type { StatewireEnvelope } from \"../client/connection\";\nimport { StatewireHttp } from \"./sse\";\nimport type { StatewireFrame } from \"./sse\";\nimport type { Statewire } from \"../types\";\nimport { openSSEStream, sseFrame } from \"./fake-sse\";\nimport type { FakeStreamHandle } from \"./fake-sse\";\n\nexport * from \"./fixtures\";\n\n/** Let queued microtasks and op batches drain through the statewire client. */\nexport const tick = () => new Promise<void>((r) => setTimeout(r, 0));\n\nexport { applyOptimistic } from \"../util/recordMutations\";\n\nexport type MockTransport<TState> = {\n /** Pass as the `transport:` option of useStatewire / Harness. */\n transport: ResourceElement<Statewire<TState | undefined, any>>;\n /** Captured statements in arrival order: cmd as `{method, params}`, ctx as `{context}`. */\n commands: { method?: string; params?: unknown[]; context?: unknown }[];\n /** Replace the replicated state and broadcast it as a root snapshot op. */\n setState: (state: TState) => Promise<void>;\n /** Deliver a bare ack cmd packet on the stream. */\n applied: (seq: number) => Promise<void>;\n /** Deliver a terminal result cmd packet on the stream. */\n settle: (seq: number, payload?: unknown) => Promise<void>;\n /** Deliver an arbitrary envelope on the stream. */\n sendEnvelope: (envelope: StatewireEnvelope) => Promise<void>;\n /** End the stream with a fin; further attaches fail like a dead server. */\n finish: (reason: string, message?: string) => Promise<void>;\n readonly clientId: string;\n readonly attached: boolean;\n};\n\n/**\n * A mock statewire backend: serves `initialState` as the attach snapshot,\n * records submitted frames (receipt only — acks and results are delivered\n * from test code), and exposes the wire as a transport ResourceElement.\n */\nlet mockCount = 0;\n\nexport const createMockTransport = <TState>(\n initialState: TState,\n): MockTransport<TState> => {\n let state: unknown = initialState;\n let clientId = \"\";\n let finished = false;\n const clients = new Map<string, { seq: number; ctxSeq: number }>();\n const streams = new Set<FakeStreamHandle>();\n const commands: MockTransport<unknown>[\"commands\"] = [];\n\n const sendEnvelope = (envelope: StatewireEnvelope) => {\n for (const stream of streams) stream.send(sseFrame(envelope));\n return tick();\n };\n\n const admit = (id: string, frame: StatewireFrame) => {\n const rec = clients.get(id)!;\n for (const statement of frame.ctx ?? []) {\n rec.ctxSeq = Math.max(rec.ctxSeq, statement.seq);\n const root = statement.ops[0] as { value?: unknown } | undefined;\n commands.push({ context: root?.value });\n }\n for (const statement of frame.cmd ?? []) {\n rec.seq = Math.max(rec.seq, statement.seq);\n commands.push({ method: statement.method, params: statement.params });\n }\n };\n\n const fakeFetch = (async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n if (finished) throw new TypeError(\"fetch failed (finished)\");\n const url = String(input);\n const headers = new Headers(init?.headers);\n const id = headers.get(\"Statewire-Client-Id\") ?? \"\";\n if (url.endsWith(\"/stream\")) {\n clientId = id;\n if (!clients.has(id)) clients.set(id, { seq: 0, ctxSeq: 0 });\n const rec = clients.get(id)!;\n const frame = JSON.parse(String(init?.body ?? \"{}\")) as StatewireFrame;\n admit(id, frame);\n return openSSEStream(\n streams,\n id,\n (handle) => {\n handle.send(\n sseFrame({\n ops: [{ op: \"replace\", path: [], value: state }],\n syn: { seq: rec.seq, ctxSeq: rec.ctxSeq },\n }),\n );\n },\n init?.signal ?? undefined,\n { \"Statewire-Lease\": \"mock-lease\" },\n );\n }\n if (url.endsWith(\"/frames\")) {\n admit(clientId, JSON.parse(String(init?.body ?? \"{}\")) as StatewireFrame);\n return Response.json({});\n }\n return new Response(null, { status: 404 });\n }) as typeof fetch;\n\n return {\n transport: StatewireHttp({\n url: `http://mock-${++mockCount}/api`,\n fetch: fakeFetch,\n }),\n commands,\n setState: (next) => {\n state = next;\n return sendEnvelope({ ops: [{ op: \"replace\", path: [], value: next }] });\n },\n applied: (seq) => sendEnvelope({ cmd: [{ seq, type: \"applied\" }] }),\n settle: (seq, payload) =>\n sendEnvelope({\n cmd: [\n {\n seq,\n type: \"result\",\n ...(payload !== undefined && { payload }),\n },\n ],\n }),\n sendEnvelope,\n finish: async (reason, message) => {\n await sendEnvelope({\n fin: { reason, ...(message !== undefined && { message }) },\n });\n finished = true;\n for (const stream of [...streams]) stream.close();\n await tick();\n },\n get clientId() {\n return clientId;\n },\n get attached() {\n return streams.size > 0;\n },\n };\n};\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { Statewire } from "../types.js";
3
3
  import { WS_SUBPROTOCOL } from "../wire/version.js";
4
4
  import { ResourceElement } from "@assistant-ui/tap";
5
5
  //#region src/transports/ws.d.ts
6
- declare const StatewireWS: <TState = any, TCommands extends Statewire.Commands = Statewire.Commands>(options: StatewireClient.WSOptions) => ResourceElement<Statewire<TState | undefined, TCommands>>;
6
+ declare const StatewireWebsocket: <TState = any, TCommands extends Statewire.Commands = Statewire.Commands>(options: StatewireClient.WebsocketOptions) => ResourceElement<Statewire<TState | undefined, TCommands>>;
7
7
  //#endregion
8
- export { StatewireWS, WS_SUBPROTOCOL };
8
+ export { StatewireWebsocket, WS_SUBPROTOCOL };
9
9
  //# sourceMappingURL=ws.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ws.d.ts","names":[],"sources":["../../src/transports/ws.ts"],"mappings":";;;;;cAwLa,cACX,cACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,cACtB,gBAAgB,UAAU,oBAAoB"}
1
+ {"version":3,"file":"ws.d.ts","names":[],"sources":["../../src/transports/ws.ts"],"mappings":";;;;;cAwLa,qBACX,cACA,kBAAkB,UAAU,WAAW,UAAU,UAEjD,SAAS,gBAAgB,qBACtB,gBAAgB,UAAU,oBAAoB"}
@@ -134,12 +134,12 @@ const useWsLink = (options, ctx) => {
134
134
  } else t2 = $[9];
135
135
  return useLink(t2);
136
136
  };
137
- const useStatewireWS = (options) => useStatewireRemote(options, useWsLink);
138
- const StatewireWS = resource(useStatewireWS);
137
+ const useStatewireWebsocket = (options) => useStatewireRemote(options, useWsLink);
138
+ const StatewireWebsocket = resource(useStatewireWebsocket);
139
139
  function _temp() {
140
140
  return { socket: null };
141
141
  }
142
142
  //#endregion
143
- export { StatewireWS, WS_SUBPROTOCOL };
143
+ export { StatewireWebsocket, WS_SUBPROTOCOL };
144
144
 
145
145
  //# sourceMappingURL=ws.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ws.js","names":["useState","flushTapSync","resource","ResourceElement","timing","attachFrame","handleEnvelope","unsupportedVersion","useLink","AttemptOutcome","Conn","StatewireEnvelope","Statewire","StatewireClient","useStatewireRemote","CLIENT_QUERY_PARAM","WS_SUBPROTOCOL","RemoteLink","StatewireFrame","StatewireSubmitResult","StatewireRemoteProps","WsChannel","socket","WebSocket","OPEN","socketUrl","options","WSOptions","clientId","url","query","params","URLSearchParams","set","resolved","URL","globalThis","location","href","protocol","replace","pathname","search","toString","runSocket","c","ws","frame","abort","AbortController","Promise","resolve","reject","timer","ReturnType","setTimeout","timedOut","outcome","closed","arm","clearTimeout","close","heartbeatTimeoutMs","signal","addEventListener","onerror","onopen","negotiated","trim","send","stale","Boolean","aborted","fail","error","Error","onmessage","event","env","JSON","parse","String","data","SyntaxError","Object","keys","length","done","onclose","attemptSocket","w","ctx","body","headers","throwIfAborted","protocols","webSocket","WS","extra","undefined","sendFrame","readyState","stringify","type","useWsLink","$","_c","_temp","t0","t1","_","t2","attemptOnce","useStatewireWS","StatewireWS","Commands","TState","TCommands"],"sources":["../../src/transports/ws.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { flushTapSync, resource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { timing } from \"../client/timing\";\nimport {\n attachFrame,\n handleEnvelope,\n unsupportedVersion,\n useLink,\n} from \"../client/connection\";\nimport type {\n AttemptOutcome,\n Conn,\n StatewireEnvelope,\n} from \"../client/connection\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\nimport { useStatewireRemote } from \"./remote\";\nimport { CLIENT_QUERY_PARAM } from \"../host/adapter\";\nimport { WS_SUBPROTOCOL } from \"../wire/version\";\nimport type {\n RemoteLink,\n StatewireFrame,\n StatewireSubmitResult,\n StatewireRemoteProps,\n} from \"./sse\";\n\ntype WsChannel = {\n socket: WebSocket | null;\n};\n\nconst OPEN = 1;\n\nexport { WS_SUBPROTOCOL };\n\nconst socketUrl = async (\n options: StatewireClient.WSOptions,\n clientId: string,\n) => {\n const { url, query } = options;\n const params = new URLSearchParams(\n typeof query === \"function\" ? await query() : query,\n );\n params.set(CLIENT_QUERY_PARAM, clientId);\n const resolved = new URL(url, globalThis.location?.href);\n resolved.protocol = resolved.protocol.replace(/^http/, \"ws\");\n resolved.pathname = `${resolved.pathname.replace(/\\/$/, \"\")}/ws`;\n resolved.search = params.toString();\n return resolved.href;\n};\n\nconst runSocket = (\n c: Conn,\n ws: WebSocket,\n frame: string,\n abort: AbortController,\n): Promise<AttemptOutcome> =>\n new Promise((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n let outcome: AttemptOutcome | null = null;\n let closed = false;\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n timedOut = true;\n ws.close();\n }, timing.heartbeatTimeoutMs);\n };\n arm();\n abort.signal.addEventListener(\"abort\", () => ws.close());\n ws.onerror = () => {};\n ws.onopen = () => {\n const negotiated = ws.protocol.trim();\n if (negotiated !== \"\" && negotiated !== WS_SUBPROTOCOL) {\n outcome = unsupportedVersion(c, negotiated);\n ws.close();\n return;\n }\n ws.send(frame);\n };\n const stale = () => Boolean(outcome) || closed || abort.signal.aborted;\n const fail = (error: unknown) => {\n clearTimeout(timer);\n reject(error instanceof Error ? error : new Error(\"protocol\"));\n ws.close();\n };\n ws.onmessage = (event) => {\n if (stale()) return;\n arm();\n let env: StatewireEnvelope;\n try {\n env = JSON.parse(String(event.data)) as StatewireEnvelope;\n } catch {\n fail(new SyntaxError(\"invalid JSON packet\"));\n return;\n }\n // {} heartbeats live below the packet layer: invisible to handlers.\n if (\n typeof env === \"object\" &&\n env !== null &&\n Object.keys(env).length === 0\n ) {\n return;\n }\n try {\n const done = flushTapSync(() => handleEnvelope(c, env));\n if (done) {\n outcome = done;\n ws.close();\n }\n } catch (error) {\n fail(error);\n }\n };\n ws.onclose = () => {\n closed = true;\n clearTimeout(timer);\n if (outcome) resolve(outcome);\n else reject(new Error(timedOut ? \"timeout\" : \"network\"));\n };\n });\n\nconst attemptSocket = async (\n c: Conn,\n w: WsChannel,\n options: StatewireClient.WSOptions,\n abort: AbortController,\n): Promise<AttemptOutcome> => {\n let ws: WebSocket | null = null;\n try {\n const url = await socketUrl(options, c.ctx.clientId);\n const { body } = await attachFrame(c, options.headers);\n abort.signal.throwIfAborted();\n const { protocols, webSocket } = options;\n const WS = webSocket ?? globalThis.WebSocket;\n if (!WS) throw new Error(\"no WebSocket implementation\");\n const extra =\n protocols === undefined\n ? []\n : typeof protocols === \"string\"\n ? [protocols]\n : protocols;\n ws = new WS(url, [WS_SUBPROTOCOL, ...extra]);\n w.socket = ws;\n return await runSocket(c, ws, body, abort);\n } finally {\n if (w.socket === ws) w.socket = null;\n }\n};\n\nconst sendFrame = (\n w: WsChannel,\n frame: StatewireFrame,\n): Promise<StatewireSubmitResult> => {\n const ws = w.socket;\n if (!ws || ws.readyState !== OPEN) {\n return Promise.reject(new Error(\"network\"));\n }\n try {\n ws.send(JSON.stringify(frame));\n } catch {\n return Promise.reject(new Error(\"network\"));\n }\n return Promise.resolve({ type: \"ok\" });\n};\n\nconst useWsLink = (\n options: StatewireClient.WSOptions,\n ctx: StatewireRemoteProps,\n): RemoteLink => {\n const [w] = useState((): WsChannel => ({ socket: null }));\n return useLink({\n ...options,\n ctx,\n attemptOnce: (c, abort) => attemptSocket(c, w, options, abort),\n send: (_, frame) => sendFrame(w, frame),\n });\n};\n\nconst useStatewireWS = (\n options: StatewireClient.WSOptions,\n): Statewire<any, any> => useStatewireRemote(options, useWsLink);\n\nexport const StatewireWS = resource(useStatewireWS) as <\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.WSOptions,\n) => ResourceElement<Statewire<TState | undefined, TCommands>>;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ws.js","names":["useState","flushTapSync","resource","ResourceElement","timing","attachFrame","handleEnvelope","unsupportedVersion","useLink","AttemptOutcome","Conn","StatewireEnvelope","Statewire","StatewireClient","useStatewireRemote","CLIENT_QUERY_PARAM","WS_SUBPROTOCOL","RemoteLink","StatewireFrame","StatewireSubmitResult","StatewireRemoteProps","WsChannel","socket","WebSocket","OPEN","socketUrl","options","WebsocketOptions","clientId","url","query","params","URLSearchParams","set","resolved","URL","globalThis","location","href","protocol","replace","pathname","search","toString","runSocket","c","ws","frame","abort","AbortController","Promise","resolve","reject","timer","ReturnType","setTimeout","timedOut","outcome","closed","arm","clearTimeout","close","heartbeatTimeoutMs","signal","addEventListener","onerror","onopen","negotiated","trim","send","stale","Boolean","aborted","fail","error","Error","onmessage","event","env","JSON","parse","String","data","SyntaxError","Object","keys","length","done","onclose","attemptSocket","w","ctx","body","headers","throwIfAborted","protocols","webSocket","WS","extra","undefined","sendFrame","readyState","stringify","type","useWsLink","$","_c","_temp","t0","t1","_","t2","attemptOnce","useStatewireWebsocket","StatewireWebsocket","Commands","TState","TCommands"],"sources":["../../src/transports/ws.ts"],"sourcesContent":["import { useState } from \"react\";\nimport { flushTapSync, resource } from \"@assistant-ui/tap\";\nimport type { ResourceElement } from \"@assistant-ui/tap\";\nimport { timing } from \"../client/timing\";\nimport {\n attachFrame,\n handleEnvelope,\n unsupportedVersion,\n useLink,\n} from \"../client/connection\";\nimport type {\n AttemptOutcome,\n Conn,\n StatewireEnvelope,\n} from \"../client/connection\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\nimport { useStatewireRemote } from \"./remote\";\nimport { CLIENT_QUERY_PARAM } from \"../host/adapter\";\nimport { WS_SUBPROTOCOL } from \"../wire/version\";\nimport type {\n RemoteLink,\n StatewireFrame,\n StatewireSubmitResult,\n StatewireRemoteProps,\n} from \"./sse\";\n\ntype WsChannel = {\n socket: WebSocket | null;\n};\n\nconst OPEN = 1;\n\nexport { WS_SUBPROTOCOL };\n\nconst socketUrl = async (\n options: StatewireClient.WebsocketOptions,\n clientId: string,\n) => {\n const { url, query } = options;\n const params = new URLSearchParams(\n typeof query === \"function\" ? await query() : query,\n );\n params.set(CLIENT_QUERY_PARAM, clientId);\n const resolved = new URL(url, globalThis.location?.href);\n resolved.protocol = resolved.protocol.replace(/^http/, \"ws\");\n resolved.pathname = `${resolved.pathname.replace(/\\/$/, \"\")}/ws`;\n resolved.search = params.toString();\n return resolved.href;\n};\n\nconst runSocket = (\n c: Conn,\n ws: WebSocket,\n frame: string,\n abort: AbortController,\n): Promise<AttemptOutcome> =>\n new Promise((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let timedOut = false;\n let outcome: AttemptOutcome | null = null;\n let closed = false;\n const arm = () => {\n clearTimeout(timer);\n timer = setTimeout(() => {\n timedOut = true;\n ws.close();\n }, timing.heartbeatTimeoutMs);\n };\n arm();\n abort.signal.addEventListener(\"abort\", () => ws.close());\n ws.onerror = () => {};\n ws.onopen = () => {\n const negotiated = ws.protocol.trim();\n if (negotiated !== \"\" && negotiated !== WS_SUBPROTOCOL) {\n outcome = unsupportedVersion(c, negotiated);\n ws.close();\n return;\n }\n ws.send(frame);\n };\n const stale = () => Boolean(outcome) || closed || abort.signal.aborted;\n const fail = (error: unknown) => {\n clearTimeout(timer);\n reject(error instanceof Error ? error : new Error(\"protocol\"));\n ws.close();\n };\n ws.onmessage = (event) => {\n if (stale()) return;\n arm();\n let env: StatewireEnvelope;\n try {\n env = JSON.parse(String(event.data)) as StatewireEnvelope;\n } catch {\n fail(new SyntaxError(\"invalid JSON packet\"));\n return;\n }\n // {} heartbeats live below the packet layer: invisible to handlers.\n if (\n typeof env === \"object\" &&\n env !== null &&\n Object.keys(env).length === 0\n ) {\n return;\n }\n try {\n const done = flushTapSync(() => handleEnvelope(c, env));\n if (done) {\n outcome = done;\n ws.close();\n }\n } catch (error) {\n fail(error);\n }\n };\n ws.onclose = () => {\n closed = true;\n clearTimeout(timer);\n if (outcome) resolve(outcome);\n else reject(new Error(timedOut ? \"timeout\" : \"network\"));\n };\n });\n\nconst attemptSocket = async (\n c: Conn,\n w: WsChannel,\n options: StatewireClient.WebsocketOptions,\n abort: AbortController,\n): Promise<AttemptOutcome> => {\n let ws: WebSocket | null = null;\n try {\n const url = await socketUrl(options, c.ctx.clientId);\n const { body } = await attachFrame(c, options.headers);\n abort.signal.throwIfAborted();\n const { protocols, webSocket } = options;\n const WS = webSocket ?? globalThis.WebSocket;\n if (!WS) throw new Error(\"no WebSocket implementation\");\n const extra =\n protocols === undefined\n ? []\n : typeof protocols === \"string\"\n ? [protocols]\n : protocols;\n ws = new WS(url, [WS_SUBPROTOCOL, ...extra]);\n w.socket = ws;\n return await runSocket(c, ws, body, abort);\n } finally {\n if (w.socket === ws) w.socket = null;\n }\n};\n\nconst sendFrame = (\n w: WsChannel,\n frame: StatewireFrame,\n): Promise<StatewireSubmitResult> => {\n const ws = w.socket;\n if (!ws || ws.readyState !== OPEN) {\n return Promise.reject(new Error(\"network\"));\n }\n try {\n ws.send(JSON.stringify(frame));\n } catch {\n return Promise.reject(new Error(\"network\"));\n }\n return Promise.resolve({ type: \"ok\" });\n};\n\nconst useWsLink = (\n options: StatewireClient.WebsocketOptions,\n ctx: StatewireRemoteProps,\n): RemoteLink => {\n const [w] = useState((): WsChannel => ({ socket: null }));\n return useLink({\n ...options,\n ctx,\n attemptOnce: (c, abort) => attemptSocket(c, w, options, abort),\n send: (_, frame) => sendFrame(w, frame),\n });\n};\n\nconst useStatewireWebsocket = (\n options: StatewireClient.WebsocketOptions,\n): Statewire<any, any> => useStatewireRemote(options, useWsLink);\n\nexport const StatewireWebsocket = resource(useStatewireWebsocket) as <\n TState = any,\n TCommands extends Statewire.Commands = Statewire.Commands,\n>(\n options: StatewireClient.WebsocketOptions,\n) => ResourceElement<Statewire<TState | undefined, TCommands>>;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region src/util/randomId.ts
2
- const randomId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
2
+ const randomId = () => Array.from(crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16)), (byte) => byte.toString(16).padStart(2, "0")).join("");
3
3
  //#endregion
4
4
  export { randomId };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"randomId.js","names":["randomId","crypto","randomUUID","Date","now","toString","Math","random","slice"],"sources":["../../src/util/randomId.ts"],"sourcesContent":["export const randomId = (): string =>\n typeof crypto !== \"undefined\" && \"randomUUID\" in crypto\n ? crypto.randomUUID()\n : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n"],"mappings":";AAAA,MAAaA,iBACX,OAAOC,WAAW,eAAe,gBAAgBA,SAC7CA,OAAOC,WAAW,IAClB,GAAGC,KAAKC,IAAI,CAAC,CAACC,SAAS,EAAE,EAAC,GAAIC,KAAKC,OAAO,CAAC,CAACF,SAAS,EAAE,CAAC,CAACG,MAAM,GAAG,EAAE"}
1
+ {"version":3,"file":"randomId.js","names":["randomId","Array","from","crypto","getRandomValues","Uint8Array","byte","toString","padStart","join"],"sources":["../../src/util/randomId.ts"],"sourcesContent":["export const randomId = (): string =>\n Array.from(crypto.getRandomValues(new Uint8Array(16)), (byte) =>\n byte.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n"],"mappings":";AAAA,MAAaA,iBACXC,MAAMC,KAAKC,OAAOC,gCAAgB,IAAIC,WAAW,EAAE,CAAC,IAAIC,SACtDA,KAAKC,SAAS,EAAE,CAAC,CAACC,SAAS,GAAG,GAAG,CACnC,CAAC,CAACC,KAAK,EAAE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "statewire",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "State over the wire: snapshot-first delta streaming and command submission for any state and any command",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -22,7 +22,7 @@ import {
22
22
  } from "./sessionStore";
23
23
  import { backoff } from "./timing";
24
24
  import { createMethodProxy } from "../util/methodProxy";
25
- import { randomId } from "../util/randomId";
25
+ import { randomId as newClientId } from "../util/randomId";
26
26
  import { StatewireSendError } from "../types";
27
27
  import type {
28
28
  RemoteLink,
@@ -60,8 +60,6 @@ const protocolError = (message: string): never => {
60
60
  throw new Error(`statewire: protocol error: ${message}`);
61
61
  };
62
62
 
63
- const newClientId = () => `c-${randomId()}`;
64
-
65
63
  const rejectedSend = (
66
64
  failure: StatewireClient.SendFailure,
67
65
  ): Promise<unknown> => {
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type { Statewire } from "./types";
2
2
  export { StatewireClient, useStatewire, StatewireResource } from "./statewire";
3
- export { StatewireSSE } from "./transports/sse";
4
- export { StatewireWS } from "./transports/ws";
3
+ export { StatewireHttp } from "./transports/sse";
4
+ export { StatewireWebsocket } from "./transports/ws";
5
5
  export { StatewireSendError } from "./types";
package/src/statewire.ts CHANGED
@@ -373,7 +373,7 @@ export namespace StatewireClient {
373
373
  | HeadersInit
374
374
  | ((ctx: { staleAuth: boolean }) => HeadersInit | Promise<HeadersInit>);
375
375
 
376
- export type SSEOptions = {
376
+ export type HttpOptions = {
377
377
  sessionStore?: SessionStorage | undefined;
378
378
  url: string;
379
379
  /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */
@@ -387,7 +387,7 @@ export namespace StatewireClient {
387
387
  onDone?: () => void;
388
388
  };
389
389
 
390
- export type WSOptions = {
390
+ export type WebsocketOptions = {
391
391
  sessionStore?: SessionStorage | undefined;
392
392
  url: string;
393
393
  /** The session does not exist on the server yet: the first attach waits for the first command send (or an explicit `reconnect()`). */
@@ -61,7 +61,7 @@ export type RemoteLink = {
61
61
 
62
62
  const LEASE_HEADER = "Statewire-Lease";
63
63
 
64
- const baseUrl = (options: StatewireClient.SSEOptions) =>
64
+ const baseUrl = (options: StatewireClient.HttpOptions) =>
65
65
  options.url.replace(/\/$/, "");
66
66
 
67
67
  const withExtra = (headers: Headers, extra: Record<string, string>) => {
@@ -71,7 +71,7 @@ const withExtra = (headers: Headers, extra: Record<string, string>) => {
71
71
  };
72
72
 
73
73
  const timedFetch = async (
74
- options: StatewireClient.SSEOptions,
74
+ options: StatewireClient.HttpOptions,
75
75
  input: string,
76
76
  init: RequestInit & { signal: AbortSignal },
77
77
  timeout: AbortSignal,
@@ -116,7 +116,7 @@ const consume = async (
116
116
 
117
117
  const attemptStream = async (
118
118
  c: Conn,
119
- options: StatewireClient.SSEOptions,
119
+ options: StatewireClient.HttpOptions,
120
120
  abort: AbortController,
121
121
  ): Promise<AttemptOutcome> => {
122
122
  c.lease = null;
@@ -169,7 +169,7 @@ const attemptStream = async (
169
169
 
170
170
  const postFrame = async (
171
171
  c: Conn,
172
- options: StatewireClient.SSEOptions,
172
+ options: StatewireClient.HttpOptions,
173
173
  lease: string,
174
174
  frame: StatewireFrame,
175
175
  timeout: AbortSignal,
@@ -230,7 +230,7 @@ const refusalSyn = async (res: Response): Promise<StatewireSyn> => {
230
230
 
231
231
  const sendFrame = async (
232
232
  c: Conn,
233
- options: StatewireClient.SSEOptions,
233
+ options: StatewireClient.HttpOptions,
234
234
  frame: StatewireFrame,
235
235
  ): Promise<StatewireSubmitResult> => {
236
236
  const lease = c.lease;
@@ -256,7 +256,7 @@ const sendFrame = async (
256
256
  };
257
257
 
258
258
  const useSseLink = (
259
- options: StatewireClient.SSEOptions,
259
+ options: StatewireClient.HttpOptions,
260
260
  ctx: StatewireRemoteProps,
261
261
  ): RemoteLink =>
262
262
  useLink({
@@ -282,13 +282,13 @@ const useSseLink = (
282
282
  },
283
283
  });
284
284
 
285
- const useStatewireSSE = (
286
- options: StatewireClient.SSEOptions,
285
+ const useStatewireHttp = (
286
+ options: StatewireClient.HttpOptions,
287
287
  ): Statewire<any, any> => useStatewireRemote(options, useSseLink);
288
288
 
289
- export const StatewireSSE = resource(useStatewireSSE) as <
289
+ export const StatewireHttp = resource(useStatewireHttp) as <
290
290
  TState = any,
291
291
  TCommands extends Statewire.Commands = Statewire.Commands,
292
292
  >(
293
- options: StatewireClient.SSEOptions,
293
+ options: StatewireClient.HttpOptions,
294
294
  ) => ResourceElement<Statewire<TState | undefined, TCommands>>;
@@ -1,6 +1,6 @@
1
1
  import type { ResourceElement } from "@assistant-ui/tap";
2
2
  import type { StatewireEnvelope } from "../client/connection";
3
- import { StatewireSSE } from "./sse";
3
+ import { StatewireHttp } from "./sse";
4
4
  import type { StatewireFrame } from "./sse";
5
5
  import type { Statewire } from "../types";
6
6
  import { openSSEStream, sseFrame } from "./fake-sse";
@@ -104,7 +104,7 @@ export const createMockTransport = <TState>(
104
104
  }) as typeof fetch;
105
105
 
106
106
  return {
107
- transport: StatewireSSE({
107
+ transport: StatewireHttp({
108
108
  url: `http://mock-${++mockCount}/api`,
109
109
  fetch: fakeFetch,
110
110
  }),
@@ -34,7 +34,7 @@ const OPEN = 1;
34
34
  export { WS_SUBPROTOCOL };
35
35
 
36
36
  const socketUrl = async (
37
- options: StatewireClient.WSOptions,
37
+ options: StatewireClient.WebsocketOptions,
38
38
  clientId: string,
39
39
  ) => {
40
40
  const { url, query } = options;
@@ -124,7 +124,7 @@ const runSocket = (
124
124
  const attemptSocket = async (
125
125
  c: Conn,
126
126
  w: WsChannel,
127
- options: StatewireClient.WSOptions,
127
+ options: StatewireClient.WebsocketOptions,
128
128
  abort: AbortController,
129
129
  ): Promise<AttemptOutcome> => {
130
130
  let ws: WebSocket | null = null;
@@ -166,7 +166,7 @@ const sendFrame = (
166
166
  };
167
167
 
168
168
  const useWsLink = (
169
- options: StatewireClient.WSOptions,
169
+ options: StatewireClient.WebsocketOptions,
170
170
  ctx: StatewireRemoteProps,
171
171
  ): RemoteLink => {
172
172
  const [w] = useState((): WsChannel => ({ socket: null }));
@@ -178,13 +178,13 @@ const useWsLink = (
178
178
  });
179
179
  };
180
180
 
181
- const useStatewireWS = (
182
- options: StatewireClient.WSOptions,
181
+ const useStatewireWebsocket = (
182
+ options: StatewireClient.WebsocketOptions,
183
183
  ): Statewire<any, any> => useStatewireRemote(options, useWsLink);
184
184
 
185
- export const StatewireWS = resource(useStatewireWS) as <
185
+ export const StatewireWebsocket = resource(useStatewireWebsocket) as <
186
186
  TState = any,
187
187
  TCommands extends Statewire.Commands = Statewire.Commands,
188
188
  >(
189
- options: StatewireClient.WSOptions,
189
+ options: StatewireClient.WebsocketOptions,
190
190
  ) => ResourceElement<Statewire<TState | undefined, TCommands>>;
@@ -1,4 +1,4 @@
1
1
  export const randomId = (): string =>
2
- typeof crypto !== "undefined" && "randomUUID" in crypto
3
- ? crypto.randomUUID()
4
- : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
2
+ Array.from(crypto.getRandomValues(new Uint8Array(16)), (byte) =>
3
+ byte.toString(16).padStart(2, "0"),
4
+ ).join("");