statewire 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -80
- package/dist/client/connection.d.ts +19 -6
- package/dist/client/connection.d.ts.map +1 -1
- package/dist/client/connection.js +79 -40
- package/dist/client/connection.js.map +1 -1
- package/dist/client/core.d.ts +1 -0
- package/dist/client/core.d.ts.map +1 -1
- package/dist/client/core.js +5 -0
- package/dist/client/core.js.map +1 -1
- package/dist/client/session.d.ts +2 -0
- package/dist/client/session.d.ts.map +1 -1
- package/dist/client/session.js +98 -19
- package/dist/client/session.js.map +1 -1
- package/dist/host/adapter.d.ts +1 -1
- package/dist/host/adapter.d.ts.map +1 -1
- package/dist/host/adapter.js +7 -1
- package/dist/host/adapter.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 +45 -5
- package/dist/host/host.js.map +1 -1
- package/dist/host/http.d.ts +1 -1
- package/dist/host/http.d.ts.map +1 -1
- package/dist/host/http.js +75 -47
- package/dist/host/http.js.map +1 -1
- package/dist/host/socket.d.ts +23 -7
- package/dist/host/socket.d.ts.map +1 -1
- package/dist/host/socket.js +275 -74
- package/dist/host/socket.js.map +1 -1
- package/dist/host/work.d.ts +7 -0
- package/dist/host/work.d.ts.map +1 -0
- package/dist/host/work.js +53 -0
- package/dist/host/work.js.map +1 -0
- package/dist/host-internal.d.ts +35 -5
- package/dist/host-internal.d.ts.map +1 -1
- package/dist/host-internal.js +2 -1
- package/dist/host.d.ts +16 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +2 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/statewire.d.ts +13 -4
- package/dist/statewire.d.ts.map +1 -1
- package/dist/statewire.js.map +1 -1
- package/dist/transports/sse.d.ts +2 -5
- package/dist/transports/sse.d.ts.map +1 -1
- package/dist/transports/sse.js +50 -59
- package/dist/transports/sse.js.map +1 -1
- package/dist/transports/testing.js +4 -4
- package/dist/transports/testing.js.map +1 -1
- package/dist/transports/ws.d.ts +3 -3
- package/dist/transports/ws.d.ts.map +1 -1
- package/dist/transports/ws.js +57 -44
- package/dist/transports/ws.js.map +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/util/randomId.js +1 -1
- package/dist/util/randomId.js.map +1 -1
- package/dist/wire/documents.d.ts +20 -0
- package/dist/wire/documents.d.ts.map +1 -0
- package/dist/wire/documents.js +74 -0
- package/dist/wire/documents.js.map +1 -0
- package/dist/wire/limits.d.ts +10 -0
- package/dist/wire/limits.d.ts.map +1 -0
- package/dist/wire/limits.js +11 -0
- package/dist/wire/limits.js.map +1 -0
- package/dist/wire/meta.d.ts.map +1 -1
- package/dist/wire/meta.js +1 -1
- package/dist/wire/meta.js.map +1 -1
- package/dist/wire/ops.d.ts.map +1 -1
- package/dist/wire/ops.js +1 -2
- package/dist/wire/ops.js.map +1 -1
- package/dist/wire/version.d.ts +7 -0
- package/dist/wire/version.d.ts.map +1 -0
- package/dist/wire/version.js +8 -0
- package/dist/wire/version.js.map +1 -0
- package/package.json +1 -1
- package/src/client/connection.ts +159 -52
- package/src/client/core.ts +6 -0
- package/src/client/session.ts +105 -32
- package/src/host/adapter.ts +10 -2
- package/src/host/host.ts +54 -4
- package/src/host/http.ts +132 -66
- package/src/host/socket.ts +410 -81
- package/src/host/work.ts +50 -0
- package/src/host-internal.ts +32 -4
- package/src/host.ts +18 -2
- package/src/index.ts +2 -2
- package/src/statewire.ts +18 -4
- package/src/transports/sse.ts +70 -78
- package/src/transports/testing.ts +4 -4
- package/src/transports/ws.ts +36 -55
- package/src/types.ts +1 -0
- package/src/util/randomId.ts +3 -3
- package/src/wire/documents.ts +109 -0
- package/src/wire/limits.ts +6 -0
- package/src/wire/meta.ts +6 -1
- package/src/wire/ops.ts +1 -2
- package/src/wire/version.ts +3 -0
package/dist/client/core.js
CHANGED
|
@@ -127,6 +127,10 @@ const flush = (c, scheduled = false) => {
|
|
|
127
127
|
const connectionChanged = connection !== c.notifiedConnection;
|
|
128
128
|
c.notifiedConnection = connection;
|
|
129
129
|
if (connectionChanged) options.onConnectionChange?.(connection);
|
|
130
|
+
if (connection.error !== c.notifiedError) {
|
|
131
|
+
c.notifiedError = connection.error;
|
|
132
|
+
if (connection.error) options.onError?.(connection.error);
|
|
133
|
+
}
|
|
130
134
|
const busy = c.getBusy();
|
|
131
135
|
const busyChanged = busy !== c.notifiedBusy;
|
|
132
136
|
c.notifiedBusy = busy;
|
|
@@ -201,6 +205,7 @@ const useStatewireCore = (getOptions, value) => {
|
|
|
201
205
|
notifiedPublished: void 0,
|
|
202
206
|
notifiedOverlayPaths: [],
|
|
203
207
|
notifiedConnection: null,
|
|
208
|
+
notifiedError: void 0,
|
|
204
209
|
notifiedBusy: true,
|
|
205
210
|
notifiedFailed: NO_FAILED,
|
|
206
211
|
stale: false,
|
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","notifiedBusy","notifiedFailed","stale","everAttached","overlaysDirty","flushing","scheduled","listeners","Set","post","commandsListener","getState","getBusy","getFailed","commands","CommandsProxy","subscribe","listener","schedule","c","markStale","drainCanonical","push","takeChanged","snapshot","undefined","next","initialState","state","dropCovered","failureCovered","failures","entry","list","discard","recompute","prevCanonical","optimistic","materialize","paths","overlay","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","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 notifiedBusy: boolean;\n notifiedFailed: readonly StatewireClient.FailedCommand[];\n stale: boolean;\n everAttached: boolean;\n overlaysDirty: boolean;\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 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.stale || !c.value) 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) return;\n c.overlaysDirty = false;\n const { optimistic, materialize } = c.getOptions();\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 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 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 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 notifiedBusy: true,\n notifiedFailed: NO_FAILED,\n stale: false,\n everAttached: false,\n overlaysDirty: false,\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 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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"}
|
|
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","flushing","scheduled","listeners","Set","post","commandsListener","getState","getBusy","getFailed","commands","CommandsProxy","subscribe","listener","schedule","c","markStale","drainCanonical","push","takeChanged","snapshot","undefined","next","initialState","state","dropCovered","failureCovered","failures","entry","list","discard","recompute","prevCanonical","optimistic","materialize","paths","overlay","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 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 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.stale || !c.value) 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) return;\n c.overlaysDirty = false;\n const { optimistic, materialize } = c.getOptions();\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 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 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 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 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/session.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { RemoteLink, StatewireRemoteProps } from "../transports/sse.js";
|
|
|
3
3
|
import { StatewireClient } from "../statewire.js";
|
|
4
4
|
import { Statewire, StatewireSendError } from "../types.js";
|
|
5
5
|
import { StatewirePath } from "../wire/ops.js";
|
|
6
|
+
import { StatewireDocuments } from "../wire/documents.js";
|
|
6
7
|
//#region src/client/session.d.ts
|
|
7
8
|
type WireCommand = {
|
|
8
9
|
method: string;
|
|
@@ -60,6 +61,7 @@ type Session = {
|
|
|
60
61
|
frameFailures: number;
|
|
61
62
|
pending: Pending[];
|
|
62
63
|
canonical: unknown;
|
|
64
|
+
documents: StatewireDocuments.State;
|
|
63
65
|
lastPublished: unknown;
|
|
64
66
|
changed: StatewirePath[];
|
|
65
67
|
source: Statewire.StateSource;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"session.d.ts","names":[],"sources":["../../src/client/session.ts"],"mappings":";;;;;;;KAgCK;EACH;EACA;EACA;;KAGG;WACM;WACA,SAAS;WACT,KAAK;;EAEd;;EAEA;;EAEA;EACA,UAAU;EACV,SAAS,OAAO;;KAGb;WACM;WACA;EACT;;KAeG;KAEO;EACV,eAAe,gBAAgB;EAC/B,gBAAgB,gBAAgB;EAChC;;KAGG;EACH,KAAK;EACL,QAAQ,gBAAgB;EACxB;;KAGG;EACH,QAAQ,gBAAgB;EACxB,KAAK;EACL;EACA,OAAO,gBAAgB;EACvB,QAAQ;EACR;;EAEA;EACA;EACA;EACA;EACA;EACA,eAAe,gBAAgB;EAC/B;EACA;EACA,YAAY;EACZ;EACA,0BAA0B,qBAAqB;EAC/C;EACA,SAAS;EACT;EACA,WAAW,mBAAmB;EAC9B;EACA,SAAS;EACT,QAAQ,UAAU;EAClB,QAAQ;EACR;EACA;EACA;EACA,WAAW;EACX;EACA,WAAW;EACX;EACA,UAAU,mBAAmB,sBAAsB;;cAwHxC,iBACX,GAAG,qBACO,gBAAgB;cAklBtB,eAAgB,GAAG,SAAS,WAAW;cAkJhC,gBACX,GAAG,SACH,OAAO,gBAAgB;cAYZ,cACX,GAAG,SACH,OAAO,gBAAgB,kBACtB;cA0DG,aAAc,GAAG,SAAS,OAAO;cAmC1B,sBACX,SAAS,4BACR"}
|
package/dist/client/session.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { applyOps } from "../wire/ops.js";
|
|
2
1
|
import { createMethodProxy } from "../util/methodProxy.js";
|
|
3
2
|
import { StatewireSendError } from "../types.js";
|
|
4
3
|
import { bindCommandsHost } from "../host/host.js";
|
|
5
4
|
import { encodeParams, encodeValue, reviveResponse, reviveValue } from "../wire/meta.js";
|
|
5
|
+
import "../wire/limits.js";
|
|
6
6
|
import { SessionStorageContext, createMemorySessionStore } from "./sessionStore.js";
|
|
7
7
|
import { backoff } from "./timing.js";
|
|
8
8
|
import { TERMINAL } from "./connection.js";
|
|
9
|
+
import { applyDocumentOps } from "../wire/documents.js";
|
|
9
10
|
import { randomId } from "../util/randomId.js";
|
|
10
11
|
import { useContext, useEffect, useState } from "@assistant-ui/tap/react-shim";
|
|
11
12
|
//#region src/client/session.ts
|
|
12
13
|
const protocolError = (message) => {
|
|
13
14
|
throw new Error(`statewire: protocol error: ${message}`);
|
|
14
15
|
};
|
|
15
|
-
const newClientId = () => `c-${randomId()}`;
|
|
16
16
|
const rejectedSend = (failure) => {
|
|
17
17
|
const result = Promise.reject(new StatewireSendError(failure));
|
|
18
18
|
result.catch(() => {});
|
|
@@ -99,7 +99,7 @@ const cover = (s, entry) => {
|
|
|
99
99
|
};
|
|
100
100
|
const NO_FAILED = [];
|
|
101
101
|
const failedCommands = (s) => s.record.failed ?? NO_FAILED;
|
|
102
|
-
const
|
|
102
|
+
const retainFailedInner = (s, entry, failure) => {
|
|
103
103
|
setRecord(s, {
|
|
104
104
|
...s.record,
|
|
105
105
|
failed: [...s.record.failed ?? [], {
|
|
@@ -113,6 +113,13 @@ const retainFailed = (s, entry, failure) => {
|
|
|
113
113
|
});
|
|
114
114
|
s.notify();
|
|
115
115
|
};
|
|
116
|
+
const retainFailed = (s, entry, failure) => {
|
|
117
|
+
if (!s.shared) {
|
|
118
|
+
retainFailedInner(s, entry, failure);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
transact(s, () => retainFailedInner(s, entry, failure));
|
|
122
|
+
};
|
|
116
123
|
const settleEntry = (s, entry, outcome) => {
|
|
117
124
|
s.pending = s.pending.filter((p) => p !== entry);
|
|
118
125
|
if (outcome.ok) {
|
|
@@ -217,7 +224,7 @@ const adoptReset = (s, stored) => rebaseRecord(s, () => {
|
|
|
217
224
|
const ephemeralDetach = (s) => {
|
|
218
225
|
s.ephemeral = false;
|
|
219
226
|
s.sessionKnown = false;
|
|
220
|
-
resetRecord(s,
|
|
227
|
+
resetRecord(s, randomId());
|
|
221
228
|
};
|
|
222
229
|
const rejectedFailure = (cmd) => {
|
|
223
230
|
return {
|
|
@@ -317,8 +324,9 @@ const handleCmds = (s, cmds) => {
|
|
|
317
324
|
wake(s);
|
|
318
325
|
};
|
|
319
326
|
const ingestOps = (s, ops) => {
|
|
320
|
-
const applied =
|
|
321
|
-
s.
|
|
327
|
+
const applied = applyDocumentOps(s.documents, ops);
|
|
328
|
+
s.documents = applied;
|
|
329
|
+
s.canonical = applied.documents.get(0)?.value;
|
|
322
330
|
s.changed.push(...applied.changedPaths);
|
|
323
331
|
};
|
|
324
332
|
const publishIngested = (s) => {
|
|
@@ -353,6 +361,10 @@ const sessionLostInner = (s, seqWm, ctxWm) => {
|
|
|
353
361
|
};
|
|
354
362
|
const handleHello = (s, { ops, syn }) => {
|
|
355
363
|
if (syn.record !== void 0 && syn.record !== "ephemeral") protocolError(`unknown record: ${String(syn.record)}`);
|
|
364
|
+
s.documents = {
|
|
365
|
+
mode: null,
|
|
366
|
+
documents: /* @__PURE__ */ new Map()
|
|
367
|
+
};
|
|
356
368
|
ingestOps(s, ops);
|
|
357
369
|
s.attach = "attached";
|
|
358
370
|
s.attachEpoch += 1;
|
|
@@ -429,7 +441,7 @@ const handleDetach = (s) => {
|
|
|
429
441
|
wake(s);
|
|
430
442
|
};
|
|
431
443
|
const handleFinish = (s, { reason }) => {
|
|
432
|
-
if (reason === "
|
|
444
|
+
if (reason === "reconnect" || reason === "error") return;
|
|
433
445
|
s.attach = "finished";
|
|
434
446
|
settleAll(s, "gone");
|
|
435
447
|
publish(s);
|
|
@@ -440,12 +452,14 @@ const buildLanes = (s) => {
|
|
|
440
452
|
const ctxEntries = [];
|
|
441
453
|
for (const entry of s.ctxPending) {
|
|
442
454
|
if (entry.posted) continue;
|
|
455
|
+
if (ctxEntries.length >= 256) break;
|
|
443
456
|
if (ctxEntries.length > 0 && entry.seq !== ctxEntries.at(-1).seq + 1) break;
|
|
444
457
|
ctxEntries.push(entry);
|
|
445
458
|
}
|
|
446
459
|
const cmdEntries = [];
|
|
447
460
|
for (const entry of s.pending) {
|
|
448
461
|
if (entry.posted) continue;
|
|
462
|
+
if (cmdEntries.length >= 256) break;
|
|
449
463
|
if (cmdEntries.length > 0 && entry.seq !== cmdEntries.at(-1).seq + 1) break;
|
|
450
464
|
cmdEntries.push(entry);
|
|
451
465
|
}
|
|
@@ -605,7 +619,23 @@ const enqueue = (s, command, params, resolve, reject) => {
|
|
|
605
619
|
pump(s);
|
|
606
620
|
return;
|
|
607
621
|
}
|
|
608
|
-
transact(s, () =>
|
|
622
|
+
transact(s, () => {
|
|
623
|
+
if (!s.running) {
|
|
624
|
+
reject(new StatewireSendError({
|
|
625
|
+
fate: "aborted",
|
|
626
|
+
cause: "unmount"
|
|
627
|
+
}));
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
if (isFinished(s)) {
|
|
631
|
+
reject(new StatewireSendError({
|
|
632
|
+
fate: "aborted",
|
|
633
|
+
cause: "stream-gone"
|
|
634
|
+
}));
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
enqueueInner(s, command, params, resolve, reject);
|
|
638
|
+
}).then(() => {
|
|
609
639
|
wake(s);
|
|
610
640
|
pump(s);
|
|
611
641
|
});
|
|
@@ -657,10 +687,12 @@ const sendCommand = (s, method, params) => {
|
|
|
657
687
|
result.catch(() => {});
|
|
658
688
|
return result;
|
|
659
689
|
};
|
|
690
|
+
const findFailed = (s, entry) => (s.record.failed ?? []).find((f) => f.seq === entry.seq && f.ts === entry.ts && f.command === entry.command);
|
|
691
|
+
const unknownFailed = (entry) => /* @__PURE__ */ new Error(`statewire: unknown failed command "${entry.command}"`);
|
|
660
692
|
const takeFailed = (s, entry) => {
|
|
661
693
|
const failed = s.record.failed ?? [];
|
|
662
|
-
const found =
|
|
663
|
-
if (found === void 0) throw
|
|
694
|
+
const found = findFailed(s, entry);
|
|
695
|
+
if (found === void 0) throw unknownFailed(entry);
|
|
664
696
|
setRecord(s, {
|
|
665
697
|
...s.record,
|
|
666
698
|
failed: failed.filter((f) => f !== found)
|
|
@@ -669,7 +701,14 @@ const takeFailed = (s, entry) => {
|
|
|
669
701
|
return found;
|
|
670
702
|
};
|
|
671
703
|
const discardFailed = (s, entry) => {
|
|
672
|
-
|
|
704
|
+
if (!s.shared) {
|
|
705
|
+
takeFailed(s, entry);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
if (findFailed(s, entry) === void 0) throw unknownFailed(entry);
|
|
709
|
+
transact(s, () => {
|
|
710
|
+
if (findFailed(s, entry) !== void 0) takeFailed(s, entry);
|
|
711
|
+
});
|
|
673
712
|
};
|
|
674
713
|
const retryFailed = (s, entry) => {
|
|
675
714
|
if (!s.running) return rejectedSend({
|
|
@@ -680,14 +719,47 @@ const retryFailed = (s, entry) => {
|
|
|
680
719
|
fate: "aborted",
|
|
681
720
|
cause: "stream-gone"
|
|
682
721
|
});
|
|
683
|
-
const found =
|
|
722
|
+
const found = findFailed(s, entry);
|
|
723
|
+
if (found === void 0) throw unknownFailed(entry);
|
|
684
724
|
const params = found.meta === void 0 ? found.params : reviveValue([...found.params], found.meta);
|
|
685
725
|
const result = new Promise((resolve, reject) => {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
726
|
+
const retry = () => {
|
|
727
|
+
if (!s.running) {
|
|
728
|
+
reject(new StatewireSendError({
|
|
729
|
+
fate: "aborted",
|
|
730
|
+
cause: "unmount"
|
|
731
|
+
}));
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
if (isFinished(s)) {
|
|
735
|
+
reject(new StatewireSendError({
|
|
736
|
+
fate: "aborted",
|
|
737
|
+
cause: "stream-gone"
|
|
738
|
+
}));
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
const current = findFailed(s, entry);
|
|
742
|
+
if (current === void 0) {
|
|
743
|
+
reject(unknownFailed(entry));
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
takeFailed(s, current);
|
|
747
|
+
enqueueInner(s, {
|
|
748
|
+
method: current.command,
|
|
749
|
+
params: [...current.params],
|
|
750
|
+
...current.meta !== void 0 && { meta: current.meta }
|
|
751
|
+
}, params, resolve, reject);
|
|
752
|
+
};
|
|
753
|
+
if (!s.shared) {
|
|
754
|
+
retry();
|
|
755
|
+
wake(s);
|
|
756
|
+
pump(s);
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
transact(s, retry).then(() => {
|
|
760
|
+
wake(s);
|
|
761
|
+
pump(s);
|
|
762
|
+
}, reject);
|
|
691
763
|
});
|
|
692
764
|
result.catch(() => {});
|
|
693
765
|
return result;
|
|
@@ -721,7 +793,10 @@ const setContext = (s, value) => {
|
|
|
721
793
|
pump(s);
|
|
722
794
|
return;
|
|
723
795
|
}
|
|
724
|
-
transact(s,
|
|
796
|
+
transact(s, () => {
|
|
797
|
+
if (!s.running || isFinished(s)) return;
|
|
798
|
+
mint();
|
|
799
|
+
}).then(() => {
|
|
725
800
|
wake(s);
|
|
726
801
|
pump(s);
|
|
727
802
|
});
|
|
@@ -737,7 +812,7 @@ const useStatewireSession = (options) => {
|
|
|
737
812
|
if (stored !== null && !Array.isArray(stored.commands)) throw new Error("statewire: session storage loaded a record without a commands array");
|
|
738
813
|
const session = {
|
|
739
814
|
record: stored ?? {
|
|
740
|
-
clientId:
|
|
815
|
+
clientId: randomId(),
|
|
741
816
|
nextSeq: 1,
|
|
742
817
|
ctxNextSeq: 1,
|
|
743
818
|
commands: []
|
|
@@ -777,6 +852,10 @@ const useStatewireSession = (options) => {
|
|
|
777
852
|
frameFailures: 0,
|
|
778
853
|
pending: [],
|
|
779
854
|
canonical: void 0,
|
|
855
|
+
documents: {
|
|
856
|
+
mode: null,
|
|
857
|
+
documents: /* @__PURE__ */ new Map()
|
|
858
|
+
},
|
|
780
859
|
lastPublished: void 0,
|
|
781
860
|
changed: [],
|
|
782
861
|
source: {
|