statewire 0.24.0 → 0.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/connection.d.ts +4 -0
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +9 -2
- package/dist/client/connection.js.map +1 -1
- package/dist/client/session.d.ts +9 -0
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +100 -17
- package/dist/client/session.js.map +1 -1
- package/dist/host/host.d.ts +1 -0
- package/dist/host/host.d.ts.map +1 -1
- package/dist/host/host.js +8 -0
- package/dist/host/host.js.map +1 -1
- package/dist/host/socket.d.ts.map +1 -1
- package/dist/host/socket.js +3 -2
- package/dist/host/socket.js.map +1 -1
- package/dist/host.d.ts +13 -7
- package/dist/host.d.ts.map +1 -1
- package/dist/storage.js +1 -1
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +2 -1
- package/dist/transports/sse.js.map +1 -1
- package/dist/wire/protocol.d.ts +6 -1
- package/dist/wire/protocol.d.ts.map +1 -1
- package/dist/wire/protocol.js +12 -4
- package/dist/wire/protocol.js.map +1 -1
- package/package.json +1 -1
- package/src/client/connection.ts +11 -0
- package/src/client/session.ts +166 -18
- package/src/host/host.ts +13 -0
- package/src/host/socket.ts +5 -2
- package/src/host.ts +14 -6
- package/src/transports/sse.ts +2 -0
- package/src/wire/protocol.ts +11 -3
package/dist/host.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,mBAAgB;AAEzC,OAAO,EAAE,eAAe,EAAE,yBAAsB;AAChD,OAAO,EAAE,gBAAgB,EAAE,uBAAoB;AAC/C,OAAO,EAAE,MAAM,EAAE,wBAAqB;AACtC,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,GACrB,uBAAoB;AACrB,OAAO,EAAE,cAAc,EAAE,yBAAsB;AAE/C,yBAAiB,aAAa,CAAC;IAC7B,KAAY,IAAI,GAAG;QACjB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;QACzB,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;QAC3C,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;KAC1C,CAAC;IAEF,KAAY,QAAQ,CAAC,MAAM,GAAG,OAAO,IAAI;QACvC,qEAAqE;QACrE,KAAK,EAAE,CAAC,GAAG,EAAE,SAAS,SAAS,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC;QAC9C,uGAAuG;QACvG,QAAQ,EAAE,MAAM,MAAM,CAAC;KACxB,CAAC;IAEF,KAAY,QAAQ,GAAG;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;QAC9B,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;KAChB,CAAC;IAEF,KAAY,SAAS,GAAG,SAAS,CAAC,WAAW,GAAG;QAC9C,oEAAoE;QACpE,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;QACjE,4HAA4H;QAC5H,KAAK,EAAE,CACL,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;YAAE,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;YAAC,IAAI,CAAC,EAAE,OAAO,CAAA;SAAE,KAClD,IAAI,CAAC;QACV,OAAO,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;QAC7D,SAAS,EAAE,MAAM,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC/C,cAAc,EAAE,CAAC,QAAQ,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;KACzD,CAAC;IAEF
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"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"}
|
package/dist/storage.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/transports/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,uBAAoB;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/transports/sse.ts"],"names":[],"mappings":"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"}
|
package/dist/transports/sse.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { negotiationHeaders, parseNegotiation } from "../wire/protocol.js";
|
|
2
2
|
import { timing } from "../client/timing.js";
|
|
3
|
-
import { classify, handleEnvelope, resolveHeaders, settleFin, useLink, validateRefusalSyn } from "../client/connection.js";
|
|
3
|
+
import { classify, handleEnvelope, replacing, resolveHeaders, settleFin, useLink, validateRefusalSyn } from "../client/connection.js";
|
|
4
4
|
import { createSseParser } from "./sse-parser.js";
|
|
5
5
|
import { useStatewireRemote } from "./remote.js";
|
|
6
6
|
import { flushTapSync, resource } from "@assistant-ui/tap";
|
|
@@ -55,6 +55,7 @@ const attemptStream = async (c, options, abort) => {
|
|
|
55
55
|
const headers = await resolveHeaders(options.headers, c.authStale);
|
|
56
56
|
for (const [name, value] of Object.entries(negotiationHeaders(options))) if (!headers.has(name)) headers.set(name, value);
|
|
57
57
|
c.negotiation = parseNegotiation(headers);
|
|
58
|
+
replacing(c, headers);
|
|
58
59
|
c.authStale = false;
|
|
59
60
|
const lanes = flushTapSync(() => c.ctx.takeAttachLanes());
|
|
60
61
|
const body = lanes === null ? void 0 : JSON.stringify(lanes);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.js","names":["StatewireDocument","flushTapSync","resource","ResourceElement","createSseParser","timing","settleFin","classify","handleEnvelope","resolveHeaders","useLink","validateRefusalSyn","AttemptOutcome","Conn","StatewireCmd","StatewireEnvelope","StatewireSyn","Statewire","StatewireClient","StatewireHost","useStatewireRemote","negotiationHeaders","parseNegotiation","StatewireFrame","ctx","protocol","Encoded","cmd","method","params","meta","seq","res","StatewireRemoteProps","beforeAttach","Promise","clientId","takeAttachLanes","onHello","args","ops","syn","onOps","cmds","onCmds","onRefusal","onIdle","level","onDetach","onFinish","Fin","StatewireSubmitResult","type","ConnectionState","RemoteLink","storageFailed","error","Error","protocolFailed","connection","Connection","parked","send","frame","LEASE_HEADER","warnedNoLease","warnNoLease","console","warn","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","persistence","aborted","lease","authStale","has","negotiation","lanes","body","undefined","stringify","headerTimer","accept","cache","any","ok","clone","json","catch","fin","httpFin","get","getReader","cancel","addEventListener","once","removeEventListener","postFrame","lifetime","retryAfterMs","header","trim","test","retry","Number","isSafeInteger","reason","status","message","code","refusalSyn","sendFrame","headerRetry","useSseLink","attemptOnce","SyntaxError","startsWith","useStatewireHttp","StatewireHttp","Commands","TState","TCommands"],"sources":["../../src/transports/sse.ts"],"sourcesContent":["import type { StatewireDocument } from \"../document\";\nimport { 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 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 { negotiationHeaders, parseNegotiation } from \"../wire/protocol\";\n\n/** A client frame's lanes: stamped statements, strictly consecutive per lane. */\nexport type StatewireFrame = {\n ctx?: ({ protocol: string } & StatewireDocument.Encoded)[];\n cmd?: {\n protocol: string;\n method: string;\n params: unknown[];\n meta?: unknown;\n seq: number;\n }[];\n /** Attach only: per durable lane, the seq through which the client holds every verdict. */\n res?: { protocol: string; seq: number }[];\n};\n\nexport type StatewireRemoteProps = {\n beforeAttach?: () => void | Promise<void>;\n clientId: string;\n /** Lanes to ride the attach frame: ephemeral-lane statements, plus durable cmds on no-lease supersession; records the included entries. */\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 storageFailed: (error: Error) => void;\n protocolFailed: (error: Error) => void;\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\nlet warnedNoLease = false;\n\nconst warnNoLease = () => {\n if (warnedNoLease) return;\n warnedNoLease = true;\n console.warn(\n \"statewire: SSE attach returned no readable Statewire-Lease header; commands will re-attach the stream. Cross-origin hosts must expose it (Access-Control-Expose-Headers: Statewire-Lease).\",\n );\n};\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 const persistence = c.ctx.beforeAttach?.();\n if (persistence) await persistence;\n if (abort.signal.aborted) return \"ended\";\n c.lease = null;\n const headers = await resolveHeaders(options.headers, c.authStale);\n for (const [name, value] of Object.entries(negotiationHeaders(options))) {\n if (!headers.has(name)) headers.set(name, value);\n }\n c.negotiation = parseNegotiation(headers);\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) {\n const body = await res\n .clone()\n .json()\n .catch(() => null);\n return (\n flushTapSync(() =>\n body?.fin === undefined\n ? settleFin(c, httpFin(res))\n : handleEnvelope(c, body),\n ) ?? \"stop\"\n );\n }\n if (!res.body)\n throw new Error(\"statewire: protocol error: stream response has no body\");\n c.lease = res.headers.get(LEASE_HEADER);\n if (c.lease === null) warnNoLease();\n const reader = res.body.getReader();\n const cancel = () => {\n void reader.cancel().catch(() => {});\n };\n abort.signal.addEventListener(\"abort\", cancel, { once: true });\n try {\n return await consume(c, reader, heartbeat, () => abort.signal.aborted);\n } finally {\n abort.signal.removeEventListener(\"abort\", cancel);\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
|
+
{"version":3,"file":"sse.js","names":["StatewireDocument","flushTapSync","resource","ResourceElement","createSseParser","timing","replacing","settleFin","classify","handleEnvelope","resolveHeaders","useLink","validateRefusalSyn","AttemptOutcome","Conn","StatewireCmd","StatewireEnvelope","StatewireSyn","Statewire","StatewireClient","StatewireHost","useStatewireRemote","negotiationHeaders","parseNegotiation","StatewireFrame","ctx","protocol","Encoded","cmd","method","params","meta","seq","res","StatewireRemoteProps","beforeAttach","Promise","clientId","takeAttachLanes","onHello","args","ops","syn","onOps","cmds","onCmds","onRefusal","onIdle","level","onDetach","onFinish","Fin","StatewireSubmitResult","type","ConnectionState","RemoteLink","storageFailed","error","Error","protocolFailed","connection","Connection","parked","send","frame","LEASE_HEADER","warnedNoLease","warnNoLease","console","warn","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","persistence","aborted","lease","authStale","has","negotiation","lanes","body","undefined","stringify","headerTimer","accept","cache","any","ok","clone","json","catch","fin","httpFin","get","getReader","cancel","addEventListener","once","removeEventListener","postFrame","lifetime","retryAfterMs","header","trim","test","retry","Number","isSafeInteger","reason","status","message","code","refusalSyn","sendFrame","headerRetry","useSseLink","attemptOnce","SyntaxError","startsWith","useStatewireHttp","StatewireHttp","Commands","TState","TCommands"],"sources":["../../src/transports/sse.ts"],"sourcesContent":["import type { StatewireDocument } from \"../document\";\nimport { 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 replacing,\n settleFin,\n classify,\n handleEnvelope,\n resolveHeaders,\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 { negotiationHeaders, parseNegotiation } from \"../wire/protocol\";\n\n/** A client frame's lanes: stamped statements, strictly consecutive per lane. */\nexport type StatewireFrame = {\n ctx?: ({ protocol: string } & StatewireDocument.Encoded)[];\n cmd?: {\n protocol: string;\n method: string;\n params: unknown[];\n meta?: unknown;\n seq: number;\n }[];\n /** Attach only: per durable lane, the seq through which the client holds every verdict. */\n res?: { protocol: string; seq: number }[];\n};\n\nexport type StatewireRemoteProps = {\n beforeAttach?: () => void | Promise<void>;\n clientId: string;\n /** Lanes to ride the attach frame: ephemeral-lane statements, plus durable cmds on no-lease supersession; records the included entries. */\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 storageFailed: (error: Error) => void;\n protocolFailed: (error: Error) => void;\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\nlet warnedNoLease = false;\n\nconst warnNoLease = () => {\n if (warnedNoLease) return;\n warnedNoLease = true;\n console.warn(\n \"statewire: SSE attach returned no readable Statewire-Lease header; commands will re-attach the stream. Cross-origin hosts must expose it (Access-Control-Expose-Headers: Statewire-Lease).\",\n );\n};\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 const persistence = c.ctx.beforeAttach?.();\n if (persistence) await persistence;\n if (abort.signal.aborted) return \"ended\";\n c.lease = null;\n const headers = await resolveHeaders(options.headers, c.authStale);\n for (const [name, value] of Object.entries(negotiationHeaders(options))) {\n if (!headers.has(name)) headers.set(name, value);\n }\n c.negotiation = parseNegotiation(headers);\n replacing(c, headers);\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) {\n const body = await res\n .clone()\n .json()\n .catch(() => null);\n return (\n flushTapSync(() =>\n body?.fin === undefined\n ? settleFin(c, httpFin(res))\n : handleEnvelope(c, body),\n ) ?? \"stop\"\n );\n }\n if (!res.body)\n throw new Error(\"statewire: protocol error: stream response has no body\");\n c.lease = res.headers.get(LEASE_HEADER);\n if (c.lease === null) warnNoLease();\n const reader = res.body.getReader();\n const cancel = () => {\n void reader.cancel().catch(() => {});\n };\n abort.signal.addEventListener(\"abort\", cancel, { once: true });\n try {\n return await consume(c, reader, heartbeat, () => abort.signal.aborted);\n } finally {\n abort.signal.removeEventListener(\"abort\", cancel);\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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"}
|
package/dist/wire/protocol.d.ts
CHANGED
|
@@ -30,9 +30,14 @@ export declare namespace StatewireProtocol {
|
|
|
30
30
|
}[];
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
-
export declare const WIRE_VERSION = "2026-11-
|
|
33
|
+
export declare const WIRE_VERSION = "2026-11-02";
|
|
34
34
|
/** Attach carries a results cursor and gets its verdicts gap-filled; a re-sent seq at or below the watermark is a protocol error. */
|
|
35
35
|
export declare const GAP_FILL_VERSION = "2026-11-01";
|
|
36
|
+
/** Every attach of a connection names its attacher; a host retires the attacher's earlier attaches before the hello. */
|
|
37
|
+
export declare const FENCE_VERSION = "2026-11-02";
|
|
38
|
+
/** The wire a client offers by default: the gap-fill contract and newer. */
|
|
39
|
+
export declare const CLIENT_WIRE: StatewireProtocol.Range;
|
|
40
|
+
export declare const ATTACHER_HEADER = "Statewire-Attacher";
|
|
36
41
|
/** The oldest wire contract a host serves by default (re-sent seqs re-emit their verdicts). */
|
|
37
42
|
export declare const MIN_SERVED_WIRE_VERSION = "2026-09-30";
|
|
38
43
|
export declare const DEFAULT_PROTOCOL_VERSION = "2026-09-30";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/wire/protocol.ts"],"names":[],"mappings":"AAAA,yBAAiB,iBAAiB,CAAC;IACjC,KAAY,KAAK,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,KAAY,KAAK,GAAG,KAAK,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACjE,KAAY,SAAS,GAAG;QACtB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,EAAE,CAAC;KACtE,CAAC;IACF,KAAY,OAAO,GAAG;QACpB,WAAW,CAAC,EAAE,KAAK,CAAC;QACpB,oBAAoB,CAAC,EAAE,SAAS,KAAK,EAAE,GAAG,GAAG,CAAC;QAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;KAC3D,CAAC;IACF,KAAY,UAAU,GAAG,KAAK,GAAG;QAC/B,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;QAC3C,YAAY,CAAC,EAAE,SAAS;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,CAAC,EAAE,WAAW,CAAA;SAAE,EAAE,CAAC;KAClE,CAAC;CACH;AAED,eAAO,MAAM,YAAY,eAAe,CAAC;AACzC,qIAAqI;AACrI,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAC7C,+FAA+F;AAC/F,eAAO,MAAM,uBAAuB,eAAe,CAAC;AACpD,eAAO,MAAM,wBAAwB,eAAe,CAAC;AACrD,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAC1C,eAAO,MAAM,eAAe,uBAAuB,CAAC;AACpD,eAAO,MAAM,cAAc,sBAAsB,CAAC;AAClD,eAAO,MAAM,aAAa,QAA6C,CAAC;AAMxE,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,KAAG,MAWhD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,iBAAiB,CAAC,KAAK;;;CAQ3D,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,OAAO,MAAM,EAAE,OAAO,iBAAiB,CAAC,KAAK,YAGpE,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,SAAS,iBAAiB,CAAC,OAAO,6CAM9D,CAAC;AAEJ,eAAO,MAAM,kBAAkB,GAC7B,SAAS,iBAAiB,CAAC,OAAO,KACjC,MAAM,CAAC,MAAM,EAAE,MAAM,CAgCvB,CAAC;AA6BF,eAAO,MAAM,gBAAgB,GAC3B,SAAS,OAAO,KACf,QAAQ,CACT,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,aAAa,GAAG,sBAAsB,CAAC,CAwDxE,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,OAAO,OAAO,EACd,SAAS,iBAAiB,CAAC,OAAO,KACjC,iBAAiB,CAAC,SA2CpB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,SAAS,OAAO,EAChB,MAAM,iBAAiB,CAAC,KAAK,EAC7B,aAAa,SAAS,iBAAiB,CAAC,UAAU,EAAE,KAElD,iBAAiB,CAAC,SAAS,GAC3B;IACE,GAAG,EAAE;QACH,MAAM,EAAE,gBAAgB,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CA2GP,CAAC"}
|
|
1
|
+
{"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../src/wire/protocol.ts"],"names":[],"mappings":"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"}
|
package/dist/wire/protocol.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
// src/wire/protocol.ts
|
|
2
|
-
const WIRE_VERSION = "2026-11-
|
|
2
|
+
const WIRE_VERSION = "2026-11-02";
|
|
3
3
|
/** Attach carries a results cursor and gets its verdicts gap-filled; a re-sent seq at or below the watermark is a protocol error. */
|
|
4
4
|
const GAP_FILL_VERSION = "2026-11-01";
|
|
5
|
+
/** Every attach of a connection names its attacher; a host retires the attacher's earlier attaches before the hello. */
|
|
6
|
+
const FENCE_VERSION = "2026-11-02";
|
|
7
|
+
/** The wire a client offers by default: the gap-fill contract and newer. */
|
|
8
|
+
const CLIENT_WIRE = {
|
|
9
|
+
version: WIRE_VERSION,
|
|
10
|
+
minVersion: GAP_FILL_VERSION
|
|
11
|
+
};
|
|
12
|
+
const ATTACHER_HEADER = "Statewire-Attacher";
|
|
5
13
|
/** The oldest wire contract a host serves by default (re-sent seqs re-emit their verdicts). */
|
|
6
14
|
const MIN_SERVED_WIRE_VERSION = "2026-09-30";
|
|
7
15
|
const DEFAULT_PROTOCOL_VERSION = "2026-09-30";
|
|
@@ -44,7 +52,7 @@ const negotiationHeaders = (options) => {
|
|
|
44
52
|
const seen = /* @__PURE__ */ new Set();
|
|
45
53
|
if (offers !== "*" && !offers.length) invalid("protocol list must not be empty");
|
|
46
54
|
return {
|
|
47
|
-
[VERSION_HEADER]: suffix(options.wireVersion ??
|
|
55
|
+
[VERSION_HEADER]: suffix(options.wireVersion ?? CLIENT_WIRE),
|
|
48
56
|
[PROTOCOL_HEADER]: offers === "*" ? "*" : offers.map((offer) => {
|
|
49
57
|
if (!protocolToken.test(offer.name) || offer.name === "*" || seen.has(offer.name)) invalid("invalid or duplicate protocol name");
|
|
50
58
|
if (offer.optional !== void 0 && typeof offer.optional !== "boolean") invalid("optional must be boolean");
|
|
@@ -128,7 +136,7 @@ const validateSelection = (value, options) => {
|
|
|
128
136
|
if (typeof value !== "object" || value === null) return invalid("missing negotiation selection");
|
|
129
137
|
const syn = value;
|
|
130
138
|
const version = validateVersion(syn.version);
|
|
131
|
-
if (!inRange(version, options.wireVersion ??
|
|
139
|
+
if (!inRange(version, options.wireVersion ?? CLIENT_WIRE)) invalid("selected wire version is outside offer");
|
|
132
140
|
if (!Array.isArray(syn.protocols)) return invalid("syn.protocols must be an array");
|
|
133
141
|
const offers = protocolOffers(options);
|
|
134
142
|
const seen = /* @__PURE__ */ new Map();
|
|
@@ -241,6 +249,6 @@ const negotiateProtocols = (headers, wire, definitions) => {
|
|
|
241
249
|
})
|
|
242
250
|
};
|
|
243
251
|
};
|
|
244
|
-
export { DEFAULT_PROTOCOL, DEFAULT_PROTOCOL_VERSION, GAP_FILL_VERSION, MIN_SERVED_WIRE_VERSION, PROTOCOL_HEADER, VERSION_HEADER, WIRE_VERSION, inRange, negotiateProtocols, negotiationHeaders, parseNegotiation, protocolOffers, protocolToken, validateRange, validateSelection, validateVersion };
|
|
252
|
+
export { ATTACHER_HEADER, CLIENT_WIRE, DEFAULT_PROTOCOL, DEFAULT_PROTOCOL_VERSION, FENCE_VERSION, GAP_FILL_VERSION, MIN_SERVED_WIRE_VERSION, PROTOCOL_HEADER, VERSION_HEADER, WIRE_VERSION, inRange, negotiateProtocols, negotiationHeaders, parseNegotiation, protocolOffers, protocolToken, validateRange, validateSelection, validateVersion };
|
|
245
253
|
|
|
246
254
|
//# sourceMappingURL=protocol.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","names":["StatewireProtocol","Range","version","minVersion","Offer","name","optional","Selection","protocols","record","Options","wireVersion","applicationProtocols","protocol","keyPrefixes","Readonly","Record","Definition","requires","subprotocols","WIRE_VERSION","GAP_FILL_VERSION","MIN_SERVED_WIRE_VERSION","DEFAULT_PROTOCOL_VERSION","DEFAULT_PROTOCOL","PROTOCOL_HEADER","VERSION_HEADER","protocolToken","invalid","message","Error","validateVersion","value","test","parsed","Date","Number","isFinite","getTime","toISOString","slice","startsWith","validateRange","range","undefined","inRange","checked","protocolOffers","options","negotiationHeaders","suffix","offers","seen","Set","length","map","offer","has","add","join","parseItem","input","atom","String","raw","text","trim","match","RegExp","exec","quoted","decode","replace","params","Map","rest","parameter","key","set","parseNegotiation","headers","Headers","Required","Pick","wire","get","application","item","keys","some","k","names","split","includes","validateSelection","syn","Array","isArray","entry","parent","lastIndexOf","child","find","o","negotiateProtocols","definitions","fin","reason","code","status","payload","supported","d","failure","const","request","ReturnType","error","sort","registry","size","definition","children","offered","solve","active","dependency","Object","result","ranges","flatMap","lower","r","at","upper","selected","filter"],"sources":["../../src/wire/protocol.ts"],"sourcesContent":["export namespace StatewireProtocol {\n export type Range = { version: string; minVersion?: string };\n export type Offer = Range & { name: string; optional?: boolean };\n export type Selection = {\n version: string;\n protocols: { name: string; version: string; record?: \"ephemeral\" }[];\n };\n export type Options = {\n wireVersion?: Range;\n applicationProtocols?: readonly Offer[] | \"*\";\n protocol?: string;\n keyPrefixes?: Readonly<Record<string, readonly string[]>>;\n };\n export type Definition = Range & {\n name: string;\n requires?: Readonly<Record<string, Range>>;\n subprotocols?: readonly { name: string; record?: \"ephemeral\" }[];\n };\n}\n\nexport const WIRE_VERSION = \"2026-11-01\";\n/** Attach carries a results cursor and gets its verdicts gap-filled; a re-sent seq at or below the watermark is a protocol error. */\nexport const GAP_FILL_VERSION = \"2026-11-01\";\n/** The oldest wire contract a host serves by default (re-sent seqs re-emit their verdicts). */\nexport const MIN_SERVED_WIRE_VERSION = \"2026-09-30\";\nexport const DEFAULT_PROTOCOL_VERSION = \"2026-09-30\";\nexport const DEFAULT_PROTOCOL = \"default\";\nexport const PROTOCOL_HEADER = \"Statewire-Protocol\";\nexport const VERSION_HEADER = \"Statewire-Version\";\nexport const protocolToken = /^[A-Za-z*][A-Za-z0-9!#$%&'*+.^_`|~:/-]*$/;\n\nconst invalid = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nexport const validateVersion = (value: unknown): string => {\n if (typeof value !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value))\n return invalid(\"version must be a YYYY-MM-DD date\");\n const parsed = new Date(`${value}T00:00:00.000Z`);\n if (\n !Number.isFinite(parsed.getTime()) ||\n parsed.toISOString().slice(0, 10) !== value ||\n value.startsWith(\"0000\")\n )\n return invalid(\"invalid version date\");\n return value;\n};\n\nexport const validateRange = (range: StatewireProtocol.Range) => {\n const version = validateVersion(range.version);\n const minVersion =\n range.minVersion === undefined\n ? version\n : validateVersion(range.minVersion);\n if (minVersion > version) invalid(\"min-version exceeds version\");\n return { version, minVersion };\n};\n\nexport const inRange = (value: string, range: StatewireProtocol.Range) => {\n const checked = validateRange(range);\n return value >= checked.minVersion && value <= checked.version;\n};\n\nexport const protocolOffers = (options: StatewireProtocol.Options) =>\n options.applicationProtocols ?? [\n {\n name: options.protocol ?? DEFAULT_PROTOCOL,\n version: DEFAULT_PROTOCOL_VERSION,\n },\n ];\n\nexport const negotiationHeaders = (\n options: StatewireProtocol.Options,\n): Record<string, string> => {\n const suffix = (range: StatewireProtocol.Range) => {\n const { version, minVersion } = validateRange(range);\n return `\"${version}\"${minVersion === version ? \"\" : `; min-version=\"${minVersion}\"`}`;\n };\n const offers = protocolOffers(options);\n const seen = new Set<string>();\n if (offers !== \"*\" && !offers.length)\n invalid(\"protocol list must not be empty\");\n return {\n [VERSION_HEADER]: suffix(options.wireVersion ?? { version: WIRE_VERSION }),\n [PROTOCOL_HEADER]:\n offers === \"*\"\n ? \"*\"\n : offers\n .map((offer) => {\n if (\n !protocolToken.test(offer.name) ||\n offer.name === \"*\" ||\n seen.has(offer.name)\n )\n invalid(\"invalid or duplicate protocol name\");\n if (\n offer.optional !== undefined &&\n typeof offer.optional !== \"boolean\"\n )\n invalid(\"optional must be boolean\");\n seen.add(offer.name);\n return `${offer.name}; version=${suffix(offer)}${offer.optional ? \"; optional\" : \"\"}`;\n })\n .join(\", \"),\n };\n};\n\nconst parseItem = (input: string) => {\n const atom = String.raw`\"(?:[\\x20-\\x21\\x23-\\x5b\\x5d-\\x7e]|\\\\[\"\\\\])*\"|[A-Za-z*][A-Za-z0-9!#$%&'*+.^_\\x60|~:/-]*|\\?[01]`;\n const text = input.trim();\n const match = new RegExp(`^(?:${atom})`).exec(text);\n if (!match) return invalid(\"invalid structured item\");\n const quoted = match[0].startsWith('\"');\n const decode = (raw: string) => raw.slice(1, -1).replace(/\\\\([\"\\\\])/g, \"$1\");\n const value = quoted ? decode(match[0]) : match[0];\n const params = new Map<string, string | boolean>();\n let rest = text.slice(match[0].length);\n while (rest) {\n const parameter = new RegExp(\n `^; *([a-z*][a-z0-9_.*-]*)(?:=(${atom}))?`,\n ).exec(rest);\n if (!parameter) return invalid(\"invalid structured parameters\");\n const key = parameter[1]!;\n const raw = parameter[2];\n if (params.has(key)) invalid(\"duplicate parameter\");\n if (raw === undefined || raw === \"?1\") params.set(key, true);\n else if (raw === \"?0\") params.set(key, false);\n else if (raw.startsWith('\"')) params.set(key, decode(raw));\n else invalid(\"parameter must be string or boolean\");\n rest = rest.slice(parameter[0].length);\n }\n return { value, quoted, params };\n};\n\nexport const parseNegotiation = (\n headers: Headers,\n): Required<\n Pick<StatewireProtocol.Options, \"wireVersion\" | \"applicationProtocols\">\n> => {\n const wire = headers.get(VERSION_HEADER);\n const application = headers.get(PROTOCOL_HEADER);\n if (wire === null || application === null)\n return invalid(\"negotiation fields are required\");\n const item = parseItem(wire);\n if (!item.quoted || [...item.params.keys()].some((k) => k !== \"min-version\"))\n invalid(\"invalid Statewire-Version\");\n const minVersion = item.params.get(\"min-version\");\n if (minVersion !== undefined && typeof minVersion !== \"string\")\n return invalid(\"min-version must be a string\");\n const wireVersion = validateRange({\n version: item.value,\n ...(minVersion === undefined ? {} : { minVersion }),\n });\n if (application.trim() === \"*\")\n return { wireVersion, applicationProtocols: \"*\" };\n const names = new Set<string>();\n const applicationProtocols = application\n .split(\",\")\n .map((text): StatewireProtocol.Offer => {\n const { value: name, quoted, params } = parseItem(text);\n if (\n quoted ||\n !protocolToken.test(name) ||\n name === \"*\" ||\n names.has(name)\n )\n invalid(\"invalid or duplicate protocol name\");\n names.add(name);\n if (\n [...params.keys()].some(\n (k) => ![\"version\", \"min-version\", \"optional\"].includes(k),\n )\n )\n invalid(\"unsupported parameter\");\n const version = params.get(\"version\");\n const minVersion = params.get(\"min-version\");\n const optional = params.get(\"optional\") ?? false;\n if (\n typeof version !== \"string\" ||\n (minVersion !== undefined && typeof minVersion !== \"string\") ||\n typeof optional !== \"boolean\"\n )\n return invalid(\"invalid protocol parameters\");\n return {\n name,\n ...validateRange({\n version,\n ...(minVersion === undefined ? {} : { minVersion }),\n }),\n optional,\n };\n });\n return { wireVersion, applicationProtocols };\n};\n\nexport const validateSelection = (\n value: unknown,\n options: StatewireProtocol.Options,\n): StatewireProtocol.Selection => {\n if (typeof value !== \"object\" || value === null)\n return invalid(\"missing negotiation selection\");\n const syn = value as Record<string, unknown>;\n const version = validateVersion(syn.version);\n if (!inRange(version, options.wireVersion ?? { version: WIRE_VERSION }))\n invalid(\"selected wire version is outside offer\");\n if (!Array.isArray(syn.protocols))\n return invalid(\"syn.protocols must be an array\");\n const offers = protocolOffers(options);\n const seen = new Map<string, string>();\n const protocols = syn.protocols.map((entry: unknown) => {\n if (typeof entry !== \"object\" || entry === null)\n return invalid(\"invalid selected protocol\");\n const item = entry as Record<string, unknown>;\n const name = item.name;\n if (\n typeof name !== \"string\" ||\n !protocolToken.test(name) ||\n name === \"*\" ||\n seen.has(name)\n )\n return invalid(\"invalid selected protocol name\");\n const version = validateVersion(item.version);\n if (item.record !== undefined && item.record !== \"ephemeral\")\n invalid(\"invalid selected protocol record\");\n const record = item.record as \"ephemeral\" | undefined;\n const parent = name.slice(0, name.lastIndexOf(\"/\"));\n const child = parent !== \"\" && seen.has(parent);\n if (child) {\n if (seen.get(parent) !== version)\n invalid(\"subprotocol version differs from its parent\");\n } else if (offers !== \"*\") {\n const offer = offers.find((o) => o.name === name);\n if (!offer || !inRange(version, offer))\n invalid(\"selected protocol is outside offer\");\n }\n seen.set(name, version);\n return { name, version, ...(record !== undefined && { record }) };\n });\n if (offers !== \"*\" && offers.some((o) => !o.optional && !seen.has(o.name)))\n invalid(\"required protocol missing from selection\");\n return { version, protocols };\n};\n\nexport const negotiateProtocols = (\n headers: Headers,\n wire: StatewireProtocol.Range,\n definitions: readonly StatewireProtocol.Definition[],\n):\n | StatewireProtocol.Selection\n | {\n fin: {\n reason: \"protocol-error\";\n code: string;\n status: number;\n message: string;\n payload?: unknown;\n };\n } => {\n const supported = {\n ...validateRange(wire),\n protocols: definitions.map((d) => ({ name: d.name, ...validateRange(d) })),\n };\n const failure = (code: string, message: string) => ({\n fin: {\n reason: \"protocol-error\" as const,\n code,\n message,\n status: code === \"invalid-negotiation\" ? 400 : 406,\n ...(code === \"invalid-negotiation\" ? {} : { payload: supported }),\n },\n });\n let request: ReturnType<typeof parseNegotiation>;\n try {\n request = parseNegotiation(headers);\n } catch (error) {\n return failure(\n \"invalid-negotiation\",\n error instanceof Error ? error.message : \"invalid negotiation\",\n );\n }\n const version = [wire.version, request.wireVersion.version].sort()[0]!;\n if (!inRange(version, wire) || !inRange(version, request.wireVersion))\n return failure(\"unsupported-version\", \"Statewire versions do not overlap\");\n const offers =\n request.applicationProtocols === \"*\"\n ? definitions.map((d) => ({\n name: d.name,\n version: d.version,\n optional: false,\n }))\n : request.applicationProtocols;\n const registry = new Map(definitions.map((d) => [d.name, d]));\n if (registry.size !== definitions.length)\n throw new Error(\"statewire: duplicate registered protocol\");\n for (const definition of definitions) {\n const children = new Set<string>();\n for (const child of definition.subprotocols ?? []) {\n if (\n !protocolToken.test(child.name) ||\n child.name.includes(\"/\") ||\n children.has(child.name) ||\n (child.record !== undefined && child.record !== \"ephemeral\")\n )\n throw new Error(\"statewire: invalid subprotocol registration\");\n children.add(child.name);\n }\n }\n const offered = new Map(offers.map((o) => [o.name, o]));\n const solve = (names: Set<string>) => {\n const active = new Set(names);\n for (const name of active) {\n const definition = registry.get(name);\n if (!definition || !offered.has(name)) return undefined;\n for (const dependency of Object.keys(definition.requires ?? {}))\n active.add(dependency);\n }\n const result = new Map<string, string>();\n for (const name of active) {\n const ranges = [\n registry.get(name)!,\n offered.get(name)!,\n ...[...active].flatMap((parent) => {\n const dependency = registry.get(parent)!.requires?.[name];\n return dependency ? [dependency] : [];\n }),\n ].map(validateRange);\n const lower = ranges\n .map((r) => r.minVersion)\n .sort()\n .at(-1)!;\n const upper = ranges.map((r) => r.version).sort()[0]!;\n if (lower > upper) return undefined;\n result.set(name, upper);\n }\n return result;\n };\n let selected = solve(\n new Set(offers.filter((o) => !o.optional).map((o) => o.name)),\n );\n if (!selected)\n return failure(\n \"unsupported-protocol\",\n \"required protocol combination is unsupported\",\n );\n for (const offer of offers) {\n if (offer.optional)\n selected = solve(new Set([...selected.keys(), offer.name])) ?? selected;\n }\n return {\n version,\n protocols: offers.flatMap((o) => {\n const version = selected!.get(o.name);\n if (version === undefined) return [];\n return [\n { name: o.name, version },\n ...(registry.get(o.name)!.subprotocols ?? []).map((child) => ({\n name: `${o.name}/${child.name}`,\n version,\n ...(child.record !== undefined && { record: child.record }),\n })),\n ];\n }),\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"protocol.js","names":["StatewireProtocol","Range","version","minVersion","Offer","name","optional","Selection","protocols","record","Options","wireVersion","applicationProtocols","protocol","keyPrefixes","Readonly","Record","Definition","requires","subprotocols","WIRE_VERSION","GAP_FILL_VERSION","FENCE_VERSION","CLIENT_WIRE","ATTACHER_HEADER","MIN_SERVED_WIRE_VERSION","DEFAULT_PROTOCOL_VERSION","DEFAULT_PROTOCOL","PROTOCOL_HEADER","VERSION_HEADER","protocolToken","invalid","message","Error","validateVersion","value","test","parsed","Date","Number","isFinite","getTime","toISOString","slice","startsWith","validateRange","range","undefined","inRange","checked","protocolOffers","options","negotiationHeaders","suffix","offers","seen","Set","length","map","offer","has","add","join","parseItem","input","atom","String","raw","text","trim","match","RegExp","exec","quoted","decode","replace","params","Map","rest","parameter","key","set","parseNegotiation","headers","Headers","Required","Pick","wire","get","application","item","keys","some","k","names","split","includes","validateSelection","syn","Array","isArray","entry","parent","lastIndexOf","child","find","o","negotiateProtocols","definitions","fin","reason","code","status","payload","supported","d","failure","const","request","ReturnType","error","sort","registry","size","definition","children","offered","solve","active","dependency","Object","result","ranges","flatMap","lower","r","at","upper","selected","filter"],"sources":["../../src/wire/protocol.ts"],"sourcesContent":["export namespace StatewireProtocol {\n export type Range = { version: string; minVersion?: string };\n export type Offer = Range & { name: string; optional?: boolean };\n export type Selection = {\n version: string;\n protocols: { name: string; version: string; record?: \"ephemeral\" }[];\n };\n export type Options = {\n wireVersion?: Range;\n applicationProtocols?: readonly Offer[] | \"*\";\n protocol?: string;\n keyPrefixes?: Readonly<Record<string, readonly string[]>>;\n };\n export type Definition = Range & {\n name: string;\n requires?: Readonly<Record<string, Range>>;\n subprotocols?: readonly { name: string; record?: \"ephemeral\" }[];\n };\n}\n\nexport const WIRE_VERSION = \"2026-11-02\";\n/** Attach carries a results cursor and gets its verdicts gap-filled; a re-sent seq at or below the watermark is a protocol error. */\nexport const GAP_FILL_VERSION = \"2026-11-01\";\n/** Every attach of a connection names its attacher; a host retires the attacher's earlier attaches before the hello. */\nexport const FENCE_VERSION = \"2026-11-02\";\n/** The wire a client offers by default: the gap-fill contract and newer. */\nexport const CLIENT_WIRE: StatewireProtocol.Range = {\n version: WIRE_VERSION,\n minVersion: GAP_FILL_VERSION,\n};\nexport const ATTACHER_HEADER = \"Statewire-Attacher\";\n/** The oldest wire contract a host serves by default (re-sent seqs re-emit their verdicts). */\nexport const MIN_SERVED_WIRE_VERSION = \"2026-09-30\";\nexport const DEFAULT_PROTOCOL_VERSION = \"2026-09-30\";\nexport const DEFAULT_PROTOCOL = \"default\";\nexport const PROTOCOL_HEADER = \"Statewire-Protocol\";\nexport const VERSION_HEADER = \"Statewire-Version\";\nexport const protocolToken = /^[A-Za-z*][A-Za-z0-9!#$%&'*+.^_`|~:/-]*$/;\n\nconst invalid = (message: string): never => {\n throw new Error(`statewire: protocol error: ${message}`);\n};\n\nexport const validateVersion = (value: unknown): string => {\n if (typeof value !== \"string\" || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value))\n return invalid(\"version must be a YYYY-MM-DD date\");\n const parsed = new Date(`${value}T00:00:00.000Z`);\n if (\n !Number.isFinite(parsed.getTime()) ||\n parsed.toISOString().slice(0, 10) !== value ||\n value.startsWith(\"0000\")\n )\n return invalid(\"invalid version date\");\n return value;\n};\n\nexport const validateRange = (range: StatewireProtocol.Range) => {\n const version = validateVersion(range.version);\n const minVersion =\n range.minVersion === undefined\n ? version\n : validateVersion(range.minVersion);\n if (minVersion > version) invalid(\"min-version exceeds version\");\n return { version, minVersion };\n};\n\nexport const inRange = (value: string, range: StatewireProtocol.Range) => {\n const checked = validateRange(range);\n return value >= checked.minVersion && value <= checked.version;\n};\n\nexport const protocolOffers = (options: StatewireProtocol.Options) =>\n options.applicationProtocols ?? [\n {\n name: options.protocol ?? DEFAULT_PROTOCOL,\n version: DEFAULT_PROTOCOL_VERSION,\n },\n ];\n\nexport const negotiationHeaders = (\n options: StatewireProtocol.Options,\n): Record<string, string> => {\n const suffix = (range: StatewireProtocol.Range) => {\n const { version, minVersion } = validateRange(range);\n return `\"${version}\"${minVersion === version ? \"\" : `; min-version=\"${minVersion}\"`}`;\n };\n const offers = protocolOffers(options);\n const seen = new Set<string>();\n if (offers !== \"*\" && !offers.length)\n invalid(\"protocol list must not be empty\");\n return {\n [VERSION_HEADER]: suffix(options.wireVersion ?? CLIENT_WIRE),\n [PROTOCOL_HEADER]:\n offers === \"*\"\n ? \"*\"\n : offers\n .map((offer) => {\n if (\n !protocolToken.test(offer.name) ||\n offer.name === \"*\" ||\n seen.has(offer.name)\n )\n invalid(\"invalid or duplicate protocol name\");\n if (\n offer.optional !== undefined &&\n typeof offer.optional !== \"boolean\"\n )\n invalid(\"optional must be boolean\");\n seen.add(offer.name);\n return `${offer.name}; version=${suffix(offer)}${offer.optional ? \"; optional\" : \"\"}`;\n })\n .join(\", \"),\n };\n};\n\nconst parseItem = (input: string) => {\n const atom = String.raw`\"(?:[\\x20-\\x21\\x23-\\x5b\\x5d-\\x7e]|\\\\[\"\\\\])*\"|[A-Za-z*][A-Za-z0-9!#$%&'*+.^_\\x60|~:/-]*|\\?[01]`;\n const text = input.trim();\n const match = new RegExp(`^(?:${atom})`).exec(text);\n if (!match) return invalid(\"invalid structured item\");\n const quoted = match[0].startsWith('\"');\n const decode = (raw: string) => raw.slice(1, -1).replace(/\\\\([\"\\\\])/g, \"$1\");\n const value = quoted ? decode(match[0]) : match[0];\n const params = new Map<string, string | boolean>();\n let rest = text.slice(match[0].length);\n while (rest) {\n const parameter = new RegExp(\n `^; *([a-z*][a-z0-9_.*-]*)(?:=(${atom}))?`,\n ).exec(rest);\n if (!parameter) return invalid(\"invalid structured parameters\");\n const key = parameter[1]!;\n const raw = parameter[2];\n if (params.has(key)) invalid(\"duplicate parameter\");\n if (raw === undefined || raw === \"?1\") params.set(key, true);\n else if (raw === \"?0\") params.set(key, false);\n else if (raw.startsWith('\"')) params.set(key, decode(raw));\n else invalid(\"parameter must be string or boolean\");\n rest = rest.slice(parameter[0].length);\n }\n return { value, quoted, params };\n};\n\nexport const parseNegotiation = (\n headers: Headers,\n): Required<\n Pick<StatewireProtocol.Options, \"wireVersion\" | \"applicationProtocols\">\n> => {\n const wire = headers.get(VERSION_HEADER);\n const application = headers.get(PROTOCOL_HEADER);\n if (wire === null || application === null)\n return invalid(\"negotiation fields are required\");\n const item = parseItem(wire);\n if (!item.quoted || [...item.params.keys()].some((k) => k !== \"min-version\"))\n invalid(\"invalid Statewire-Version\");\n const minVersion = item.params.get(\"min-version\");\n if (minVersion !== undefined && typeof minVersion !== \"string\")\n return invalid(\"min-version must be a string\");\n const wireVersion = validateRange({\n version: item.value,\n ...(minVersion === undefined ? {} : { minVersion }),\n });\n if (application.trim() === \"*\")\n return { wireVersion, applicationProtocols: \"*\" };\n const names = new Set<string>();\n const applicationProtocols = application\n .split(\",\")\n .map((text): StatewireProtocol.Offer => {\n const { value: name, quoted, params } = parseItem(text);\n if (\n quoted ||\n !protocolToken.test(name) ||\n name === \"*\" ||\n names.has(name)\n )\n invalid(\"invalid or duplicate protocol name\");\n names.add(name);\n if (\n [...params.keys()].some(\n (k) => ![\"version\", \"min-version\", \"optional\"].includes(k),\n )\n )\n invalid(\"unsupported parameter\");\n const version = params.get(\"version\");\n const minVersion = params.get(\"min-version\");\n const optional = params.get(\"optional\") ?? false;\n if (\n typeof version !== \"string\" ||\n (minVersion !== undefined && typeof minVersion !== \"string\") ||\n typeof optional !== \"boolean\"\n )\n return invalid(\"invalid protocol parameters\");\n return {\n name,\n ...validateRange({\n version,\n ...(minVersion === undefined ? {} : { minVersion }),\n }),\n optional,\n };\n });\n return { wireVersion, applicationProtocols };\n};\n\nexport const validateSelection = (\n value: unknown,\n options: StatewireProtocol.Options,\n): StatewireProtocol.Selection => {\n if (typeof value !== \"object\" || value === null)\n return invalid(\"missing negotiation selection\");\n const syn = value as Record<string, unknown>;\n const version = validateVersion(syn.version);\n if (!inRange(version, options.wireVersion ?? CLIENT_WIRE))\n invalid(\"selected wire version is outside offer\");\n if (!Array.isArray(syn.protocols))\n return invalid(\"syn.protocols must be an array\");\n const offers = protocolOffers(options);\n const seen = new Map<string, string>();\n const protocols = syn.protocols.map((entry: unknown) => {\n if (typeof entry !== \"object\" || entry === null)\n return invalid(\"invalid selected protocol\");\n const item = entry as Record<string, unknown>;\n const name = item.name;\n if (\n typeof name !== \"string\" ||\n !protocolToken.test(name) ||\n name === \"*\" ||\n seen.has(name)\n )\n return invalid(\"invalid selected protocol name\");\n const version = validateVersion(item.version);\n if (item.record !== undefined && item.record !== \"ephemeral\")\n invalid(\"invalid selected protocol record\");\n const record = item.record as \"ephemeral\" | undefined;\n const parent = name.slice(0, name.lastIndexOf(\"/\"));\n const child = parent !== \"\" && seen.has(parent);\n if (child) {\n if (seen.get(parent) !== version)\n invalid(\"subprotocol version differs from its parent\");\n } else if (offers !== \"*\") {\n const offer = offers.find((o) => o.name === name);\n if (!offer || !inRange(version, offer))\n invalid(\"selected protocol is outside offer\");\n }\n seen.set(name, version);\n return { name, version, ...(record !== undefined && { record }) };\n });\n if (offers !== \"*\" && offers.some((o) => !o.optional && !seen.has(o.name)))\n invalid(\"required protocol missing from selection\");\n return { version, protocols };\n};\n\nexport const negotiateProtocols = (\n headers: Headers,\n wire: StatewireProtocol.Range,\n definitions: readonly StatewireProtocol.Definition[],\n):\n | StatewireProtocol.Selection\n | {\n fin: {\n reason: \"protocol-error\";\n code: string;\n status: number;\n message: string;\n payload?: unknown;\n };\n } => {\n const supported = {\n ...validateRange(wire),\n protocols: definitions.map((d) => ({ name: d.name, ...validateRange(d) })),\n };\n const failure = (code: string, message: string) => ({\n fin: {\n reason: \"protocol-error\" as const,\n code,\n message,\n status: code === \"invalid-negotiation\" ? 400 : 406,\n ...(code === \"invalid-negotiation\" ? {} : { payload: supported }),\n },\n });\n let request: ReturnType<typeof parseNegotiation>;\n try {\n request = parseNegotiation(headers);\n } catch (error) {\n return failure(\n \"invalid-negotiation\",\n error instanceof Error ? error.message : \"invalid negotiation\",\n );\n }\n const version = [wire.version, request.wireVersion.version].sort()[0]!;\n if (!inRange(version, wire) || !inRange(version, request.wireVersion))\n return failure(\"unsupported-version\", \"Statewire versions do not overlap\");\n const offers =\n request.applicationProtocols === \"*\"\n ? definitions.map((d) => ({\n name: d.name,\n version: d.version,\n optional: false,\n }))\n : request.applicationProtocols;\n const registry = new Map(definitions.map((d) => [d.name, d]));\n if (registry.size !== definitions.length)\n throw new Error(\"statewire: duplicate registered protocol\");\n for (const definition of definitions) {\n const children = new Set<string>();\n for (const child of definition.subprotocols ?? []) {\n if (\n !protocolToken.test(child.name) ||\n child.name.includes(\"/\") ||\n children.has(child.name) ||\n (child.record !== undefined && child.record !== \"ephemeral\")\n )\n throw new Error(\"statewire: invalid subprotocol registration\");\n children.add(child.name);\n }\n }\n const offered = new Map(offers.map((o) => [o.name, o]));\n const solve = (names: Set<string>) => {\n const active = new Set(names);\n for (const name of active) {\n const definition = registry.get(name);\n if (!definition || !offered.has(name)) return undefined;\n for (const dependency of Object.keys(definition.requires ?? {}))\n active.add(dependency);\n }\n const result = new Map<string, string>();\n for (const name of active) {\n const ranges = [\n registry.get(name)!,\n offered.get(name)!,\n ...[...active].flatMap((parent) => {\n const dependency = registry.get(parent)!.requires?.[name];\n return dependency ? [dependency] : [];\n }),\n ].map(validateRange);\n const lower = ranges\n .map((r) => r.minVersion)\n .sort()\n .at(-1)!;\n const upper = ranges.map((r) => r.version).sort()[0]!;\n if (lower > upper) return undefined;\n result.set(name, upper);\n }\n return result;\n };\n let selected = solve(\n new Set(offers.filter((o) => !o.optional).map((o) => o.name)),\n );\n if (!selected)\n return failure(\n \"unsupported-protocol\",\n \"required protocol combination is unsupported\",\n );\n for (const offer of offers) {\n if (offer.optional)\n selected = solve(new Set([...selected.keys(), offer.name])) ?? selected;\n }\n return {\n version,\n protocols: offers.flatMap((o) => {\n const version = selected!.get(o.name);\n if (version === undefined) return [];\n return [\n { name: o.name, version },\n ...(registry.get(o.name)!.subprotocols ?? []).map((child) => ({\n name: `${o.name}/${child.name}`,\n version,\n ...(child.record !== undefined && { record: child.record }),\n })),\n ];\n }),\n };\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/client/connection.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ATTACHER_HEADER,
|
|
2
3
|
negotiationHeaders,
|
|
3
4
|
validateSelection,
|
|
4
5
|
parseNegotiation,
|
|
@@ -9,6 +10,7 @@ import { flushTapSync } from "@assistant-ui/tap";
|
|
|
9
10
|
import { reviveOps, reviveValue } from "../wire/meta";
|
|
10
11
|
import { backoff, retryHint, timing } from "./timing";
|
|
11
12
|
import { isStorageError } from "./storageError";
|
|
13
|
+
import { randomId } from "../util/randomId";
|
|
12
14
|
import type {
|
|
13
15
|
ConnectionState,
|
|
14
16
|
RemoteLink,
|
|
@@ -111,6 +113,8 @@ export type Conn = {
|
|
|
111
113
|
connection: StatewireClient.Connection;
|
|
112
114
|
parked: boolean;
|
|
113
115
|
lease: string | null;
|
|
116
|
+
/** Names every attach of this connection, so a host retires the earlier ones (2026-11-02). */
|
|
117
|
+
attacher: string;
|
|
114
118
|
attempt: number;
|
|
115
119
|
authDenials: number;
|
|
116
120
|
authStale: boolean;
|
|
@@ -642,6 +646,11 @@ export const resolveHeaders = async (
|
|
|
642
646
|
);
|
|
643
647
|
|
|
644
648
|
// The stale flag clears only once the resolver returns: a throwing refresh keeps it for the next attempt.
|
|
649
|
+
/** Names this connection, so a host retires its earlier attaches before the hello. */
|
|
650
|
+
export const replacing = (c: Conn, headers: Headers) => {
|
|
651
|
+
headers.set(ATTACHER_HEADER, c.attacher);
|
|
652
|
+
};
|
|
653
|
+
|
|
645
654
|
export const attachFrame = async (
|
|
646
655
|
c: Conn,
|
|
647
656
|
headers: StatewireClient.HeadersOption | undefined,
|
|
@@ -654,6 +663,7 @@ export const attachFrame = async (
|
|
|
654
663
|
)) {
|
|
655
664
|
if (!resolved.has(name)) resolved.set(name, value);
|
|
656
665
|
}
|
|
666
|
+
replacing(c, resolved);
|
|
657
667
|
c.negotiation = parseNegotiation(resolved);
|
|
658
668
|
c.authStale = false;
|
|
659
669
|
const persistence = c.ctx.beforeAttach?.();
|
|
@@ -686,6 +696,7 @@ export const useLink = (
|
|
|
686
696
|
const conn: Conn = {
|
|
687
697
|
parked: props.isNew ?? false,
|
|
688
698
|
lease: null,
|
|
699
|
+
attacher: randomId(),
|
|
689
700
|
attempt: 0,
|
|
690
701
|
authDenials: 0,
|
|
691
702
|
authStale: false,
|