statewire 0.19.2 → 0.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +5 -4
- package/dist/client/connection.js.map +1 -1
- package/dist/client/core.js +1 -1
- package/dist/client/core.js.map +1 -1
- package/dist/client/timing.d.ts +2 -0
- package/dist/client/timing.d.ts.map +1 -1
- package/dist/client/timing.js +5 -4
- package/dist/client/timing.js.map +1 -1
- package/package.json +1 -1
- package/src/client/connection.ts +6 -3
- package/src/client/core.ts +1 -1
- package/src/client/timing.ts +12 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","names":[],"sources":["../../src/client/connection.ts"],"mappings":";;;;;KAqBY;EACV;EACA;EACA;;;cAIW;KAQD;EACV;EACA;EACA,2BAA2B;EAC3B;EACA;EACA;EACA;;EAEA;;KAGU;EACV;EACA;IACE;IACA;IACA;IACA;;EAEF;EACA;EACA;;KAGU;EACV;EACA,MAAM;EACN;EACA;EACA,MAAM;EACN,MAAM,cAAc;;KAGV;EAAS;EAAkB;;KAoC3B;KAEA;EACV,cAAc,kBAAkB;EAChC,YAAY,gBAAgB;EAC5B;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OAAO,gBAAgB;EACvB,SAAS;EACT;EACA,MAAM;EACN,MAAM;EACN,OAAO;EACP,UAAU;EACV,KAAK;EACL,UAAU,OAAO,gBAAgB;EACjC,WAAW,YAAY,gBAAgB;EACvC,cAAc,OAAO,oBAAoB,QAAQ;EACjD,SAAS,YAAY,gBAAgB;EACrC;;cA4GW,qBAAsB,mBAAiB;cA0KvC,YAAa,GAAG,MAAM,KAAK,cAAc,QAAM;cAgE/C,iBACX,GAAG,MACH,mBACC;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","names":[],"sources":["../../src/client/connection.ts"],"mappings":";;;;;KAqBY;EACV;EACA;EACA;;;cAIW;KAQD;EACV;EACA;EACA,2BAA2B;EAC3B;EACA;EACA;EACA;;EAEA;;KAGU;EACV;EACA;IACE;IACA;IACA;IACA;;EAEF;EACA;EACA;;KAGU;EACV;EACA,MAAM;EACN;EACA;EACA,MAAM;EACN,MAAM,cAAc;;KAGV;EAAS;EAAkB;;KAoC3B;KAEA;EACV,cAAc,kBAAkB;EAChC,YAAY,gBAAgB;EAC5B;EACA;EACA;EACA;EACA;EACA;EACA;EACA,OAAO,gBAAgB;EACvB,SAAS;EACT;EACA,MAAM;EACN,MAAM;EACN,OAAO;EACP,UAAU;EACV,KAAK;EACL,UAAU,OAAO,gBAAgB;EACjC,WAAW,YAAY,gBAAgB;EACvC,cAAc,OAAO,oBAAoB,QAAQ;EACjD,SAAS,YAAY,gBAAgB;EACrC;;cA4GW,qBAAsB,mBAAiB;cA0KvC,YAAa,GAAG,MAAM,KAAK,cAAc,QAAM;cAgE/C,iBACX,GAAG,MACH,mBACC;cA6IU,qBAAsB,GAAG,MAAM,oBAAkB;cAUjD,iBACX,SAAS,gBAAgB,2BACzB,uBACC,QAAQ;cAME,cACX,GAAG,MACH,SAAS,gBAAgB,8BAAyB;;;;cAwBvC,UACX,OAAO,kBAAkB;EACvB;EACA;EACA,aAAa,YAAY,gBAAgB;EACzC,YAAY,OAAO,gBAAgB;EACnC,KAAK;EACL,cAAc,GAAG,MAAM,OAAO,oBAAoB,QAAQ;EAC1D,OAAO,GAAG,MAAM,OAAO,mBAAmB,QAAQ;MAEnD;cAuFU,WAAY,SAAS,gBAAW"}
|
|
@@ -281,13 +281,13 @@ const handleEnvelope = (c, value) => {
|
|
|
281
281
|
}
|
|
282
282
|
return null;
|
|
283
283
|
};
|
|
284
|
-
const dialing = (c) => setStatus(c, c.
|
|
285
|
-
status: "connecting",
|
|
286
|
-
degraded: false
|
|
287
|
-
} : {
|
|
284
|
+
const dialing = (c) => setStatus(c, c.connection.status === "retrying" ? {
|
|
288
285
|
status: "retrying",
|
|
289
286
|
attempt: c.attempt,
|
|
290
287
|
degraded: true
|
|
288
|
+
} : {
|
|
289
|
+
status: "connecting",
|
|
290
|
+
degraded: false
|
|
291
291
|
});
|
|
292
292
|
const scheduleRetry = (c, failure, immediate) => {
|
|
293
293
|
if (c.liveAt !== null && Date.now() - c.liveAt >= timing.backoffResetMs) c.attempt = 0;
|
|
@@ -295,6 +295,7 @@ const scheduleRetry = (c, failure, immediate) => {
|
|
|
295
295
|
c.attempt += 1;
|
|
296
296
|
c.episode ??= { cause: "dropped" };
|
|
297
297
|
const delay = Math.max(immediate ? 0 : backoff(c.attempt), c.retryAt - Date.now());
|
|
298
|
+
if (delay === 0) return delay;
|
|
298
299
|
setStatus(c, {
|
|
299
300
|
status: "retrying",
|
|
300
301
|
degraded: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.js","names":["negotiationHeaders","validateSelection","parseNegotiation","StatewireProtocol","useEffect","useRef","useState","flushTapSync","reviveOps","reviveValue","backoff","retryHint","timing","isStorageError","ConnectionState","RemoteLink","StatewireFrame","StatewireRemoteProps","StatewireSubmitResult","StatewireClient","StatewireHost","Episode","cause","message","code","TERMINAL","const","StatewireCmd","protocol","seq","type","payload","meta","dur","StatewireSyn","version","protocols","name","record","id","idle","retry","StatewireEnvelope","ops","cmd","next","syn","fin","Fin","Gate","latched","wake","newGate","undefined","takeGate","g","was","waitGate","timeoutMs","Promise","resolve","timer","setTimeout","clearTimeout","openGate","AttemptOutcome","Conn","negotiation","Options","connection","Connection","parked","lease","attempt","authDenials","authStale","liveAt","retryAt","error","ConnectionError","episode","awaitingHello","held","gate","abort","AbortController","lifetime","ctx","onError","onChange","attemptOnce","notify","reconnect","sameState","a","b","status","nextRetryAt","lastError","reason","setStatus","c","storageFailed","Error","degraded","protocolError","isObject","value","Record","Array","isArray","isNonnegativeSafeInteger","Number","isSafeInteger","isPositiveSafeInteger","validateOptionalString","field","validateSynProtocols","hello","entry","validateSynScalars","validateRefusalSyn","validateCmd","validateFin","validateEnvelope","releaseHeld","length","onCmds","cmdsOf","env","snapshotOf","helloSynOf","isWakeHello","handleHello","onHello","onIdle","Date","now","warnedUnknownSynFact","warnUnknownSynFact","console","warn","deliverSyn","onRefusal","Object","keys","deliverEnvelope","onOps","cmds","push","settleFin","finish","denial","terminal","report","assign","onFinish","handleEnvelope","dialing","scheduleRetry","failure","immediate","backoffResetMs","delay","Math","max","reconnectConn","run","alive","outcome","pending","beforeAttach","signal","aborted","SyntaxError","test","onDetach","unsupportedVersion","resolveHeaders","headers","HeadersOption","staleAuth","Headers","attachFrame","resolved","entries","has","set","persistence","lanes","takeAttachLanes","body","JSON","stringify","fromEntries","useLink","props","url","isNew","send","frame","latest","current","setConnection","conn","link","wireVersion","applicationProtocols","classify","timeout","AbortSignal"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import {\n negotiationHeaders,\n validateSelection,\n parseNegotiation,\n} from \"../wire/protocol\";\nimport type { StatewireProtocol } from \"../wire/protocol\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveValue } from \"../wire/meta\";\nimport { backoff, retryHint, timing } from \"./timing\";\nimport { isStorageError } from \"./storageError\";\nimport type {\n ConnectionState,\n RemoteLink,\n StatewireFrame,\n StatewireRemoteProps,\n StatewireSubmitResult,\n} from \"../transports/sse\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\n\nexport type Episode = {\n cause: \"dropped\" | \"reconnect\" | \"error\" | \"unauthorized\";\n message?: string;\n code?: string;\n};\n\n/** The terminal cmd verdict types; \"applied\" is the sole non-terminal type. */\nexport const TERMINAL = [\n \"result\",\n \"rejected\",\n \"failed\",\n \"crashed\",\n \"expired\",\n] as const;\n\nexport type StatewireCmd = {\n protocol: string;\n seq: number;\n type?: \"applied\" | (typeof TERMINAL)[number];\n code?: string;\n message?: string;\n payload?: unknown;\n meta?: unknown;\n /** Cumulative: resending through this seq will never be needed. */\n dur?: boolean;\n};\n\nexport type StatewireSyn = {\n version?: string;\n protocols?: {\n name: string;\n version?: string;\n record?: \"ephemeral\";\n seq?: number;\n }[];\n id?: string;\n idle?: boolean;\n retry?: number;\n};\n\nexport type StatewireEnvelope = {\n ops?: unknown[];\n cmd?: StatewireCmd[];\n next?: true;\n idle?: boolean;\n syn?: StatewireSyn;\n fin?: StatewireHost.Fin;\n};\n\nexport type Gate = { latched: boolean; wake: (() => void) | undefined };\n\nconst newGate = (): Gate => ({ latched: false, wake: undefined });\n\nconst takeGate = (g: Gate) => {\n const was = g.latched;\n g.latched = false;\n return was;\n};\n\nconst waitGate = (g: Gate, timeoutMs?: number) => {\n if (g.latched) {\n g.latched = false;\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n g.wake = undefined;\n resolve();\n }, timeoutMs);\n g.wake = () => {\n clearTimeout(timer);\n g.wake = undefined;\n resolve();\n };\n });\n};\n\nconst openGate = (g: Gate) => {\n if (g.wake) g.wake();\n else g.latched = true;\n};\n\nexport type AttemptOutcome = \"stop\" | \"reattach\" | \"ended\" | \"idle\";\n\nexport type Conn = {\n negotiation?: StatewireProtocol.Options;\n connection: StatewireClient.Connection;\n parked: boolean;\n lease: string | null;\n attempt: number;\n authDenials: number;\n authStale: boolean;\n liveAt: number | null;\n retryAt: number;\n error: StatewireClient.ConnectionError | undefined;\n episode: Episode | null;\n awaitingHello: boolean;\n held: StatewireCmd[];\n gate: Gate;\n abort: AbortController | null;\n lifetime: AbortController | null;\n ctx: StatewireRemoteProps;\n onError: (error: StatewireClient.ConnectionError) => void;\n onChange: (connection: StatewireClient.Connection) => void;\n attemptOnce: (abort: AbortController) => Promise<AttemptOutcome>;\n notify: (connection: StatewireClient.Connection) => void;\n reconnect: () => void;\n};\n\nconst sameState = (a: ConnectionState, b: ConnectionState): boolean => {\n if (a.status !== b.status) return false;\n if (a.status === \"retrying\" && b.status === \"retrying\") {\n return (\n a.attempt === b.attempt &&\n a.cause === b.cause &&\n a.code === b.code &&\n a.nextRetryAt === b.nextRetryAt &&\n a.lastError === b.lastError &&\n a.message === b.message\n );\n }\n if (a.status === \"standby\" && b.status === \"standby\") {\n return a.reason === b.reason;\n }\n if (a.status === \"stopped\" && b.status === \"stopped\") {\n return (\n a.reason === b.reason &&\n a.message === b.message &&\n a.payload === b.payload\n );\n }\n return true;\n};\n\nconst setStatus = (c: Conn, next: ConnectionState) => {\n if (sameState(next, c.connection) && c.connection.error === c.error) return;\n c.connection = {\n ...next,\n ...(c.error === undefined ? {} : { error: c.error }),\n reconnect: c.reconnect,\n };\n c.notify(c.connection);\n c.onChange(c.connection);\n};\n\nconst storageFailed = (c: Conn, error: Error) => {\n c.error = error;\n c.onError(error);\n flushTapSync(() =>\n setStatus(c, {\n status: \"stopped\",\n reason: \"storage-error\",\n degraded: true,\n message: error.message,\n }),\n );\n c.abort?.abort();\n};\n\nconst protocolError = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isNonnegativeSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) >= 0;\n\nconst isPositiveSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) > 0;\n\nconst validateOptionalString = (value: unknown, field: string): void => {\n if (value !== undefined && typeof value !== \"string\") {\n protocolError(`${field} must be a string`);\n }\n};\n\nconst validateSynProtocols = (value: unknown, hello: boolean): void => {\n if (value === undefined) return;\n if (!Array.isArray(value))\n return protocolError(\"syn.protocols must be an array\");\n for (const entry of value) {\n if (!isObject(entry))\n return protocolError(\"syn.protocols entry must be an object\");\n if (typeof entry[\"name\"] !== \"string\")\n protocolError(\"syn.protocols[].name must be a string\");\n if (\n !hello &&\n (entry[\"version\"] !== undefined || entry[\"record\"] !== undefined)\n )\n protocolError(\"invalid mid-stream syn\");\n if (\n hello\n ? !isNonnegativeSafeInteger(entry[\"seq\"])\n : entry[\"seq\"] !== undefined && !isNonnegativeSafeInteger(entry[\"seq\"])\n )\n protocolError(\"syn.protocols[].seq must be a nonnegative safe integer\");\n if (hello && entry[\"record\"] === \"ephemeral\" && entry[\"seq\"] !== 0)\n protocolError(\"ephemeral lane hello seq must be 0\");\n }\n};\n\nconst validateSynScalars = (syn: Record<string, unknown>, hello: boolean) => {\n validateSynProtocols(syn[\"protocols\"], hello);\n if (syn[\"retry\"] !== undefined && !isNonnegativeSafeInteger(syn[\"retry\"])) {\n protocolError(\"syn.retry must be a nonnegative safe integer\");\n }\n validateOptionalString(syn[\"id\"], \"syn.id\");\n if (syn[\"idle\"] !== undefined && typeof syn[\"idle\"] !== \"boolean\") {\n protocolError(\"syn.idle must be a boolean\");\n }\n};\n\nexport const validateRefusalSyn = (value: unknown): StatewireSyn => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value, false);\n if (\n value[\"id\"] !== undefined ||\n value[\"idle\"] !== undefined ||\n value[\"version\"] !== undefined\n ) {\n protocolError(\"invalid refusal syn\");\n }\n if (value[\"protocols\"] === undefined && value[\"retry\"] === undefined) {\n protocolError(\"refusal syn has no watermarks or retry\");\n }\n return value as StatewireSyn;\n};\n\nconst validateCmd = (value: unknown): value is StatewireCmd => {\n if (!isObject(value)) return protocolError(\"cmd entry must be an object\");\n if (typeof value[\"protocol\"] !== \"string\") {\n protocolError(\"cmd.protocol must be a string\");\n }\n if (!isPositiveSafeInteger(value[\"seq\"])) {\n protocolError(\"cmd.seq must be a positive safe integer\");\n }\n validateOptionalString(value[\"type\"], \"cmd.type\");\n validateOptionalString(value[\"code\"], \"cmd.code\");\n validateOptionalString(value[\"message\"], \"cmd.message\");\n if (value[\"dur\"] !== undefined && value[\"dur\"] !== true) {\n protocolError(\"cmd.dur must be true\");\n }\n return true;\n};\n\nconst validateFin = (value: unknown): value is StatewireHost.Fin => {\n if (!isObject(value)) return protocolError(\"fin must be an object\");\n if (typeof value[\"reason\"] !== \"string\") {\n protocolError(\"fin.reason must be a string\");\n }\n validateOptionalString(value[\"message\"], \"fin.message\");\n validateOptionalString(value[\"code\"], \"fin.code\");\n if (\n value[\"status\"] !== undefined &&\n !isNonnegativeSafeInteger(value[\"status\"])\n )\n protocolError(\"fin.status must be a nonnegative safe integer\");\n if (value[\"retry\"] !== undefined && !isNonnegativeSafeInteger(value[\"retry\"]))\n protocolError(\"fin.retry must be a nonnegative safe integer\");\n return true;\n};\n\nconst validateEnvelope = (value: unknown): StatewireEnvelope => {\n if (!isObject(value)) return protocolError(\"packet must be an object\");\n if (value[\"ops\"] !== undefined && !Array.isArray(value[\"ops\"])) {\n protocolError(\"ops must be an array\");\n }\n if (value[\"cmd\"] !== undefined) {\n const cmd = value[\"cmd\"];\n if (!Array.isArray(cmd)) return protocolError(\"cmd must be an array\");\n for (const entry of cmd) validateCmd(entry);\n }\n if (value[\"idle\"] !== undefined && typeof value[\"idle\"] !== \"boolean\") {\n protocolError(\"idle must be a boolean\");\n }\n if (value[\"next\"] !== undefined) {\n if (value[\"next\"] !== true) protocolError(\"next must be true\");\n if (\n value[\"cmd\"] === undefined ||\n value[\"ops\"] !== undefined ||\n value[\"fin\"] !== undefined\n ) {\n protocolError(\"next must ride a cmd-only packet\");\n }\n }\n if (value[\"fin\"] !== undefined) validateFin(value[\"fin\"]);\n return value as StatewireEnvelope;\n};\n\n// A hold's release delivers, never settles: fin and bare close both drain it.\nconst releaseHeld = (c: Conn) => {\n if (c.held.length === 0) return;\n const held = c.held;\n c.held = [];\n c.ctx.onCmds(held);\n};\n\nconst cmdsOf = (env: StatewireEnvelope): StatewireCmd[] => {\n if (env.cmd === undefined) return [];\n return env.cmd;\n};\n\nconst snapshotOf = (env: StatewireEnvelope): unknown[] => {\n const ops = env.ops;\n if (ops === undefined) return protocolError(\"hello missing snapshot\");\n return reviveOps(ops);\n};\n\nconst helloSynOf = (env: StatewireEnvelope): StatewireSyn => {\n if (!isObject(env.syn)) return protocolError(\"expected hello\");\n validateSynScalars(env.syn, true);\n if (env.syn[\"retry\"] !== undefined) {\n protocolError(\"hello syn cannot carry retry\");\n }\n return env.syn as StatewireSyn;\n};\n\n// A host that woke on a retained socket re-sends its hello; the snapshot\n// replaces the session the way a fresh attach would.\nconst isWakeHello = (env: StatewireEnvelope) =>\n isObject(env.syn) && env.syn[\"version\"] !== undefined;\n\nconst handleHello = (c: Conn, env: StatewireEnvelope) => {\n const syn = helloSynOf(env);\n if (c.negotiation !== undefined) validateSelection(syn, c.negotiation);\n const ops = snapshotOf(env);\n c.ctx.onHello({\n ops,\n syn,\n });\n if (env.cmd !== undefined) c.ctx.onCmds(env.cmd);\n c.ctx.onIdle(syn.idle ?? false);\n c.awaitingHello = false;\n c.error = undefined;\n c.liveAt = Date.now();\n c.authDenials = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\", degraded: false });\n};\n\nlet warnedUnknownSynFact = false;\n\nconst warnUnknownSynFact = () => {\n if (warnedUnknownSynFact) return;\n warnedUnknownSynFact = true;\n console.warn(\"statewire: ignoring unknown syn fact\");\n};\n\nconst deliverSyn = (c: Conn, value: unknown) => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value, false);\n if (value[\"version\"] !== undefined || value[\"idle\"] !== undefined) {\n protocolError(\"invalid mid-stream syn\");\n }\n if (value[\"protocols\"] !== undefined || value[\"retry\"] !== undefined) {\n c.ctx.onRefusal(validateRefusalSyn(value));\n return;\n }\n if (value[\"id\"] !== undefined) return;\n if (Object.keys(value).length === 0) {\n protocolError(\"invalid mid-stream syn\");\n }\n warnUnknownSynFact();\n};\n\nconst deliverEnvelope = (c: Conn, env: StatewireEnvelope) => {\n if (env.syn !== undefined) deliverSyn(c, env.syn);\n if (env.ops !== undefined) {\n const held = c.held;\n c.held = [];\n c.ctx.onOps({\n ops: reviveOps(env.ops),\n cmds: [...held, ...cmdsOf(env)],\n });\n } else if (env.cmd !== undefined) {\n const cmds = cmdsOf(env);\n if (env.next === true) c.held.push(...cmds);\n else c.ctx.onCmds(cmds);\n }\n if (typeof env.idle === \"boolean\") c.ctx.onIdle(env.idle);\n};\n\nexport const settleFin = (c: Conn, fin: StatewireHost.Fin): AttemptOutcome => {\n const finish =\n fin.meta === undefined\n ? fin\n : { ...fin, payload: reviveValue(fin.payload, fin.meta) };\n releaseHeld(c);\n c.retryAt = Date.now() + retryHint(finish.retry ?? 0);\n if (finish.reason === \"idle\") {\n c.ctx.onIdle(true);\n c.attempt = 0;\n c.episode = null;\n c.error = undefined;\n setStatus(c, { status: \"standby\", reason: \"idle\", degraded: false });\n return \"idle\";\n }\n const denial = finish.reason === \"unauthorized\";\n const terminal =\n finish.reason === \"gone\" ||\n finish.reason === \"forbidden\" ||\n finish.reason === \"protocol-error\" ||\n (denial && c.authDenials > 0);\n if (denial) {\n c.authDenials += 1;\n c.authStale = true;\n }\n const report =\n finish.reason !== \"reconnect\" &&\n finish.reason !== \"gone\" &&\n (!denial || terminal);\n c.error = report\n ? Object.assign(new Error(finish.message ?? finish.reason), { fin: finish })\n : undefined;\n if (c.error) c.onError(c.error);\n if (!terminal) {\n c.episode = {\n cause:\n finish.reason === \"reconnect\"\n ? \"reconnect\"\n : denial\n ? \"unauthorized\"\n : \"error\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.code !== undefined && { code: finish.code }),\n };\n if (denial) openGate(c.gate);\n return \"reattach\";\n }\n c.ctx.onFinish(finish);\n setStatus(c, {\n status: \"stopped\",\n degraded: true,\n reason: denial\n ? \"unauthorized\"\n : finish.reason === \"forbidden\"\n ? \"forbidden\"\n : finish.reason === \"protocol-error\"\n ? \"protocol-error\"\n : \"gone\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.payload !== undefined && { payload: finish.payload }),\n });\n return \"stop\";\n};\n\nexport const handleEnvelope = (\n c: Conn,\n value: unknown,\n): AttemptOutcome | null => {\n const env = validateEnvelope(value);\n if (c.awaitingHello || isWakeHello(env)) {\n if (env.fin !== undefined) return settleFin(c, env.fin);\n handleHello(c, env);\n return null;\n }\n deliverEnvelope(c, env);\n if (env.fin !== undefined) return settleFin(c, env.fin);\n if (c.connection.status !== \"connected\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\", degraded: false });\n }\n return null;\n};\n\nconst dialing = (c: Conn) =>\n setStatus(\n c,\n c.attempt === 0\n ? { status: \"connecting\", degraded: false }\n : { status: \"retrying\", attempt: c.attempt, degraded: true },\n );\n\nconst scheduleRetry = (\n c: Conn,\n failure: string | undefined,\n immediate: boolean,\n) => {\n if (c.liveAt !== null && Date.now() - c.liveAt >= timing.backoffResetMs) {\n c.attempt = 0;\n }\n c.liveAt = null;\n c.attempt += 1;\n c.episode ??= { cause: \"dropped\" };\n const delay = Math.max(\n immediate ? 0 : backoff(c.attempt),\n c.retryAt - Date.now(),\n );\n setStatus(c, {\n status: \"retrying\",\n degraded: true,\n attempt: c.attempt,\n ...c.episode,\n nextRetryAt: Date.now() + delay,\n ...(failure !== undefined && { lastError: failure }),\n });\n return delay;\n};\n\nconst reconnectConn = (c: Conn) => {\n if (!c.lifetime) return;\n if (c.connection.status === \"standby\" || c.connection.status === \"stopped\") {\n // A reconnect out of a park starts a fresh episode: first dial, attempt 0.\n c.attempt = 0;\n c.authDenials = 0;\n c.episode = null;\n flushTapSync(() => dialing(c));\n }\n openGate(c.gate);\n c.abort?.abort();\n};\n\nconst run = async (c: Conn, lifetime: AbortController, gate: Gate) => {\n const alive = () => c.lifetime === lifetime;\n if (c.parked) {\n await waitGate(gate);\n if (!alive()) return;\n c.parked = false;\n }\n while (alive()) {\n if (c.retryAt > Date.now()) {\n await waitGate(gate, c.retryAt - Date.now());\n continue;\n }\n // The dial is in flight: attempt alone, no backoff fields.\n flushTapSync(() => dialing(c));\n const abort = new AbortController();\n c.abort = abort;\n c.awaitingHello = true;\n c.held = [];\n let outcome: AttemptOutcome | undefined;\n let failure: string | undefined;\n try {\n const pending = c.ctx.beforeAttach?.();\n if (pending) await pending;\n if (!alive()) return;\n outcome = await c.attemptOnce(abort);\n } catch (error) {\n if (!abort.signal.aborted) {\n if (isStorageError(error)) {\n storageFailed(c, error);\n outcome = \"stop\";\n } else if (\n error instanceof SyntaxError ||\n (error instanceof Error &&\n /^(statewire: protocol error:|Statewire cannot apply)/.test(\n error.message,\n ))\n ) {\n outcome = flushTapSync(() =>\n settleFin(c, { reason: \"protocol-error\", message: error.message }),\n );\n } else if (c.authStale) {\n outcome = flushTapSync(() =>\n settleFin(c, {\n reason: \"unauthorized\",\n message:\n error instanceof Error\n ? error.message\n : \"credential refresh failed\",\n }),\n );\n }\n failure =\n error instanceof Error && error.message ? error.message : \"network\";\n }\n }\n abort.abort();\n if (!alive()) return;\n flushTapSync(() => {\n releaseHeld(c);\n c.ctx.onDetach();\n });\n if (!alive()) return;\n if (c.connection.status === \"stopped\") outcome = \"stop\";\n if (outcome === \"stop\" || outcome === \"idle\") {\n await waitGate(gate);\n continue;\n }\n const immediate = takeGate(gate);\n const delay = flushTapSync(() => scheduleRetry(c, failure, immediate));\n if (delay === 0) continue;\n await waitGate(gate, delay);\n }\n};\n\nexport const unsupportedVersion = (c: Conn, version: string): AttemptOutcome =>\n flushTapSync(() =>\n handleEnvelope(c, {\n fin: {\n reason: \"protocol-error\",\n message: `unsupported protocol version: ${version || '\"\"'}`,\n },\n }),\n ) ?? \"stop\";\n\nexport const resolveHeaders = async (\n headers: StatewireClient.HeadersOption | undefined,\n staleAuth: boolean,\n): Promise<Headers> =>\n new Headers(\n typeof headers === \"function\" ? await headers({ staleAuth }) : headers,\n );\n\n// The stale flag clears only once the resolver returns: a throwing refresh keeps it for the next attempt.\nexport const attachFrame = async (\n c: Conn,\n headers: StatewireClient.HeadersOption | undefined,\n) => {\n const pending = c.ctx.beforeAttach?.();\n if (pending) await pending;\n const resolved = await resolveHeaders(headers, c.authStale);\n for (const [name, value] of Object.entries(\n negotiationHeaders(c.negotiation ?? {}),\n )) {\n if (!resolved.has(name)) resolved.set(name, value);\n }\n c.negotiation = parseNegotiation(resolved);\n c.authStale = false;\n const persistence = c.ctx.beforeAttach?.();\n if (persistence) await persistence;\n const lanes = flushTapSync(() => c.ctx.takeAttachLanes());\n return {\n headers: resolved,\n body: JSON.stringify({\n headers: Object.fromEntries(resolved),\n ...(lanes ?? {}),\n }),\n };\n};\n\nexport const useLink = (\n props: StatewireProtocol.Options & {\n url: string;\n isNew?: boolean | undefined;\n onChange?: ((connection: StatewireClient.Connection) => void) | undefined;\n onError?: ((error: StatewireClient.ConnectionError) => void) | undefined;\n ctx: StatewireRemoteProps;\n attemptOnce: (c: Conn, abort: AbortController) => Promise<AttemptOutcome>;\n send: (c: Conn, frame: StatewireFrame) => Promise<StatewireSubmitResult>;\n },\n): RemoteLink => {\n const latest = useRef(props);\n latest.current = props;\n const [, setConnection] = useState<StatewireClient.Connection | null>(null);\n const [c] = useState((): Conn => {\n const conn: Conn = {\n parked: props.isNew ?? false,\n lease: null,\n attempt: 0,\n authDenials: 0,\n authStale: false,\n liveAt: null,\n retryAt: 0,\n error: undefined,\n episode: null,\n awaitingHello: true,\n held: [],\n abort: null,\n gate: newGate(),\n lifetime: null,\n get ctx() {\n return latest.current.ctx;\n },\n onError: (error) => latest.current.onError?.(error),\n onChange: (connection) => latest.current.onChange?.(connection),\n attemptOnce: (abort) => {\n conn.negotiation = latest.current;\n return latest.current.attemptOnce(conn, abort);\n },\n notify: setConnection,\n reconnect: () => reconnectConn(conn),\n connection: {\n ...((props.isNew ?? false)\n ? { status: \"standby\", reason: \"deferred\", degraded: false }\n : { status: \"connecting\", degraded: false }),\n reconnect: () => conn.reconnect(),\n },\n };\n return conn;\n });\n const [link] = useState(\n (): RemoteLink => ({\n get connection() {\n return c.connection;\n },\n get parked() {\n return c.parked;\n },\n send: (frame) => latest.current.send(c, frame),\n storageFailed: (error) => storageFailed(c, error),\n }),\n );\n\n const negotiation = JSON.stringify([\n props.protocol,\n props.wireVersion,\n props.applicationProtocols,\n ]);\n useEffect(() => {\n c.lease = null;\n c.attempt = 0;\n c.authDenials = 0;\n c.authStale = false;\n c.liveAt = null;\n c.retryAt = 0;\n c.episode = null;\n setStatus(\n c,\n c.parked\n ? { status: \"standby\", reason: \"deferred\", degraded: false }\n : { status: \"connecting\", degraded: false },\n );\n const lifetime = new AbortController();\n c.lifetime = lifetime;\n c.gate = newGate();\n void run(c, lifetime, c.gate);\n return () => {\n c.abort?.abort();\n lifetime.abort();\n if (c.lifetime === lifetime) c.lifetime = null;\n openGate(c.gate);\n };\n }, [c, props.url, negotiation]);\n\n return link;\n};\n\nexport const classify = (timeout: AbortSignal) =>\n new Error(timeout.aborted ? \"timeout\" : \"network\");\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"connection.js","names":["negotiationHeaders","validateSelection","parseNegotiation","StatewireProtocol","useEffect","useRef","useState","flushTapSync","reviveOps","reviveValue","backoff","retryHint","timing","isStorageError","ConnectionState","RemoteLink","StatewireFrame","StatewireRemoteProps","StatewireSubmitResult","StatewireClient","StatewireHost","Episode","cause","message","code","TERMINAL","const","StatewireCmd","protocol","seq","type","payload","meta","dur","StatewireSyn","version","protocols","name","record","id","idle","retry","StatewireEnvelope","ops","cmd","next","syn","fin","Fin","Gate","latched","wake","newGate","undefined","takeGate","g","was","waitGate","timeoutMs","Promise","resolve","timer","setTimeout","clearTimeout","openGate","AttemptOutcome","Conn","negotiation","Options","connection","Connection","parked","lease","attempt","authDenials","authStale","liveAt","retryAt","error","ConnectionError","episode","awaitingHello","held","gate","abort","AbortController","lifetime","ctx","onError","onChange","attemptOnce","notify","reconnect","sameState","a","b","status","nextRetryAt","lastError","reason","setStatus","c","storageFailed","Error","degraded","protocolError","isObject","value","Record","Array","isArray","isNonnegativeSafeInteger","Number","isSafeInteger","isPositiveSafeInteger","validateOptionalString","field","validateSynProtocols","hello","entry","validateSynScalars","validateRefusalSyn","validateCmd","validateFin","validateEnvelope","releaseHeld","length","onCmds","cmdsOf","env","snapshotOf","helloSynOf","isWakeHello","handleHello","onHello","onIdle","Date","now","warnedUnknownSynFact","warnUnknownSynFact","console","warn","deliverSyn","onRefusal","Object","keys","deliverEnvelope","onOps","cmds","push","settleFin","finish","denial","terminal","report","assign","onFinish","handleEnvelope","dialing","scheduleRetry","failure","immediate","backoffResetMs","delay","Math","max","reconnectConn","run","alive","outcome","pending","beforeAttach","signal","aborted","SyntaxError","test","onDetach","unsupportedVersion","resolveHeaders","headers","HeadersOption","staleAuth","Headers","attachFrame","resolved","entries","has","set","persistence","lanes","takeAttachLanes","body","JSON","stringify","fromEntries","useLink","props","url","isNew","send","frame","latest","current","setConnection","conn","link","wireVersion","applicationProtocols","classify","timeout","AbortSignal"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import {\n negotiationHeaders,\n validateSelection,\n parseNegotiation,\n} from \"../wire/protocol\";\nimport type { StatewireProtocol } from \"../wire/protocol\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveValue } from \"../wire/meta\";\nimport { backoff, retryHint, timing } from \"./timing\";\nimport { isStorageError } from \"./storageError\";\nimport type {\n ConnectionState,\n RemoteLink,\n StatewireFrame,\n StatewireRemoteProps,\n StatewireSubmitResult,\n} from \"../transports/sse\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\n\nexport type Episode = {\n cause: \"dropped\" | \"reconnect\" | \"error\" | \"unauthorized\";\n message?: string;\n code?: string;\n};\n\n/** The terminal cmd verdict types; \"applied\" is the sole non-terminal type. */\nexport const TERMINAL = [\n \"result\",\n \"rejected\",\n \"failed\",\n \"crashed\",\n \"expired\",\n] as const;\n\nexport type StatewireCmd = {\n protocol: string;\n seq: number;\n type?: \"applied\" | (typeof TERMINAL)[number];\n code?: string;\n message?: string;\n payload?: unknown;\n meta?: unknown;\n /** Cumulative: resending through this seq will never be needed. */\n dur?: boolean;\n};\n\nexport type StatewireSyn = {\n version?: string;\n protocols?: {\n name: string;\n version?: string;\n record?: \"ephemeral\";\n seq?: number;\n }[];\n id?: string;\n idle?: boolean;\n retry?: number;\n};\n\nexport type StatewireEnvelope = {\n ops?: unknown[];\n cmd?: StatewireCmd[];\n next?: true;\n idle?: boolean;\n syn?: StatewireSyn;\n fin?: StatewireHost.Fin;\n};\n\nexport type Gate = { latched: boolean; wake: (() => void) | undefined };\n\nconst newGate = (): Gate => ({ latched: false, wake: undefined });\n\nconst takeGate = (g: Gate) => {\n const was = g.latched;\n g.latched = false;\n return was;\n};\n\nconst waitGate = (g: Gate, timeoutMs?: number) => {\n if (g.latched) {\n g.latched = false;\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n g.wake = undefined;\n resolve();\n }, timeoutMs);\n g.wake = () => {\n clearTimeout(timer);\n g.wake = undefined;\n resolve();\n };\n });\n};\n\nconst openGate = (g: Gate) => {\n if (g.wake) g.wake();\n else g.latched = true;\n};\n\nexport type AttemptOutcome = \"stop\" | \"reattach\" | \"ended\" | \"idle\";\n\nexport type Conn = {\n negotiation?: StatewireProtocol.Options;\n connection: StatewireClient.Connection;\n parked: boolean;\n lease: string | null;\n attempt: number;\n authDenials: number;\n authStale: boolean;\n liveAt: number | null;\n retryAt: number;\n error: StatewireClient.ConnectionError | undefined;\n episode: Episode | null;\n awaitingHello: boolean;\n held: StatewireCmd[];\n gate: Gate;\n abort: AbortController | null;\n lifetime: AbortController | null;\n ctx: StatewireRemoteProps;\n onError: (error: StatewireClient.ConnectionError) => void;\n onChange: (connection: StatewireClient.Connection) => void;\n attemptOnce: (abort: AbortController) => Promise<AttemptOutcome>;\n notify: (connection: StatewireClient.Connection) => void;\n reconnect: () => void;\n};\n\nconst sameState = (a: ConnectionState, b: ConnectionState): boolean => {\n if (a.status !== b.status) return false;\n if (a.status === \"retrying\" && b.status === \"retrying\") {\n return (\n a.attempt === b.attempt &&\n a.cause === b.cause &&\n a.code === b.code &&\n a.nextRetryAt === b.nextRetryAt &&\n a.lastError === b.lastError &&\n a.message === b.message\n );\n }\n if (a.status === \"standby\" && b.status === \"standby\") {\n return a.reason === b.reason;\n }\n if (a.status === \"stopped\" && b.status === \"stopped\") {\n return (\n a.reason === b.reason &&\n a.message === b.message &&\n a.payload === b.payload\n );\n }\n return true;\n};\n\nconst setStatus = (c: Conn, next: ConnectionState) => {\n if (sameState(next, c.connection) && c.connection.error === c.error) return;\n c.connection = {\n ...next,\n ...(c.error === undefined ? {} : { error: c.error }),\n reconnect: c.reconnect,\n };\n c.notify(c.connection);\n c.onChange(c.connection);\n};\n\nconst storageFailed = (c: Conn, error: Error) => {\n c.error = error;\n c.onError(error);\n flushTapSync(() =>\n setStatus(c, {\n status: \"stopped\",\n reason: \"storage-error\",\n degraded: true,\n message: error.message,\n }),\n );\n c.abort?.abort();\n};\n\nconst protocolError = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isNonnegativeSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) >= 0;\n\nconst isPositiveSafeInteger = (value: unknown): value is number =>\n Number.isSafeInteger(value) && (value as number) > 0;\n\nconst validateOptionalString = (value: unknown, field: string): void => {\n if (value !== undefined && typeof value !== \"string\") {\n protocolError(`${field} must be a string`);\n }\n};\n\nconst validateSynProtocols = (value: unknown, hello: boolean): void => {\n if (value === undefined) return;\n if (!Array.isArray(value))\n return protocolError(\"syn.protocols must be an array\");\n for (const entry of value) {\n if (!isObject(entry))\n return protocolError(\"syn.protocols entry must be an object\");\n if (typeof entry[\"name\"] !== \"string\")\n protocolError(\"syn.protocols[].name must be a string\");\n if (\n !hello &&\n (entry[\"version\"] !== undefined || entry[\"record\"] !== undefined)\n )\n protocolError(\"invalid mid-stream syn\");\n if (\n hello\n ? !isNonnegativeSafeInteger(entry[\"seq\"])\n : entry[\"seq\"] !== undefined && !isNonnegativeSafeInteger(entry[\"seq\"])\n )\n protocolError(\"syn.protocols[].seq must be a nonnegative safe integer\");\n if (hello && entry[\"record\"] === \"ephemeral\" && entry[\"seq\"] !== 0)\n protocolError(\"ephemeral lane hello seq must be 0\");\n }\n};\n\nconst validateSynScalars = (syn: Record<string, unknown>, hello: boolean) => {\n validateSynProtocols(syn[\"protocols\"], hello);\n if (syn[\"retry\"] !== undefined && !isNonnegativeSafeInteger(syn[\"retry\"])) {\n protocolError(\"syn.retry must be a nonnegative safe integer\");\n }\n validateOptionalString(syn[\"id\"], \"syn.id\");\n if (syn[\"idle\"] !== undefined && typeof syn[\"idle\"] !== \"boolean\") {\n protocolError(\"syn.idle must be a boolean\");\n }\n};\n\nexport const validateRefusalSyn = (value: unknown): StatewireSyn => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value, false);\n if (\n value[\"id\"] !== undefined ||\n value[\"idle\"] !== undefined ||\n value[\"version\"] !== undefined\n ) {\n protocolError(\"invalid refusal syn\");\n }\n if (value[\"protocols\"] === undefined && value[\"retry\"] === undefined) {\n protocolError(\"refusal syn has no watermarks or retry\");\n }\n return value as StatewireSyn;\n};\n\nconst validateCmd = (value: unknown): value is StatewireCmd => {\n if (!isObject(value)) return protocolError(\"cmd entry must be an object\");\n if (typeof value[\"protocol\"] !== \"string\") {\n protocolError(\"cmd.protocol must be a string\");\n }\n if (!isPositiveSafeInteger(value[\"seq\"])) {\n protocolError(\"cmd.seq must be a positive safe integer\");\n }\n validateOptionalString(value[\"type\"], \"cmd.type\");\n validateOptionalString(value[\"code\"], \"cmd.code\");\n validateOptionalString(value[\"message\"], \"cmd.message\");\n if (value[\"dur\"] !== undefined && value[\"dur\"] !== true) {\n protocolError(\"cmd.dur must be true\");\n }\n return true;\n};\n\nconst validateFin = (value: unknown): value is StatewireHost.Fin => {\n if (!isObject(value)) return protocolError(\"fin must be an object\");\n if (typeof value[\"reason\"] !== \"string\") {\n protocolError(\"fin.reason must be a string\");\n }\n validateOptionalString(value[\"message\"], \"fin.message\");\n validateOptionalString(value[\"code\"], \"fin.code\");\n if (\n value[\"status\"] !== undefined &&\n !isNonnegativeSafeInteger(value[\"status\"])\n )\n protocolError(\"fin.status must be a nonnegative safe integer\");\n if (value[\"retry\"] !== undefined && !isNonnegativeSafeInteger(value[\"retry\"]))\n protocolError(\"fin.retry must be a nonnegative safe integer\");\n return true;\n};\n\nconst validateEnvelope = (value: unknown): StatewireEnvelope => {\n if (!isObject(value)) return protocolError(\"packet must be an object\");\n if (value[\"ops\"] !== undefined && !Array.isArray(value[\"ops\"])) {\n protocolError(\"ops must be an array\");\n }\n if (value[\"cmd\"] !== undefined) {\n const cmd = value[\"cmd\"];\n if (!Array.isArray(cmd)) return protocolError(\"cmd must be an array\");\n for (const entry of cmd) validateCmd(entry);\n }\n if (value[\"idle\"] !== undefined && typeof value[\"idle\"] !== \"boolean\") {\n protocolError(\"idle must be a boolean\");\n }\n if (value[\"next\"] !== undefined) {\n if (value[\"next\"] !== true) protocolError(\"next must be true\");\n if (\n value[\"cmd\"] === undefined ||\n value[\"ops\"] !== undefined ||\n value[\"fin\"] !== undefined\n ) {\n protocolError(\"next must ride a cmd-only packet\");\n }\n }\n if (value[\"fin\"] !== undefined) validateFin(value[\"fin\"]);\n return value as StatewireEnvelope;\n};\n\n// A hold's release delivers, never settles: fin and bare close both drain it.\nconst releaseHeld = (c: Conn) => {\n if (c.held.length === 0) return;\n const held = c.held;\n c.held = [];\n c.ctx.onCmds(held);\n};\n\nconst cmdsOf = (env: StatewireEnvelope): StatewireCmd[] => {\n if (env.cmd === undefined) return [];\n return env.cmd;\n};\n\nconst snapshotOf = (env: StatewireEnvelope): unknown[] => {\n const ops = env.ops;\n if (ops === undefined) return protocolError(\"hello missing snapshot\");\n return reviveOps(ops);\n};\n\nconst helloSynOf = (env: StatewireEnvelope): StatewireSyn => {\n if (!isObject(env.syn)) return protocolError(\"expected hello\");\n validateSynScalars(env.syn, true);\n if (env.syn[\"retry\"] !== undefined) {\n protocolError(\"hello syn cannot carry retry\");\n }\n return env.syn as StatewireSyn;\n};\n\n// A host that woke on a retained socket re-sends its hello; the snapshot\n// replaces the session the way a fresh attach would.\nconst isWakeHello = (env: StatewireEnvelope) =>\n isObject(env.syn) && env.syn[\"version\"] !== undefined;\n\nconst handleHello = (c: Conn, env: StatewireEnvelope) => {\n const syn = helloSynOf(env);\n if (c.negotiation !== undefined) validateSelection(syn, c.negotiation);\n const ops = snapshotOf(env);\n c.ctx.onHello({\n ops,\n syn,\n });\n if (env.cmd !== undefined) c.ctx.onCmds(env.cmd);\n c.ctx.onIdle(syn.idle ?? false);\n c.awaitingHello = false;\n c.error = undefined;\n c.liveAt = Date.now();\n c.authDenials = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\", degraded: false });\n};\n\nlet warnedUnknownSynFact = false;\n\nconst warnUnknownSynFact = () => {\n if (warnedUnknownSynFact) return;\n warnedUnknownSynFact = true;\n console.warn(\"statewire: ignoring unknown syn fact\");\n};\n\nconst deliverSyn = (c: Conn, value: unknown) => {\n if (!isObject(value)) return protocolError(\"syn must be an object\");\n validateSynScalars(value, false);\n if (value[\"version\"] !== undefined || value[\"idle\"] !== undefined) {\n protocolError(\"invalid mid-stream syn\");\n }\n if (value[\"protocols\"] !== undefined || value[\"retry\"] !== undefined) {\n c.ctx.onRefusal(validateRefusalSyn(value));\n return;\n }\n if (value[\"id\"] !== undefined) return;\n if (Object.keys(value).length === 0) {\n protocolError(\"invalid mid-stream syn\");\n }\n warnUnknownSynFact();\n};\n\nconst deliverEnvelope = (c: Conn, env: StatewireEnvelope) => {\n if (env.syn !== undefined) deliverSyn(c, env.syn);\n if (env.ops !== undefined) {\n const held = c.held;\n c.held = [];\n c.ctx.onOps({\n ops: reviveOps(env.ops),\n cmds: [...held, ...cmdsOf(env)],\n });\n } else if (env.cmd !== undefined) {\n const cmds = cmdsOf(env);\n if (env.next === true) c.held.push(...cmds);\n else c.ctx.onCmds(cmds);\n }\n if (typeof env.idle === \"boolean\") c.ctx.onIdle(env.idle);\n};\n\nexport const settleFin = (c: Conn, fin: StatewireHost.Fin): AttemptOutcome => {\n const finish =\n fin.meta === undefined\n ? fin\n : { ...fin, payload: reviveValue(fin.payload, fin.meta) };\n releaseHeld(c);\n c.retryAt = Date.now() + retryHint(finish.retry ?? 0);\n if (finish.reason === \"idle\") {\n c.ctx.onIdle(true);\n c.attempt = 0;\n c.episode = null;\n c.error = undefined;\n setStatus(c, { status: \"standby\", reason: \"idle\", degraded: false });\n return \"idle\";\n }\n const denial = finish.reason === \"unauthorized\";\n const terminal =\n finish.reason === \"gone\" ||\n finish.reason === \"forbidden\" ||\n finish.reason === \"protocol-error\" ||\n (denial && c.authDenials > 0);\n if (denial) {\n c.authDenials += 1;\n c.authStale = true;\n }\n const report =\n finish.reason !== \"reconnect\" &&\n finish.reason !== \"gone\" &&\n (!denial || terminal);\n c.error = report\n ? Object.assign(new Error(finish.message ?? finish.reason), { fin: finish })\n : undefined;\n if (c.error) c.onError(c.error);\n if (!terminal) {\n c.episode = {\n cause:\n finish.reason === \"reconnect\"\n ? \"reconnect\"\n : denial\n ? \"unauthorized\"\n : \"error\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.code !== undefined && { code: finish.code }),\n };\n if (denial) openGate(c.gate);\n return \"reattach\";\n }\n c.ctx.onFinish(finish);\n setStatus(c, {\n status: \"stopped\",\n degraded: true,\n reason: denial\n ? \"unauthorized\"\n : finish.reason === \"forbidden\"\n ? \"forbidden\"\n : finish.reason === \"protocol-error\"\n ? \"protocol-error\"\n : \"gone\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.payload !== undefined && { payload: finish.payload }),\n });\n return \"stop\";\n};\n\nexport const handleEnvelope = (\n c: Conn,\n value: unknown,\n): AttemptOutcome | null => {\n const env = validateEnvelope(value);\n if (c.awaitingHello || isWakeHello(env)) {\n if (env.fin !== undefined) return settleFin(c, env.fin);\n handleHello(c, env);\n return null;\n }\n deliverEnvelope(c, env);\n if (env.fin !== undefined) return settleFin(c, env.fin);\n if (c.connection.status !== \"connected\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"connected\", degraded: false });\n }\n return null;\n};\n\n// A dial that no wait preceded is part of the current connect: only a\n// scheduled delay surfaces `retrying`, and the dial after it keeps that status.\nconst dialing = (c: Conn) =>\n setStatus(\n c,\n c.connection.status === \"retrying\"\n ? { status: \"retrying\", attempt: c.attempt, degraded: true }\n : { status: \"connecting\", degraded: false },\n );\n\nconst scheduleRetry = (\n c: Conn,\n failure: string | undefined,\n immediate: boolean,\n) => {\n if (c.liveAt !== null && Date.now() - c.liveAt >= timing.backoffResetMs) {\n c.attempt = 0;\n }\n c.liveAt = null;\n c.attempt += 1;\n c.episode ??= { cause: \"dropped\" };\n const delay = Math.max(\n immediate ? 0 : backoff(c.attempt),\n c.retryAt - Date.now(),\n );\n if (delay === 0) return delay;\n setStatus(c, {\n status: \"retrying\",\n degraded: true,\n attempt: c.attempt,\n ...c.episode,\n nextRetryAt: Date.now() + delay,\n ...(failure !== undefined && { lastError: failure }),\n });\n return delay;\n};\n\nconst reconnectConn = (c: Conn) => {\n if (!c.lifetime) return;\n if (c.connection.status === \"standby\" || c.connection.status === \"stopped\") {\n // A reconnect out of a park starts a fresh episode: first dial, attempt 0.\n c.attempt = 0;\n c.authDenials = 0;\n c.episode = null;\n flushTapSync(() => dialing(c));\n }\n openGate(c.gate);\n c.abort?.abort();\n};\n\nconst run = async (c: Conn, lifetime: AbortController, gate: Gate) => {\n const alive = () => c.lifetime === lifetime;\n if (c.parked) {\n await waitGate(gate);\n if (!alive()) return;\n c.parked = false;\n }\n while (alive()) {\n if (c.retryAt > Date.now()) {\n await waitGate(gate, c.retryAt - Date.now());\n continue;\n }\n // The dial is in flight: attempt alone, no backoff fields.\n flushTapSync(() => dialing(c));\n const abort = new AbortController();\n c.abort = abort;\n c.awaitingHello = true;\n c.held = [];\n let outcome: AttemptOutcome | undefined;\n let failure: string | undefined;\n try {\n const pending = c.ctx.beforeAttach?.();\n if (pending) await pending;\n if (!alive()) return;\n outcome = await c.attemptOnce(abort);\n } catch (error) {\n if (!abort.signal.aborted) {\n if (isStorageError(error)) {\n storageFailed(c, error);\n outcome = \"stop\";\n } else if (\n error instanceof SyntaxError ||\n (error instanceof Error &&\n /^(statewire: protocol error:|Statewire cannot apply)/.test(\n error.message,\n ))\n ) {\n outcome = flushTapSync(() =>\n settleFin(c, { reason: \"protocol-error\", message: error.message }),\n );\n } else if (c.authStale) {\n outcome = flushTapSync(() =>\n settleFin(c, {\n reason: \"unauthorized\",\n message:\n error instanceof Error\n ? error.message\n : \"credential refresh failed\",\n }),\n );\n }\n failure =\n error instanceof Error && error.message ? error.message : \"network\";\n }\n }\n abort.abort();\n if (!alive()) return;\n flushTapSync(() => {\n releaseHeld(c);\n c.ctx.onDetach();\n });\n if (!alive()) return;\n if (c.connection.status === \"stopped\") outcome = \"stop\";\n if (outcome === \"stop\" || outcome === \"idle\") {\n await waitGate(gate);\n continue;\n }\n const immediate = takeGate(gate);\n const delay = flushTapSync(() => scheduleRetry(c, failure, immediate));\n if (delay === 0) continue;\n await waitGate(gate, delay);\n }\n};\n\nexport const unsupportedVersion = (c: Conn, version: string): AttemptOutcome =>\n flushTapSync(() =>\n handleEnvelope(c, {\n fin: {\n reason: \"protocol-error\",\n message: `unsupported protocol version: ${version || '\"\"'}`,\n },\n }),\n ) ?? \"stop\";\n\nexport const resolveHeaders = async (\n headers: StatewireClient.HeadersOption | undefined,\n staleAuth: boolean,\n): Promise<Headers> =>\n new Headers(\n typeof headers === \"function\" ? await headers({ staleAuth }) : headers,\n );\n\n// The stale flag clears only once the resolver returns: a throwing refresh keeps it for the next attempt.\nexport const attachFrame = async (\n c: Conn,\n headers: StatewireClient.HeadersOption | undefined,\n) => {\n const pending = c.ctx.beforeAttach?.();\n if (pending) await pending;\n const resolved = await resolveHeaders(headers, c.authStale);\n for (const [name, value] of Object.entries(\n negotiationHeaders(c.negotiation ?? {}),\n )) {\n if (!resolved.has(name)) resolved.set(name, value);\n }\n c.negotiation = parseNegotiation(resolved);\n c.authStale = false;\n const persistence = c.ctx.beforeAttach?.();\n if (persistence) await persistence;\n const lanes = flushTapSync(() => c.ctx.takeAttachLanes());\n return {\n headers: resolved,\n body: JSON.stringify({\n headers: Object.fromEntries(resolved),\n ...(lanes ?? {}),\n }),\n };\n};\n\nexport const useLink = (\n props: StatewireProtocol.Options & {\n url: string;\n isNew?: boolean | undefined;\n onChange?: ((connection: StatewireClient.Connection) => void) | undefined;\n onError?: ((error: StatewireClient.ConnectionError) => void) | undefined;\n ctx: StatewireRemoteProps;\n attemptOnce: (c: Conn, abort: AbortController) => Promise<AttemptOutcome>;\n send: (c: Conn, frame: StatewireFrame) => Promise<StatewireSubmitResult>;\n },\n): RemoteLink => {\n const latest = useRef(props);\n latest.current = props;\n const [, setConnection] = useState<StatewireClient.Connection | null>(null);\n const [c] = useState((): Conn => {\n const conn: Conn = {\n parked: props.isNew ?? false,\n lease: null,\n attempt: 0,\n authDenials: 0,\n authStale: false,\n liveAt: null,\n retryAt: 0,\n error: undefined,\n episode: null,\n awaitingHello: true,\n held: [],\n abort: null,\n gate: newGate(),\n lifetime: null,\n get ctx() {\n return latest.current.ctx;\n },\n onError: (error) => latest.current.onError?.(error),\n onChange: (connection) => latest.current.onChange?.(connection),\n attemptOnce: (abort) => {\n conn.negotiation = latest.current;\n return latest.current.attemptOnce(conn, abort);\n },\n notify: setConnection,\n reconnect: () => reconnectConn(conn),\n connection: {\n ...((props.isNew ?? false)\n ? { status: \"standby\", reason: \"deferred\", degraded: false }\n : { status: \"connecting\", degraded: false }),\n reconnect: () => conn.reconnect(),\n },\n };\n return conn;\n });\n const [link] = useState(\n (): RemoteLink => ({\n get connection() {\n return c.connection;\n },\n get parked() {\n return c.parked;\n },\n send: (frame) => latest.current.send(c, frame),\n storageFailed: (error) => storageFailed(c, error),\n }),\n );\n\n const negotiation = JSON.stringify([\n props.protocol,\n props.wireVersion,\n props.applicationProtocols,\n ]);\n useEffect(() => {\n c.lease = null;\n c.attempt = 0;\n c.authDenials = 0;\n c.authStale = false;\n c.liveAt = null;\n c.retryAt = 0;\n c.episode = null;\n setStatus(\n c,\n c.parked\n ? { status: \"standby\", reason: \"deferred\", degraded: false }\n : { status: \"connecting\", degraded: false },\n );\n const lifetime = new AbortController();\n c.lifetime = lifetime;\n c.gate = newGate();\n void run(c, lifetime, c.gate);\n return () => {\n c.abort?.abort();\n lifetime.abort();\n if (c.lifetime === lifetime) c.lifetime = null;\n openGate(c.gate);\n };\n }, [c, props.url, negotiation]);\n\n return link;\n};\n\nexport const classify = (timeout: AbortSignal) =>\n new Error(timeout.aborted ? \"timeout\" : \"network\");\n"],"mappings":"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"}
|
package/dist/client/core.js
CHANGED
|
@@ -138,7 +138,7 @@ const flush = (c, scheduled = false) => {
|
|
|
138
138
|
const busy = c.getBusy();
|
|
139
139
|
const busyChanged = busy !== c.notifiedBusy;
|
|
140
140
|
c.notifiedBusy = busy;
|
|
141
|
-
const failed = c.value
|
|
141
|
+
const failed = c.value?.failures?.list() ?? NO_FAILED;
|
|
142
142
|
let failedChanged = false;
|
|
143
143
|
if (failed !== c.notifiedFailed) {
|
|
144
144
|
if (scheduled) {
|
package/dist/client/core.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.js","names":["useEffect","useState","createChanges","getCommandsHost","getStateHost","CommandsInvocation","CommandsListener","recordMutations","createMacrotaskPoster","createMethodProxy","StatewirePath","StatewireSendError","Statewire","StatewireClient","CONNECTED_CONNECTION","Connection","status","degraded","reconnect","NO_FAILED","FailedCommand","failureOf","error","SendFailure","failure","fate","cause","message","Error","String","Overlay","inv","dropped","Core","getOptions","Options","value","source","StateSource","overlays","updates","CommandUpdate","pendingChanged","canonical","published","overlayPaths","notifiedPublished","notifiedOverlayPaths","notifiedConnection","notifiedError","ConnectionError","notifiedBusy","notifiedFailed","stale","everAttached","overlaysDirty","materializeKey","flushing","scheduled","listeners","Set","post","commandsListener","getState","getBusy","getFailed","rematerialize","commands","CommandsProxy","subscribe","listener","schedule","c","markStale","drainCanonical","push","takeChanged","snapshot","undefined","next","initialState","state","dropCovered","failureCovered","failures","entry","list","discard","recompute","optimistic","materialize","rekeyed","Object","is","prevCanonical","paths","overlay","protocol","ctx","OptimisticContext","ts","seq","clientId","recorded","draft","method","params","Command","changedPaths","console","getConnection","connection","flush","options","stateChanged","prev","changed","onStateChange","changes","length","batch","update","onCommandChange","connectionChanged","onConnectionChange","onError","busy","busyChanged","failed","failedChanged","note","extra","result","attach","nextSource","setOnChange","setListener","detach","useStatewireCore","core","onStart","onPosted","onApplied","onCovered","some","o","filter","onSettle","outcome","type","payload","isBusy","Promise","reject","send","Record","args","promise","add","delete"],"sources":["../../src/client/core.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { createChanges } from \"./changes\";\nimport { getCommandsHost, getStateHost } from \"../host/host\";\nimport type { CommandsInvocation, CommandsListener } from \"../host/host\";\nimport { recordMutations } from \"../util/recordMutations\";\nimport { createMacrotaskPoster } from \"../util/macrotask\";\nimport { createMethodProxy } from \"../util/methodProxy\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport { StatewireSendError } from \"../types\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\n\nexport const CONNECTED_CONNECTION: StatewireClient.Connection = {\n status: \"connected\",\n degraded: false,\n reconnect: () => {},\n};\n\nconst NO_FAILED: readonly StatewireClient.FailedCommand[] = [];\n\nconst failureOf = (error: unknown): StatewireClient.SendFailure =>\n error instanceof StatewireSendError\n ? error.failure\n : {\n fate: \"rejected\",\n cause: \"server\",\n message: error instanceof Error ? error.message : String(error),\n };\n\ntype Overlay = { inv: CommandsInvocation; dropped: boolean };\n\ntype Core = {\n getOptions: () => StatewireClient.Options<any, any>;\n value: Statewire<unknown> | null;\n source: Statewire.StateSource | null;\n overlays: Overlay[];\n updates: Statewire.CommandUpdate[];\n pendingChanged: StatewirePath[];\n canonical: unknown;\n published: unknown;\n overlayPaths: readonly StatewirePath[];\n notifiedPublished: unknown;\n notifiedOverlayPaths: readonly StatewirePath[];\n notifiedConnection: StatewireClient.Connection | null;\n notifiedError: StatewireClient.ConnectionError | undefined;\n notifiedBusy: boolean;\n notifiedFailed: readonly StatewireClient.FailedCommand[];\n stale: boolean;\n everAttached: boolean;\n overlaysDirty: boolean;\n materializeKey: unknown;\n flushing: boolean;\n scheduled: boolean;\n listeners: Set<() => void>;\n post: () => void;\n commandsListener: CommandsListener;\n getState: () => unknown;\n getBusy: () => boolean;\n getFailed: () => readonly StatewireClient.FailedCommand[];\n rematerialize: () => void;\n commands: Statewire.CommandsProxy<any>;\n subscribe: (listener: () => void) => () => void;\n};\n\nconst schedule = (c: Core) => {\n if (c.scheduled) return;\n c.scheduled = true;\n c.post();\n};\n\nconst markStale = (c: Core) => {\n c.stale = true;\n schedule(c);\n};\n\n// initialState stands in for the canonical state only before the first\n// attach snapshot; replay boundaries after that read as loading, not preload.\nconst drainCanonical = (c: Core) => {\n if (c.source) {\n c.pendingChanged.push(...c.source.takeChanged());\n const snapshot = c.source.snapshot();\n if (snapshot !== undefined) {\n c.everAttached = true;\n c.canonical = snapshot;\n return;\n }\n const next = c.everAttached ? undefined : c.getOptions().initialState;\n if (next !== c.canonical) c.pendingChanged.push([]);\n c.canonical = next;\n } else if (c.value) {\n if (c.value.state !== undefined) c.everAttached = true;\n const next = c.everAttached ? c.value.state : c.getOptions().initialState;\n if (next !== c.canonical) {\n c.pendingChanged.push([]);\n c.canonical = next;\n }\n }\n};\n\nconst dropCovered = (c: Core) => {\n const { failureCovered } = c.getOptions();\n const failures = c.value?.failures;\n if (!failureCovered || !failures || c.canonical === undefined) return;\n for (const entry of failures.list()) {\n if (failureCovered(c.canonical as never, entry)) failures.discard(entry);\n }\n};\n\nconst recompute = (c: Core) => {\n if (!c.value) return;\n const { optimistic, materialize, materializeKey } = c.getOptions();\n const rekeyed = !Object.is(materializeKey, c.materializeKey);\n if (!c.stale && !rekeyed) return;\n c.stale = false;\n const prevCanonical = c.canonical;\n drainCanonical(c);\n if (c.canonical !== prevCanonical) dropCovered(c);\n if (c.canonical === prevCanonical && !c.overlaysDirty && !rekeyed) return;\n c.overlaysDirty = false;\n c.materializeKey = materializeKey;\n let next = c.canonical;\n let paths: readonly StatewirePath[] = [];\n if (optimistic && c.canonical !== undefined) {\n for (const overlay of c.overlays) {\n if (overlay.dropped) continue;\n const { inv } = overlay;\n if (\n inv.protocol !== undefined &&\n inv.protocol !== (c.getOptions().protocol ?? \"default\")\n )\n continue;\n const ctx: StatewireClient.OptimisticContext = {\n ts: inv.ts,\n seq: inv.seq,\n ...(inv.clientId !== undefined && { clientId: inv.clientId }),\n };\n try {\n const recorded = recordMutations(next, (draft) =>\n optimistic(\n draft as never,\n { method: inv.method, params: inv.params } as Statewire.Command,\n ctx,\n ),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n overlay.dropped = true;\n console.error(\n `statewire: optimistic reducer threw for \"${inv.method}\"; dropping its optimistic update`,\n error,\n );\n }\n }\n }\n if (materialize && next !== undefined) {\n try {\n const recorded = recordMutations(next, (draft) =>\n materialize(draft as never),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n console.error(\n \"statewire: materialize threw; publishing without its update\",\n error,\n );\n }\n }\n c.published = next;\n c.overlayPaths = paths;\n};\n\nconst getConnection = (c: Core): StatewireClient.Connection =>\n c.value?.connection ?? CONNECTED_CONNECTION;\n\nconst flush = (c: Core, scheduled = false) => {\n if (!c.value) return;\n if (c.flushing) {\n schedule(c);\n return;\n }\n c.flushing = true;\n try {\n recompute(c);\n const options = c.getOptions();\n const stateChanged = c.published !== c.notifiedPublished;\n if (stateChanged) {\n const prev = c.notifiedPublished;\n const changed = [\n ...c.pendingChanged,\n ...c.notifiedOverlayPaths,\n ...c.overlayPaths,\n ];\n c.pendingChanged = [];\n c.notifiedPublished = c.published;\n c.notifiedOverlayPaths = c.overlayPaths;\n options.onStateChange?.(c.published as never, {\n changes: createChanges(prev, c.published, changed),\n });\n }\n if (c.updates.length > 0 && c.published !== undefined) {\n const batch = c.updates;\n c.updates = [];\n for (const update of batch) {\n options.onCommandChange?.(update, { state: c.published as never });\n }\n }\n const connection = getConnection(c);\n const connectionChanged = connection !== c.notifiedConnection;\n c.notifiedConnection = connection;\n if (connectionChanged) options.onConnectionChange?.(connection);\n if (connection.error !== c.notifiedError) {\n c.notifiedError = connection.error;\n if (connection.error) options.onError?.(connection.error);\n }\n const busy = c.getBusy();\n const busyChanged = busy !== c.notifiedBusy;\n c.notifiedBusy = busy;\n // The failed snapshot advances only on the scheduled pass: settles land\n // mid-unmount, where a changed snapshot re-renders the unmounting tree.\n const failed = c.value.failures?.list() ?? NO_FAILED;\n let failedChanged = false;\n if (failed !== c.notifiedFailed) {\n if (scheduled) {\n c.notifiedFailed = failed;\n failedChanged = true;\n } else {\n schedule(c);\n }\n }\n if (stateChanged || connectionChanged || busyChanged || failedChanged) {\n for (const listener of [...c.listeners]) listener();\n }\n } finally {\n c.flushing = false;\n }\n};\n\nconst note = (\n c: Core,\n inv: CommandsInvocation,\n status: Statewire.CommandUpdate[\"status\"],\n extra?: { result?: unknown; failure?: StatewireClient.SendFailure },\n) => {\n if (!c.getOptions().onCommandChange) return;\n c.updates.push({\n ...(inv.protocol !== undefined && { protocol: inv.protocol }),\n method: inv.method,\n params: inv.params as never[],\n seq: inv.seq,\n status,\n ...extra,\n });\n schedule(c);\n};\n\nconst attach = (c: Core, next: Statewire<unknown>) => {\n if (next === c.value) return;\n const prev = c.value;\n c.value = next;\n const nextSource =\n next.source ??\n (typeof next.state === \"object\" && next.state !== null\n ? getStateHost(next.state)\n : undefined) ??\n null;\n if (nextSource !== c.source) {\n c.source?.setOnChange(null);\n c.source = nextSource;\n c.source?.setOnChange(() => markStale(c));\n // A new source is a new attach lifecycle: initialState preloads again.\n c.everAttached = false;\n markStale(c);\n }\n if (next.commands !== prev?.commands) {\n if (prev) getCommandsHost(prev.commands)?.setListener(null);\n getCommandsHost(next.commands)?.setListener(c.commandsListener);\n if (c.overlays.length > 0) {\n c.overlays = [];\n c.overlaysDirty = true;\n }\n markStale(c);\n }\n if (!c.source) markStale(c);\n schedule(c);\n};\n\nconst detach = (c: Core) => {\n c.source?.setOnChange(null);\n c.source = null;\n if (c.value) {\n getCommandsHost(c.value.commands)?.setListener(null);\n c.value = null;\n }\n};\n\nexport const useStatewireCore = (\n getOptions: () => StatewireClient.Options<any, any>,\n value: Statewire<unknown>,\n) => {\n const [core] = useState((): Core => {\n const c: Core = {\n getOptions,\n value: null,\n source: null,\n overlays: [],\n updates: [],\n pendingChanged: [],\n canonical: undefined,\n published: undefined,\n overlayPaths: [],\n notifiedPublished: undefined,\n notifiedOverlayPaths: [],\n notifiedConnection: null,\n notifiedError: undefined,\n notifiedBusy: true,\n notifiedFailed: NO_FAILED,\n stale: false,\n everAttached: false,\n overlaysDirty: false,\n materializeKey: undefined,\n flushing: false,\n scheduled: false,\n listeners: new Set(),\n post: createMacrotaskPoster(() => {\n c.scheduled = false;\n flush(c, true);\n }),\n commandsListener: {\n onStart: (inv) => {\n c.overlays.push({ inv, dropped: false });\n c.overlaysDirty = true;\n markStale(c);\n note(c, inv, \"queued\");\n },\n onPosted: (inv) => note(c, inv, \"posted\"),\n onApplied: (inv) => note(c, inv, \"applied\"),\n onCovered: (inv) => {\n if (!c.overlays.some((o) => o.inv === inv)) return;\n c.overlays = c.overlays.filter((o) => o.inv !== inv);\n c.overlaysDirty = true;\n markStale(c);\n },\n onSettle: (inv, outcome) => {\n note(\n c,\n inv,\n \"settled\",\n outcome.type === \"accepted\"\n ? { result: outcome.payload }\n : { failure: failureOf(outcome.error) },\n );\n flush(c);\n },\n },\n getState: () => {\n recompute(c);\n return c.published;\n },\n getBusy: () => c.value?.isBusy ?? true,\n getFailed: () => c.notifiedFailed,\n rematerialize: () => flush(c),\n commands: createMethodProxy<Statewire.CommandsProxy<any>>(\n (method, params) => {\n if (!c.value) {\n return Promise.reject(\n new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }),\n );\n }\n const send = (\n c.value.commands as Record<\n string,\n (...args: unknown[]) => Promise<unknown>\n >\n )[method]!;\n const promise = send(...params);\n flush(c);\n return promise;\n },\n ),\n subscribe: (listener) => {\n c.listeners.add(listener);\n return () => {\n c.listeners.delete(listener);\n };\n },\n };\n return c;\n });\n core.getOptions = getOptions;\n // Attach during render so the first snapshot reads the transport's state;\n // re-attaching the same transport is a no-op and the single-slot host\n // listeners make a swap land on the last writer.\n attach(core, value);\n useEffect(() => {\n attach(core, value);\n });\n useEffect(() => () => detach(core), [core]);\n return core;\n};\n"],"mappings":";;;;;;;;AAYA,MAAac,uBAAmD;CAC9DE,QAAQ;CACRC,UAAU;CACVC,iBAAiB,CAAC;AACpB;AAEA,MAAMC,YAAsD,CAAA;AAE5D,MAAME,aAAaC,UACjBA,iBAAiBX,qBACbW,MAAME,UACN;CACEC,MAAM;CACNC,OAAO;CACPC,SAASL,iBAAiBM,QAAQN,MAAMK,UAAUE,OAAOP,KAAK;AAChE;AAqCN,MAAMiD,YAAYC,MAAY;CAC5B,IAAIA,EAAEd,WAAW;CACjBc,EAAEd,YAAY;CACdc,EAAEX,KAAK;AACT;AAEA,MAAMY,aAAaD,MAAY;CAC7BA,EAAEnB,QAAQ;CACVkB,SAASC,CAAC;AACZ;AAIA,MAAME,kBAAkBF,MAAY;CAClC,IAAIA,EAAEnC,QAAQ;EACZmC,EAAE9B,eAAeiC,KAAK,GAAGH,EAAEnC,OAAOuC,YAAY,CAAC;EAC/C,MAAMC,WAAWL,EAAEnC,OAAOwC,SAAS;EACnC,IAAIA,aAAaC,KAAAA,GAAW;GAC1BN,EAAElB,eAAe;GACjBkB,EAAE7B,YAAYkC;GACd;EACF;EACA,MAAME,OAAOP,EAAElB,eAAewB,KAAAA,IAAYN,EAAEtC,WAAW,CAAC,CAAC8C;EACzD,IAAID,SAASP,EAAE7B,WAAW6B,EAAE9B,eAAeiC,KAAK,CAAA,CAAE;EAClDH,EAAE7B,YAAYoC;CAChB,OAAO,IAAIP,EAAEpC,OAAO;EAClB,IAAIoC,EAAEpC,MAAM6C,UAAUH,KAAAA,GAAWN,EAAElB,eAAe;EAClD,MAAMyB,OAAOP,EAAElB,eAAekB,EAAEpC,MAAM6C,QAAQT,EAAEtC,WAAW,CAAC,CAAC8C;EAC7D,IAAID,SAASP,EAAE7B,WAAW;GACxB6B,EAAE9B,eAAeiC,KAAK,CAAA,CAAE;GACxBH,EAAE7B,YAAYoC;EAChB;CACF;AACF;AAEA,MAAMG,eAAeV,MAAY;CAC/B,MAAM,EAAEW,mBAAmBX,EAAEtC,WAAW;CACxC,MAAMkD,WAAWZ,EAAEpC,OAAOgD;CAC1B,IAAI,CAACD,kBAAkB,CAACC,YAAYZ,EAAE7B,cAAcmC,KAAAA,GAAW;CAC/D,KAAK,MAAMO,SAASD,SAASE,KAAK,GAChC,IAAIH,eAAeX,EAAE7B,WAAoB0C,KAAK,GAAGD,SAASG,QAAQF,KAAK;AAE3E;AAEA,MAAMG,aAAahB,MAAY;CAC7B,IAAI,CAACA,EAAEpC,OAAO;CACd,MAAM,EAAEqD,YAAYC,aAAalC,mBAAmBgB,EAAEtC,WAAW;CACjE,MAAMyD,UAAU,CAACC,OAAOC,GAAGrC,gBAAgBgB,EAAEhB,cAAc;CAC3D,IAAI,CAACgB,EAAEnB,SAAS,CAACsC,SAAS;CAC1BnB,EAAEnB,QAAQ;CACV,MAAMyC,gBAAgBtB,EAAE7B;CACxB+B,eAAeF,CAAC;CAChB,IAAIA,EAAE7B,cAAcmD,eAAeZ,YAAYV,CAAC;CAChD,IAAIA,EAAE7B,cAAcmD,iBAAiB,CAACtB,EAAEjB,iBAAiB,CAACoC,SAAS;CACnEnB,EAAEjB,gBAAgB;CAClBiB,EAAEhB,iBAAiBA;CACnB,IAAIuB,OAAOP,EAAE7B;CACb,IAAIoD,QAAkC,CAAA;CACtC,IAAIN,cAAcjB,EAAE7B,cAAcmC,KAAAA,GAChC,KAAK,MAAMkB,WAAWxB,EAAEjC,UAAU;EAChC,IAAIyD,QAAQhE,SAAS;EACrB,MAAM,EAAED,QAAQiE;EAChB,IACEjE,IAAIkE,aAAanB,KAAAA,KACjB/C,IAAIkE,cAAczB,EAAEtC,WAAW,CAAC,CAAC+D,YAAY,YAE7C;EACF,MAAMC,MAAyC;GAC7CE,IAAIrE,IAAIqE;GACRC,KAAKtE,IAAIsE;GACT,GAAItE,IAAIuE,aAAaxB,KAAAA,KAAa,EAAEwB,UAAUvE,IAAIuE,SAAS;EAC7D;EACA,IAAI;GACF,MAAMC,WAAWhG,gBAAgBwE,OAAOyB,UACtCf,WACEe,OACA;IAAEC,QAAQ1E,IAAI0E;IAAQC,QAAQ3E,IAAI2E;GAAO,GACzCR,GACF,CACF;GACAnB,OAAOwB,SAAStB;GAChBc,QAAQ,CAAC,GAAGA,OAAO,GAAGQ,SAASK,YAAY;EAC7C,SAAStF,OAAO;GACd0E,QAAQhE,UAAU;GAClB6E,QAAQvF,MACN,4CAA4CS,IAAI0E,OAAM,oCACtDnF,KACF;EACF;CACF;CAEF,IAAIoE,eAAeX,SAASD,KAAAA,GAC1B,IAAI;EACF,MAAMyB,WAAWhG,gBAAgBwE,OAAOyB,UACtCd,YAAYc,KAAc,CAC5B;EACAzB,OAAOwB,SAAStB;EAChBc,QAAQ,CAAC,GAAGA,OAAO,GAAGQ,SAASK,YAAY;CAC7C,SAAStF,OAAO;EACduF,QAAQvF,MACN,+DACAA,KACF;CACF;CAEFkD,EAAE5B,YAAYmC;CACdP,EAAE3B,eAAekD;AACnB;AAEA,MAAMe,iBAAiBtC,MACrBA,EAAEpC,OAAO2E,cAAcjG;AAEzB,MAAMkG,SAASxC,GAASd,YAAY,UAAU;CAC5C,IAAI,CAACc,EAAEpC,OAAO;CACd,IAAIoC,EAAEf,UAAU;EACdc,SAASC,CAAC;EACV;CACF;CACAA,EAAEf,WAAW;CACb,IAAI;EACF+B,UAAUhB,CAAC;EACX,MAAMyC,UAAUzC,EAAEtC,WAAW;EAC7B,MAAMgF,eAAe1C,EAAE5B,cAAc4B,EAAE1B;EACvC,IAAIoE,cAAc;GAChB,MAAMC,OAAO3C,EAAE1B;GACf,MAAMsE,UAAU;IACd,GAAG5C,EAAE9B;IACL,GAAG8B,EAAEzB;IACL,GAAGyB,EAAE3B;GAAY;GAEnB2B,EAAE9B,iBAAiB,CAAA;GACnB8B,EAAE1B,oBAAoB0B,EAAE5B;GACxB4B,EAAEzB,uBAAuByB,EAAE3B;GAC3BoE,QAAQI,gBAAgB7C,EAAE5B,WAAoB,EAC5C0E,SAASpH,cAAciH,MAAM3C,EAAE5B,WAAWwE,OAAO,EACnD,CAAC;EACH;EACA,IAAI5C,EAAEhC,QAAQ+E,SAAS,KAAK/C,EAAE5B,cAAckC,KAAAA,GAAW;GACrD,MAAM0C,QAAQhD,EAAEhC;GAChBgC,EAAEhC,UAAU,CAAA;GACZ,KAAK,MAAMiF,UAAUD,OACnBP,QAAQS,kBAAkBD,QAAQ,EAAExC,OAAOT,EAAE5B,UAAmB,CAAC;EAErE;EACA,MAAMmE,aAAaD,cAActC,CAAC;EAClC,MAAMmD,oBAAoBZ,eAAevC,EAAExB;EAC3CwB,EAAExB,qBAAqB+D;EACvB,IAAIY,mBAAmBV,QAAQW,qBAAqBb,UAAU;EAC9D,IAAIA,WAAWzF,UAAUkD,EAAEvB,eAAe;GACxCuB,EAAEvB,gBAAgB8D,WAAWzF;GAC7B,IAAIyF,WAAWzF,OAAO2F,QAAQY,UAAUd,WAAWzF,KAAK;EAC1D;EACA,MAAMwG,OAAOtD,EAAER,QAAQ;EACvB,MAAM+D,cAAcD,SAAStD,EAAErB;EAC/BqB,EAAErB,eAAe2E;EAGjB,MAAME,SAASxD,EAAEpC,MAAMgD,UAAUE,KAAK,KAAKnE;EAC3C,IAAI8G,gBAAgB;EACpB,IAAID,WAAWxD,EAAEpB,gBAAgB;GAC/B,IAAIM,WAAW;IACbc,EAAEpB,iBAAiB4E;IACnBC,gBAAgB;GAClB,OACE1D,SAASC,CAAC;EAEd;EACA,IAAI0C,gBAAgBS,qBAAqBI,eAAeE,eACtD,KAAK,MAAM3D,YAAY,CAAC,GAAGE,EAAEb,SAAS,GAAGW,SAAS;CAEtD,UAAU;EACRE,EAAEf,WAAW;CACf;AACF;AAEA,MAAMyE,QACJ1D,GACAzC,KACAf,QACAmH,UACG;CACH,IAAI,CAAC3D,EAAEtC,WAAW,CAAC,CAACwF,iBAAiB;CACrClD,EAAEhC,QAAQmC,KAAK;EACb,GAAI5C,IAAIkE,aAAanB,KAAAA,KAAa,EAAEmB,UAAUlE,IAAIkE,SAAS;EAC3DQ,QAAQ1E,IAAI0E;EACZC,QAAQ3E,IAAI2E;EACZL,KAAKtE,IAAIsE;EACTrF;EACA,GAAGmH;CACL,CAAC;CACD5D,SAASC,CAAC;AACZ;AAEA,MAAM6D,UAAU7D,GAASO,SAA6B;CACpD,IAAIA,SAASP,EAAEpC,OAAO;CACtB,MAAM+E,OAAO3C,EAAEpC;CACfoC,EAAEpC,QAAQ2C;CACV,MAAMuD,aACJvD,KAAK1C,WACJ,OAAO0C,KAAKE,UAAU,YAAYF,KAAKE,UAAU,OAC9C7E,aAAa2E,KAAKE,KAAK,IACvBH,KAAAA,MACJ;CACF,IAAIwD,eAAe9D,EAAEnC,QAAQ;EAC3BmC,EAAEnC,QAAQkG,YAAY,IAAI;EAC1B/D,EAAEnC,SAASiG;EACX9D,EAAEnC,QAAQkG,kBAAkB9D,UAAUD,CAAC,CAAC;EAExCA,EAAElB,eAAe;EACjBmB,UAAUD,CAAC;CACb;CACA,IAAIO,KAAKZ,aAAagD,MAAMhD,UAAU;EACpC,IAAIgD,MAAMhH,gBAAgBgH,KAAKhD,QAAQ,CAAC,EAAEqE,YAAY,IAAI;EAC1DrI,gBAAgB4E,KAAKZ,QAAQ,CAAC,EAAEqE,YAAYhE,EAAEV,gBAAgB;EAC9D,IAAIU,EAAEjC,SAASgF,SAAS,GAAG;GACzB/C,EAAEjC,WAAW,CAAA;GACbiC,EAAEjB,gBAAgB;EACpB;EACAkB,UAAUD,CAAC;CACb;CACA,IAAI,CAACA,EAAEnC,QAAQoC,UAAUD,CAAC;CAC1BD,SAASC,CAAC;AACZ;AAEA,MAAMiE,UAAUjE,MAAY;CAC1BA,EAAEnC,QAAQkG,YAAY,IAAI;CAC1B/D,EAAEnC,SAAS;CACX,IAAImC,EAAEpC,OAAO;EACXjC,gBAAgBqE,EAAEpC,MAAM+B,QAAQ,CAAC,EAAEqE,YAAY,IAAI;EACnDhE,EAAEpC,QAAQ;CACZ;AACF;AAEA,MAAasG,oBACXxG,YACAE,UACG;CACH,MAAM,CAACuG,QAAQ1I,eAAqB;EAClC,MAAMuE,IAAU;GACdtC;GACAE,OAAO;GACPC,QAAQ;GACRE,UAAU,CAAA;GACVC,SAAS,CAAA;GACTE,gBAAgB,CAAA;GAChBC,WAAWmC,KAAAA;GACXlC,WAAWkC,KAAAA;GACXjC,cAAc,CAAA;GACdC,mBAAmBgC,KAAAA;GACnB/B,sBAAsB,CAAA;GACtBC,oBAAoB;GACpBC,eAAe6B,KAAAA;GACf3B,cAAc;GACdC,gBAAgBjC;GAChBkC,OAAO;GACPC,cAAc;GACdC,eAAe;GACfC,gBAAgBsB,KAAAA;GAChBrB,UAAU;GACVC,WAAW;GACXC,2BAAW,IAAIC,IAAI;GACnBC,MAAMrD,4BAA4B;IAChCgE,EAAEd,YAAY;IACdsD,MAAMxC,GAAG,IAAI;GACf,CAAC;GACDV,kBAAkB;IAChB8E,UAAU7G,QAAQ;KAChByC,EAAEjC,SAASoC,KAAK;MAAE5C;MAAKC,SAAS;KAAM,CAAC;KACvCwC,EAAEjB,gBAAgB;KAClBkB,UAAUD,CAAC;KACX0D,KAAK1D,GAAGzC,KAAK,QAAQ;IACvB;IACA8G,WAAW9G,UAAQmG,KAAK1D,GAAGzC,OAAK,QAAQ;IACxC+G,YAAY/G,UAAQmG,KAAK1D,GAAGzC,OAAK,SAAS;IAC1CgH,YAAYhH,UAAQ;KAClB,IAAI,CAACyC,EAAEjC,SAASyG,MAAMC,MAAMA,EAAElH,QAAQA,KAAG,GAAG;KAC5CyC,EAAEjC,WAAWiC,EAAEjC,SAAS2G,QAAQD,QAAMA,IAAElH,QAAQA,KAAG;KACnDyC,EAAEjB,gBAAgB;KAClBkB,UAAUD,CAAC;IACb;IACA2E,WAAWpH,OAAKqH,YAAY;KAC1BlB,KACE1D,GACAzC,OACA,WACAqH,QAAQC,SAAS,aACb,EAAEjB,QAAQgB,QAAQE,QAAQ,IAC1B,EAAE9H,SAASH,UAAU+H,QAAQ9H,KAAK,EAAE,CAC1C;KACA0F,MAAMxC,CAAC;IACT;GACF;GACAT,gBAAgB;IACdyB,UAAUhB,CAAC;IACX,OAAOA,EAAE5B;GACX;GACAoB,eAAeQ,EAAEpC,OAAOmH,UAAU;GAClCtF,iBAAiBO,EAAEpB;GACnBc,qBAAqB8C,MAAMxC,CAAC;GAC5BL,UAAU1D,mBACPgG,QAAQC,WAAW;IAClB,IAAI,CAAClC,EAAEpC,OACL,OAAOoH,QAAQC,OACb,IAAI9I,mBAAmB;KAAEc,MAAM;KAAWC,OAAO;IAAU,CAAC,CAC9D;IAEF,MAAMgI,OACJlF,EAAEpC,MAAM+B,SAIRsC;IACF,MAAMoD,UAAUH,KAAK,GAAGhD,MAAM;IAC9BM,MAAMxC,CAAC;IACP,OAAOqF;GACT,CACF;GACAxF,YAAYC,aAAa;IACvBE,EAAEb,UAAUmG,IAAIxF,QAAQ;IACxB,aAAa;KACXE,EAAEb,UAAUoG,OAAOzF,QAAQ;IAC7B;GACF;EACF;EACA,OAAOE;CACT,CAAC;CACDmE,KAAKzG,aAAaA;CAIlBmG,OAAOM,MAAMvG,KAAK;CAClBpC,gBAAgB;EACdqI,OAAOM,MAAMvG,KAAK;CACpB,CAAC;CACDpC,sBAAsByI,OAAOE,IAAI,GAAG,CAACA,IAAI,CAAC;CAC1C,OAAOA;AACT"}
|
|
1
|
+
{"version":3,"file":"core.js","names":["useEffect","useState","createChanges","getCommandsHost","getStateHost","CommandsInvocation","CommandsListener","recordMutations","createMacrotaskPoster","createMethodProxy","StatewirePath","StatewireSendError","Statewire","StatewireClient","CONNECTED_CONNECTION","Connection","status","degraded","reconnect","NO_FAILED","FailedCommand","failureOf","error","SendFailure","failure","fate","cause","message","Error","String","Overlay","inv","dropped","Core","getOptions","Options","value","source","StateSource","overlays","updates","CommandUpdate","pendingChanged","canonical","published","overlayPaths","notifiedPublished","notifiedOverlayPaths","notifiedConnection","notifiedError","ConnectionError","notifiedBusy","notifiedFailed","stale","everAttached","overlaysDirty","materializeKey","flushing","scheduled","listeners","Set","post","commandsListener","getState","getBusy","getFailed","rematerialize","commands","CommandsProxy","subscribe","listener","schedule","c","markStale","drainCanonical","push","takeChanged","snapshot","undefined","next","initialState","state","dropCovered","failureCovered","failures","entry","list","discard","recompute","optimistic","materialize","rekeyed","Object","is","prevCanonical","paths","overlay","protocol","ctx","OptimisticContext","ts","seq","clientId","recorded","draft","method","params","Command","changedPaths","console","getConnection","connection","flush","options","stateChanged","prev","changed","onStateChange","changes","length","batch","update","onCommandChange","connectionChanged","onConnectionChange","onError","busy","busyChanged","failed","failedChanged","note","extra","result","attach","nextSource","setOnChange","setListener","detach","useStatewireCore","core","onStart","onPosted","onApplied","onCovered","some","o","filter","onSettle","outcome","type","payload","isBusy","Promise","reject","send","Record","args","promise","add","delete"],"sources":["../../src/client/core.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\nimport { createChanges } from \"./changes\";\nimport { getCommandsHost, getStateHost } from \"../host/host\";\nimport type { CommandsInvocation, CommandsListener } from \"../host/host\";\nimport { recordMutations } from \"../util/recordMutations\";\nimport { createMacrotaskPoster } from \"../util/macrotask\";\nimport { createMethodProxy } from \"../util/methodProxy\";\nimport type { StatewirePath } from \"../wire/ops\";\nimport { StatewireSendError } from \"../types\";\nimport type { Statewire } from \"../types\";\nimport type { StatewireClient } from \"../statewire\";\n\nexport const CONNECTED_CONNECTION: StatewireClient.Connection = {\n status: \"connected\",\n degraded: false,\n reconnect: () => {},\n};\n\nconst NO_FAILED: readonly StatewireClient.FailedCommand[] = [];\n\nconst failureOf = (error: unknown): StatewireClient.SendFailure =>\n error instanceof StatewireSendError\n ? error.failure\n : {\n fate: \"rejected\",\n cause: \"server\",\n message: error instanceof Error ? error.message : String(error),\n };\n\ntype Overlay = { inv: CommandsInvocation; dropped: boolean };\n\ntype Core = {\n getOptions: () => StatewireClient.Options<any, any>;\n value: Statewire<unknown> | null;\n source: Statewire.StateSource | null;\n overlays: Overlay[];\n updates: Statewire.CommandUpdate[];\n pendingChanged: StatewirePath[];\n canonical: unknown;\n published: unknown;\n overlayPaths: readonly StatewirePath[];\n notifiedPublished: unknown;\n notifiedOverlayPaths: readonly StatewirePath[];\n notifiedConnection: StatewireClient.Connection | null;\n notifiedError: StatewireClient.ConnectionError | undefined;\n notifiedBusy: boolean;\n notifiedFailed: readonly StatewireClient.FailedCommand[];\n stale: boolean;\n everAttached: boolean;\n overlaysDirty: boolean;\n materializeKey: unknown;\n flushing: boolean;\n scheduled: boolean;\n listeners: Set<() => void>;\n post: () => void;\n commandsListener: CommandsListener;\n getState: () => unknown;\n getBusy: () => boolean;\n getFailed: () => readonly StatewireClient.FailedCommand[];\n rematerialize: () => void;\n commands: Statewire.CommandsProxy<any>;\n subscribe: (listener: () => void) => () => void;\n};\n\nconst schedule = (c: Core) => {\n if (c.scheduled) return;\n c.scheduled = true;\n c.post();\n};\n\nconst markStale = (c: Core) => {\n c.stale = true;\n schedule(c);\n};\n\n// initialState stands in for the canonical state only before the first\n// attach snapshot; replay boundaries after that read as loading, not preload.\nconst drainCanonical = (c: Core) => {\n if (c.source) {\n c.pendingChanged.push(...c.source.takeChanged());\n const snapshot = c.source.snapshot();\n if (snapshot !== undefined) {\n c.everAttached = true;\n c.canonical = snapshot;\n return;\n }\n const next = c.everAttached ? undefined : c.getOptions().initialState;\n if (next !== c.canonical) c.pendingChanged.push([]);\n c.canonical = next;\n } else if (c.value) {\n if (c.value.state !== undefined) c.everAttached = true;\n const next = c.everAttached ? c.value.state : c.getOptions().initialState;\n if (next !== c.canonical) {\n c.pendingChanged.push([]);\n c.canonical = next;\n }\n }\n};\n\nconst dropCovered = (c: Core) => {\n const { failureCovered } = c.getOptions();\n const failures = c.value?.failures;\n if (!failureCovered || !failures || c.canonical === undefined) return;\n for (const entry of failures.list()) {\n if (failureCovered(c.canonical as never, entry)) failures.discard(entry);\n }\n};\n\nconst recompute = (c: Core) => {\n if (!c.value) return;\n const { optimistic, materialize, materializeKey } = c.getOptions();\n const rekeyed = !Object.is(materializeKey, c.materializeKey);\n if (!c.stale && !rekeyed) return;\n c.stale = false;\n const prevCanonical = c.canonical;\n drainCanonical(c);\n if (c.canonical !== prevCanonical) dropCovered(c);\n if (c.canonical === prevCanonical && !c.overlaysDirty && !rekeyed) return;\n c.overlaysDirty = false;\n c.materializeKey = materializeKey;\n let next = c.canonical;\n let paths: readonly StatewirePath[] = [];\n if (optimistic && c.canonical !== undefined) {\n for (const overlay of c.overlays) {\n if (overlay.dropped) continue;\n const { inv } = overlay;\n if (\n inv.protocol !== undefined &&\n inv.protocol !== (c.getOptions().protocol ?? \"default\")\n )\n continue;\n const ctx: StatewireClient.OptimisticContext = {\n ts: inv.ts,\n seq: inv.seq,\n ...(inv.clientId !== undefined && { clientId: inv.clientId }),\n };\n try {\n const recorded = recordMutations(next, (draft) =>\n optimistic(\n draft as never,\n { method: inv.method, params: inv.params } as Statewire.Command,\n ctx,\n ),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n overlay.dropped = true;\n console.error(\n `statewire: optimistic reducer threw for \"${inv.method}\"; dropping its optimistic update`,\n error,\n );\n }\n }\n }\n if (materialize && next !== undefined) {\n try {\n const recorded = recordMutations(next, (draft) =>\n materialize(draft as never),\n );\n next = recorded.state;\n paths = [...paths, ...recorded.changedPaths];\n } catch (error) {\n console.error(\n \"statewire: materialize threw; publishing without its update\",\n error,\n );\n }\n }\n c.published = next;\n c.overlayPaths = paths;\n};\n\nconst getConnection = (c: Core): StatewireClient.Connection =>\n c.value?.connection ?? CONNECTED_CONNECTION;\n\nconst flush = (c: Core, scheduled = false) => {\n if (!c.value) return;\n if (c.flushing) {\n schedule(c);\n return;\n }\n c.flushing = true;\n try {\n recompute(c);\n const options = c.getOptions();\n const stateChanged = c.published !== c.notifiedPublished;\n if (stateChanged) {\n const prev = c.notifiedPublished;\n const changed = [\n ...c.pendingChanged,\n ...c.notifiedOverlayPaths,\n ...c.overlayPaths,\n ];\n c.pendingChanged = [];\n c.notifiedPublished = c.published;\n c.notifiedOverlayPaths = c.overlayPaths;\n options.onStateChange?.(c.published as never, {\n changes: createChanges(prev, c.published, changed),\n });\n }\n if (c.updates.length > 0 && c.published !== undefined) {\n const batch = c.updates;\n c.updates = [];\n for (const update of batch) {\n options.onCommandChange?.(update, { state: c.published as never });\n }\n }\n const connection = getConnection(c);\n const connectionChanged = connection !== c.notifiedConnection;\n c.notifiedConnection = connection;\n if (connectionChanged) options.onConnectionChange?.(connection);\n if (connection.error !== c.notifiedError) {\n c.notifiedError = connection.error;\n if (connection.error) options.onError?.(connection.error);\n }\n const busy = c.getBusy();\n const busyChanged = busy !== c.notifiedBusy;\n c.notifiedBusy = busy;\n // The failed snapshot advances only on the scheduled pass: settles land\n // mid-unmount, where a changed snapshot re-renders the unmounting tree.\n const failed = c.value?.failures?.list() ?? NO_FAILED;\n let failedChanged = false;\n if (failed !== c.notifiedFailed) {\n if (scheduled) {\n c.notifiedFailed = failed;\n failedChanged = true;\n } else {\n schedule(c);\n }\n }\n if (stateChanged || connectionChanged || busyChanged || failedChanged) {\n for (const listener of [...c.listeners]) listener();\n }\n } finally {\n c.flushing = false;\n }\n};\n\nconst note = (\n c: Core,\n inv: CommandsInvocation,\n status: Statewire.CommandUpdate[\"status\"],\n extra?: { result?: unknown; failure?: StatewireClient.SendFailure },\n) => {\n if (!c.getOptions().onCommandChange) return;\n c.updates.push({\n ...(inv.protocol !== undefined && { protocol: inv.protocol }),\n method: inv.method,\n params: inv.params as never[],\n seq: inv.seq,\n status,\n ...extra,\n });\n schedule(c);\n};\n\nconst attach = (c: Core, next: Statewire<unknown>) => {\n if (next === c.value) return;\n const prev = c.value;\n c.value = next;\n const nextSource =\n next.source ??\n (typeof next.state === \"object\" && next.state !== null\n ? getStateHost(next.state)\n : undefined) ??\n null;\n if (nextSource !== c.source) {\n c.source?.setOnChange(null);\n c.source = nextSource;\n c.source?.setOnChange(() => markStale(c));\n // A new source is a new attach lifecycle: initialState preloads again.\n c.everAttached = false;\n markStale(c);\n }\n if (next.commands !== prev?.commands) {\n if (prev) getCommandsHost(prev.commands)?.setListener(null);\n getCommandsHost(next.commands)?.setListener(c.commandsListener);\n if (c.overlays.length > 0) {\n c.overlays = [];\n c.overlaysDirty = true;\n }\n markStale(c);\n }\n if (!c.source) markStale(c);\n schedule(c);\n};\n\nconst detach = (c: Core) => {\n c.source?.setOnChange(null);\n c.source = null;\n if (c.value) {\n getCommandsHost(c.value.commands)?.setListener(null);\n c.value = null;\n }\n};\n\nexport const useStatewireCore = (\n getOptions: () => StatewireClient.Options<any, any>,\n value: Statewire<unknown>,\n) => {\n const [core] = useState((): Core => {\n const c: Core = {\n getOptions,\n value: null,\n source: null,\n overlays: [],\n updates: [],\n pendingChanged: [],\n canonical: undefined,\n published: undefined,\n overlayPaths: [],\n notifiedPublished: undefined,\n notifiedOverlayPaths: [],\n notifiedConnection: null,\n notifiedError: undefined,\n notifiedBusy: true,\n notifiedFailed: NO_FAILED,\n stale: false,\n everAttached: false,\n overlaysDirty: false,\n materializeKey: undefined,\n flushing: false,\n scheduled: false,\n listeners: new Set(),\n post: createMacrotaskPoster(() => {\n c.scheduled = false;\n flush(c, true);\n }),\n commandsListener: {\n onStart: (inv) => {\n c.overlays.push({ inv, dropped: false });\n c.overlaysDirty = true;\n markStale(c);\n note(c, inv, \"queued\");\n },\n onPosted: (inv) => note(c, inv, \"posted\"),\n onApplied: (inv) => note(c, inv, \"applied\"),\n onCovered: (inv) => {\n if (!c.overlays.some((o) => o.inv === inv)) return;\n c.overlays = c.overlays.filter((o) => o.inv !== inv);\n c.overlaysDirty = true;\n markStale(c);\n },\n onSettle: (inv, outcome) => {\n note(\n c,\n inv,\n \"settled\",\n outcome.type === \"accepted\"\n ? { result: outcome.payload }\n : { failure: failureOf(outcome.error) },\n );\n flush(c);\n },\n },\n getState: () => {\n recompute(c);\n return c.published;\n },\n getBusy: () => c.value?.isBusy ?? true,\n getFailed: () => c.notifiedFailed,\n rematerialize: () => flush(c),\n commands: createMethodProxy<Statewire.CommandsProxy<any>>(\n (method, params) => {\n if (!c.value) {\n return Promise.reject(\n new StatewireSendError({ fate: \"aborted\", cause: \"unmount\" }),\n );\n }\n const send = (\n c.value.commands as Record<\n string,\n (...args: unknown[]) => Promise<unknown>\n >\n )[method]!;\n const promise = send(...params);\n flush(c);\n return promise;\n },\n ),\n subscribe: (listener) => {\n c.listeners.add(listener);\n return () => {\n c.listeners.delete(listener);\n };\n },\n };\n return c;\n });\n core.getOptions = getOptions;\n // Attach during render so the first snapshot reads the transport's state;\n // re-attaching the same transport is a no-op and the single-slot host\n // listeners make a swap land on the last writer.\n attach(core, value);\n useEffect(() => {\n attach(core, value);\n });\n useEffect(() => () => detach(core), [core]);\n return core;\n};\n"],"mappings":"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"}
|
package/dist/client/timing.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing.d.ts","names":[],"sources":["../../src/client/timing.ts"],"mappings":";cAAa
|
|
1
|
+
{"version":3,"file":"timing.d.ts","names":[],"sources":["../../src/client/timing.ts"],"mappings":";cAAa;;;;;;;;;;cAWA,YAAa;cAGb,UAAW"}
|
package/dist/client/timing.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
//#region src/client/timing.ts
|
|
2
2
|
const timing = {
|
|
3
|
-
|
|
3
|
+
backoffFirstMs: 0,
|
|
4
|
+
backoffBaseMs: 1e3,
|
|
4
5
|
backoffMaxMs: 3e4,
|
|
6
|
+
backoffJitter: .5,
|
|
5
7
|
backoffResetMs: 3e4,
|
|
6
8
|
heartbeatTimeoutMs: 3e4,
|
|
7
9
|
pingIntervalMs: 1e4,
|
|
@@ -9,9 +11,8 @@ const timing = {
|
|
|
9
11
|
};
|
|
10
12
|
const retryHint = (ms) => Math.min(ms, timing.backoffMaxMs);
|
|
11
13
|
const backoff = (attempt) => {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
return Math.round(floor + (limit - floor) * timing.random());
|
|
14
|
+
const floor = attempt <= 1 ? timing.backoffFirstMs : Math.min(timing.backoffBaseMs * 2 ** (attempt - 2), timing.backoffMaxMs);
|
|
15
|
+
return Math.round(floor * (1 + timing.backoffJitter * timing.random()));
|
|
15
16
|
};
|
|
16
17
|
//#endregion
|
|
17
18
|
export { backoff, retryHint, timing };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timing.js","names":["timing","backoffBaseMs","backoffMaxMs","backoffResetMs","heartbeatTimeoutMs","pingIntervalMs","random","Math","retryHint","ms","min","backoff","attempt","
|
|
1
|
+
{"version":3,"file":"timing.js","names":["timing","backoffFirstMs","backoffBaseMs","backoffMaxMs","backoffJitter","backoffResetMs","heartbeatTimeoutMs","pingIntervalMs","random","Math","retryHint","ms","min","backoff","attempt","floor","round"],"sources":["../../src/client/timing.ts"],"sourcesContent":["export const timing = {\n backoffFirstMs: 0,\n backoffBaseMs: 1_000,\n backoffMaxMs: 30_000,\n backoffJitter: 0.5,\n backoffResetMs: 30_000,\n heartbeatTimeoutMs: 30_000,\n pingIntervalMs: 10_000,\n random: Math.random,\n};\n\nexport const retryHint = (ms: number) => Math.min(ms, timing.backoffMaxMs);\n\n// Jitter only stretches the floor, so attempt n never lands before floor(n).\nexport const backoff = (attempt: number) => {\n const floor =\n attempt <= 1\n ? timing.backoffFirstMs\n : Math.min(\n timing.backoffBaseMs * 2 ** (attempt - 2),\n timing.backoffMaxMs,\n );\n return Math.round(floor * (1 + timing.backoffJitter * timing.random()));\n};\n"],"mappings":";AAAA,MAAaA,SAAS;CACpBC,gBAAgB;CAChBC,eAAe;CACfC,cAAc;CACdC,eAAe;CACfC,gBAAgB;CAChBC,oBAAoB;CACpBC,gBAAgB;CAChBC,QAAQC,KAAKD;AACf;AAEA,MAAaE,aAAaC,OAAeF,KAAKG,IAAID,IAAIX,OAAOG,YAAY;AAGzE,MAAaU,WAAWC,YAAoB;CAC1C,MAAMC,QACJD,WAAW,IACPd,OAAOC,iBACPQ,KAAKG,IACHZ,OAAOE,gBAAgB,MAAMY,UAAU,IACvCd,OAAOG,YACT;CACN,OAAOM,KAAKO,MAAMD,SAAS,IAAIf,OAAOI,gBAAgBJ,OAAOQ,OAAO,EAAE;AACxE"}
|
package/package.json
CHANGED
package/src/client/connection.ts
CHANGED
|
@@ -490,12 +490,14 @@ export const handleEnvelope = (
|
|
|
490
490
|
return null;
|
|
491
491
|
};
|
|
492
492
|
|
|
493
|
+
// A dial that no wait preceded is part of the current connect: only a
|
|
494
|
+
// scheduled delay surfaces `retrying`, and the dial after it keeps that status.
|
|
493
495
|
const dialing = (c: Conn) =>
|
|
494
496
|
setStatus(
|
|
495
497
|
c,
|
|
496
|
-
c.
|
|
497
|
-
? { status: "
|
|
498
|
-
: { status: "
|
|
498
|
+
c.connection.status === "retrying"
|
|
499
|
+
? { status: "retrying", attempt: c.attempt, degraded: true }
|
|
500
|
+
: { status: "connecting", degraded: false },
|
|
499
501
|
);
|
|
500
502
|
|
|
501
503
|
const scheduleRetry = (
|
|
@@ -513,6 +515,7 @@ const scheduleRetry = (
|
|
|
513
515
|
immediate ? 0 : backoff(c.attempt),
|
|
514
516
|
c.retryAt - Date.now(),
|
|
515
517
|
);
|
|
518
|
+
if (delay === 0) return delay;
|
|
516
519
|
setStatus(c, {
|
|
517
520
|
status: "retrying",
|
|
518
521
|
degraded: true,
|
package/src/client/core.ts
CHANGED
|
@@ -219,7 +219,7 @@ const flush = (c: Core, scheduled = false) => {
|
|
|
219
219
|
c.notifiedBusy = busy;
|
|
220
220
|
// The failed snapshot advances only on the scheduled pass: settles land
|
|
221
221
|
// mid-unmount, where a changed snapshot re-renders the unmounting tree.
|
|
222
|
-
const failed = c.value
|
|
222
|
+
const failed = c.value?.failures?.list() ?? NO_FAILED;
|
|
223
223
|
let failedChanged = false;
|
|
224
224
|
if (failed !== c.notifiedFailed) {
|
|
225
225
|
if (scheduled) {
|
package/src/client/timing.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export const timing = {
|
|
2
|
-
|
|
2
|
+
backoffFirstMs: 0,
|
|
3
|
+
backoffBaseMs: 1_000,
|
|
3
4
|
backoffMaxMs: 30_000,
|
|
5
|
+
backoffJitter: 0.5,
|
|
4
6
|
backoffResetMs: 30_000,
|
|
5
7
|
heartbeatTimeoutMs: 30_000,
|
|
6
8
|
pingIntervalMs: 10_000,
|
|
@@ -9,11 +11,14 @@ export const timing = {
|
|
|
9
11
|
|
|
10
12
|
export const retryHint = (ms: number) => Math.min(ms, timing.backoffMaxMs);
|
|
11
13
|
|
|
14
|
+
// Jitter only stretches the floor, so attempt n never lands before floor(n).
|
|
12
15
|
export const backoff = (attempt: number) => {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const floor =
|
|
17
|
+
attempt <= 1
|
|
18
|
+
? timing.backoffFirstMs
|
|
19
|
+
: Math.min(
|
|
20
|
+
timing.backoffBaseMs * 2 ** (attempt - 2),
|
|
21
|
+
timing.backoffMaxMs,
|
|
22
|
+
);
|
|
23
|
+
return Math.round(floor * (1 + timing.backoffJitter * timing.random()));
|
|
19
24
|
};
|