statewire 0.0.1 → 0.0.3

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.
Files changed (148) hide show
  1. package/README.md +14 -13
  2. package/dist/client/changes.d.ts +2 -2
  3. package/dist/client/changes.d.ts.map +1 -1
  4. package/dist/client/changes.js +3 -10
  5. package/dist/client/changes.js.map +1 -1
  6. package/dist/client/connection.d.ts +18 -39
  7. package/dist/client/connection.d.ts.map +1 -1
  8. package/dist/client/connection.js +61 -54
  9. package/dist/client/connection.js.map +1 -1
  10. package/dist/client/core.d.ts +7 -11
  11. package/dist/client/core.d.ts.map +1 -1
  12. package/dist/client/core.js +58 -55
  13. package/dist/client/core.js.map +1 -1
  14. package/dist/client/session.d.ts +12 -26
  15. package/dist/client/session.d.ts.map +1 -1
  16. package/dist/client/session.js +70 -43
  17. package/dist/client/session.js.map +1 -1
  18. package/dist/client/sessionStore.d.ts +1 -1
  19. package/dist/client/sessionStore.js.map +1 -1
  20. package/dist/client/timing.d.ts +2 -1
  21. package/dist/client/timing.d.ts.map +1 -1
  22. package/dist/client/timing.js +5 -1
  23. package/dist/client/timing.js.map +1 -1
  24. package/dist/host/adapter.d.ts +8 -0
  25. package/dist/host/adapter.d.ts.map +1 -0
  26. package/dist/host/adapter.js +23 -0
  27. package/dist/host/adapter.js.map +1 -0
  28. package/dist/host/draft.d.ts +21 -7
  29. package/dist/host/draft.d.ts.map +1 -1
  30. package/dist/host/draft.js +190 -103
  31. package/dist/host/draft.js.map +1 -1
  32. package/dist/host/host.d.ts +19 -35
  33. package/dist/host/host.d.ts.map +1 -1
  34. package/dist/host/host.js +86 -54
  35. package/dist/host/host.js.map +1 -1
  36. package/dist/host/socket.d.ts +14 -0
  37. package/dist/host/socket.d.ts.map +1 -0
  38. package/dist/host/socket.js +511 -0
  39. package/dist/host/socket.js.map +1 -0
  40. package/dist/host-internal.d.ts +27 -0
  41. package/dist/host-internal.d.ts.map +1 -0
  42. package/dist/host-internal.js +3 -0
  43. package/dist/host.d.ts +54 -0
  44. package/dist/host.d.ts.map +1 -0
  45. package/dist/host.js +4 -0
  46. package/dist/index.d.ts +5 -28
  47. package/dist/index.js +2 -3
  48. package/dist/statewire.d.ts +97 -10
  49. package/dist/statewire.d.ts.map +1 -1
  50. package/dist/statewire.js +32 -36
  51. package/dist/statewire.js.map +1 -1
  52. package/dist/transports/fake-sse.d.ts +12 -0
  53. package/dist/transports/fake-sse.d.ts.map +1 -0
  54. package/dist/transports/fake-sse.js +39 -0
  55. package/dist/transports/fake-sse.js.map +1 -0
  56. package/dist/transports/fixtures.d.ts +33 -0
  57. package/dist/transports/fixtures.d.ts.map +1 -0
  58. package/dist/transports/fixtures.js +50 -0
  59. package/dist/transports/fixtures.js.map +1 -0
  60. package/dist/transports/remote.d.ts +6 -13
  61. package/dist/transports/remote.d.ts.map +1 -1
  62. package/dist/transports/remote.js +7 -25
  63. package/dist/transports/remote.js.map +1 -1
  64. package/dist/transports/sse.d.ts +32 -20
  65. package/dist/transports/sse.d.ts.map +1 -1
  66. package/dist/transports/sse.js +57 -46
  67. package/dist/transports/sse.js.map +1 -1
  68. package/dist/transports/testing.d.ts +8 -6
  69. package/dist/transports/testing.d.ts.map +1 -1
  70. package/dist/transports/testing.js +19 -46
  71. package/dist/transports/testing.js.map +1 -1
  72. package/dist/transports/ws.d.ts +4 -13
  73. package/dist/transports/ws.d.ts.map +1 -1
  74. package/dist/transports/ws.js +59 -63
  75. package/dist/transports/ws.js.map +1 -1
  76. package/dist/types.d.ts +55 -100
  77. package/dist/types.d.ts.map +1 -1
  78. package/dist/types.js.map +1 -1
  79. package/dist/util/draftTraps.d.ts +6 -0
  80. package/dist/util/draftTraps.d.ts.map +1 -0
  81. package/dist/util/draftTraps.js +25 -0
  82. package/dist/util/draftTraps.js.map +1 -0
  83. package/dist/util/macrotask.d.ts +5 -0
  84. package/dist/util/macrotask.d.ts.map +1 -0
  85. package/dist/util/macrotask.js +25 -0
  86. package/dist/util/macrotask.js.map +1 -0
  87. package/dist/util/methodProxy.d.ts +5 -0
  88. package/dist/util/methodProxy.d.ts.map +1 -0
  89. package/dist/util/methodProxy.js +17 -0
  90. package/dist/util/methodProxy.js.map +1 -0
  91. package/dist/util/randomId.d.ts +5 -0
  92. package/dist/util/randomId.d.ts.map +1 -0
  93. package/dist/util/randomId.js +6 -0
  94. package/dist/util/randomId.js.map +1 -0
  95. package/dist/{client/optimistic.d.ts → util/recordMutations.d.ts} +2 -2
  96. package/dist/util/recordMutations.d.ts.map +1 -0
  97. package/dist/{client/optimistic.js → util/recordMutations.js} +5 -24
  98. package/dist/util/recordMutations.js.map +1 -0
  99. package/dist/util/statePath.d.ts +14 -0
  100. package/dist/util/statePath.d.ts.map +1 -0
  101. package/dist/util/statePath.js +31 -0
  102. package/dist/util/statePath.js.map +1 -0
  103. package/dist/wire/meta.d.ts +6 -1
  104. package/dist/wire/meta.d.ts.map +1 -1
  105. package/dist/wire/meta.js +30 -28
  106. package/dist/wire/meta.js.map +1 -1
  107. package/dist/wire/ops.d.ts +5 -26
  108. package/dist/wire/ops.d.ts.map +1 -1
  109. package/dist/wire/ops.js +67 -80
  110. package/dist/wire/ops.js.map +1 -1
  111. package/package.json +15 -11
  112. package/src/client/changes.ts +5 -15
  113. package/src/client/connection.ts +87 -113
  114. package/src/client/core.ts +57 -91
  115. package/src/client/session.ts +129 -90
  116. package/src/client/sessionStore.ts +1 -1
  117. package/src/client/timing.ts +6 -0
  118. package/src/host/adapter.ts +33 -0
  119. package/src/host/draft.ts +293 -125
  120. package/src/host/host.ts +122 -110
  121. package/src/host/socket.ts +618 -0
  122. package/src/host-internal.ts +28 -0
  123. package/src/host.ts +72 -0
  124. package/src/index.ts +2 -62
  125. package/src/statewire.ts +168 -61
  126. package/src/transports/fake-sse.ts +51 -0
  127. package/src/transports/fixtures.ts +60 -0
  128. package/src/transports/remote.ts +14 -51
  129. package/src/transports/sse.ts +87 -89
  130. package/src/transports/testing.ts +33 -63
  131. package/src/transports/ws.ts +78 -100
  132. package/src/types.ts +52 -131
  133. package/src/util/draftTraps.ts +32 -0
  134. package/src/util/macrotask.ts +25 -0
  135. package/src/util/methodProxy.ts +16 -0
  136. package/src/util/randomId.ts +4 -0
  137. package/src/{client/optimistic.ts → util/recordMutations.ts} +0 -0
  138. package/src/util/statePath.ts +61 -0
  139. package/src/wire/meta.ts +42 -47
  140. package/src/wire/ops.ts +107 -106
  141. package/LICENSE +0 -21
  142. package/dist/client/optimistic.d.ts.map +0 -1
  143. package/dist/client/optimistic.js.map +0 -1
  144. package/dist/index.d.ts.map +0 -1
  145. package/dist/server.d.ts +0 -15
  146. package/dist/server.d.ts.map +0 -1
  147. package/dist/server.js +0 -3
  148. package/src/server.ts +0 -32
package/README.md CHANGED
@@ -9,7 +9,7 @@ type Commands = {
9
9
  increment(): void;
10
10
  };
11
11
 
12
- const { state, transport, commands } = useStatewire<State, Commands, Event>({
12
+ const { state, connection, commands } = useStatewire<State, Commands, Event>({
13
13
  transport: StatewireSSE({ url: "/api/threads/demo" }),
14
14
  optimistic: (draft, command) => {
15
15
  if (command.method === "increment") draft.count += 1;
@@ -24,15 +24,16 @@ const onClick = async () => {
24
24
  ## What you get
25
25
 
26
26
  - **`state`** — `undefined` until the first snapshot, then canonical server state with your pending commands' optimistic effects rebased on top. When the server's ack arrives, the optimistic overlay drops in the same tick: no flicker.
27
- - **`transport`** — connection health as a tagged union: `transport.status` is `"connecting" | "live" | "reconnecting" | "gone"`, and each variant carries exactly the data that exists in that situation: `reconnecting` has `cause` (`"dropped"`, `"ended"`, or `"error"`), `attempt`, `nextRetryAt`, `lastError?`, `message?`; `gone` carries the server's `message?`. `transport.reconnect()` re-attaches manually from `gone`, or "retry now" during backoff.
28
- - **`commands`** — a typed proxy over the `Commands` method map: `commands.increment()` submits `{ method: "increment", params: [] }` and resolves with the handler's result only once the stream ack proves the effect is in canonical state. Rejects with `StatewireSendError`, whose `failure.stage` carries the verdict; the boundary is definitiveness:
27
+ - **`connection`** — connection health as a tagged union: `connection.status` is `"connecting" | "live" | "reconnecting" | "gone"`, and each variant carries exactly the data that exists in that situation: `reconnecting` has `cause` (`"dropped"`, `"evicted"`, or `"error"`), `attempt`, `nextRetryAt`, `lastError?`, `message?`; `gone` carries the server's `message?` and `payload?`. `connection.reconnect()` re-attaches manually from `gone`, or "retry now" during backoff.
28
+ - **`commands`** — a typed proxy over the `Commands` method map: `commands.increment()` submits `{ method: "increment", params: [] }` and resolves with the handler's result only once the stream ack proves the effect is in canonical state. Rejects with `StatewireSendError`, whose `failure.fate` carries the verdict; the boundary is definitiveness:
29
29
  - `"aborted"` — definitely not applied (never POSTed, or every attempt accounted for); safe to resend
30
30
  - `"lost"` — a POST left the machine and never got a definitive answer; whether the server applied it is unknown — check the snapshot for your payload ids
31
- - `"rejected"` — the server said no; not applied (`message`, optional `payload` from the backend's `Reject`)
31
+ - `"rejected"` — the server said no; not applied (`message`, optional `payload` from the backend's `StatewireReject`)
32
+ - `"unknown-command"` / `"invalid-params"` — the server does not know the method, or the args failed its schema
32
33
  - `"crashed"` — acked, but the processing died before producing a result
33
- - `"unavailable"` — acked, but the result can no longer be delivered
34
+ - `"result-unavailable"` — acked, but the result can no longer be delivered
34
35
 
35
- Every failure also carries `reason` — the trigger: `"response"` = the server's response settled it, `"stream-gone"` = terminal `finish(gone)`, `"session-lost"` = the server forgot the client id (eviction), `"superseded"` = another attach took the writer lease, `"unmount"` / `"cascade"` are client-side. `Statewire.SendFailure` is the taxonomy's single exported type; the `stage` and `reason` unions are reachable as `SendFailure["stage"]` / `SendFailure["reason"]`.
36
+ Every failure also carries `cause` — which channel settled it: `"server"` = the server's answer, `"stream-gone"` = terminal `finish(gone)`, `"session-lost"` = the server forgot the client id (eviction), `"superseded"` = another attach took the writer lease, `"unmount"` / `"cascade"` are client-side. The taxonomy's single exported type is `StatewireClient.SendFailure`; the `fate` and `cause` unions are reachable as `SendFailure["fate"]` / `SendFailure["cause"]`.
36
37
 
37
38
  Reconnects are not errors: transport drops and server evictions self-heal with exponential backoff while `state` stays renderable. Commands carry a monotonic seq, so retries are deduplicated server-side and a reconnect splices already-applied commands instead of re-running them.
38
39
 
@@ -45,13 +46,13 @@ One implementation, three entry points:
45
46
  ```ts
46
47
  useStatewire(options) // React hook
47
48
  StatewireResource(options) // @assistant-ui/tap resource, for composition
48
- new Statewire(options) // framework-free: .state/.transport/.commands,
49
+ new StatewireClient(options) // framework-free: .state/.connection/.commands,
49
50
  // .subscribe(cb), .dispose()
50
51
  ```
51
52
 
52
- `Statewire#subscribe` follows the external-store contract (`useSyncExternalStore`-compatible). `dispose()` settles pending commands like an unmount.
53
+ `StatewireClient#subscribe` follows the external-store contract (`useSyncExternalStore`-compatible). `dispose()` settles pending commands like an unmount.
53
54
 
54
- Every public type merges onto the class as a namespace — `Statewire.Transport`, `Statewire.TransportStatus`, `Statewire.Options`, `Statewire.SendFailure`, … — so one import covers the whole surface.
55
+ Every public type merges onto the class as a namespace — `StatewireClient.Connection`, `StatewireClient.ConnectionStatus`, `StatewireClient.Options`, `StatewireClient.SendFailure`, … — so one import covers the whole surface.
55
56
 
56
57
  There is no session key: a transport `url` change reattaches in place and the attach snapshot arbitrates identity (an unknown client evicts — pending settles, the client id rotates). For a forced fresh session, key the resource — `withKey(threadId, StatewireResource(options))`; pending commands settle with reason `"unmount"`.
57
58
 
@@ -65,20 +66,20 @@ StatewireSSE({
65
66
  })
66
67
  ```
67
68
 
68
- `StatewireWS({ url, protocols, query, webSocket })` is the full-duplex sibling over `/ws`. Transports implement the `Statewire.TransportProps` seam; `createMockTransport` from `statewire/testing` is a complete in-memory driver for tests.
69
+ `StatewireWS({ url, protocols, query, webSocket })` is the full-duplex sibling over `/ws`. A transport is a tap resource producing the `Statewire` value the client consumes; `createMockTransport` from `statewire/testing` is a complete in-memory driver for tests.
69
70
 
70
71
  ## Backend
71
72
 
72
- Any server speaking the Statewire convention works. The Python implementation lives in this repo (`python/statewire`):
73
+ Any server speaking the Statewire convention works. The Python implementation lives in this repo (`python/statewire/statewire`):
73
74
 
74
75
  ```python
75
- from statewire import Statewire, Reject, command
76
+ from statewire import Statewire, StatewireReject, command
76
77
 
77
78
  class Counter(Statewire):
78
79
  @command
79
80
  async def increment(self):
80
81
  if self.state["count"] >= 10:
81
- raise Reject("counter is full", payload={"max": 10})
82
+ raise StatewireReject("counter is full", payload={"max": 10})
82
83
  self.state["count"] += 1
83
84
  ```
84
85
 
@@ -1,7 +1,7 @@
1
+ import { Statewire } from "../types.js";
1
2
  import { StatewirePath } from "../wire/ops.js";
2
- import { StatewireChanges } from "../types.js";
3
3
  //#region src/client/changes.d.ts
4
- declare const createChanges: (prev: unknown, next: unknown, changedPaths: readonly StatewirePath[]) => StatewireChanges;
4
+ declare const createChanges: (prev: unknown, next: unknown, changedPaths: readonly StatewirePath[]) => Statewire.Changes;
5
5
  //#endregion
6
6
  export { createChanges };
7
7
  //# sourceMappingURL=changes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"changes.d.ts","names":[],"sources":["../../src/client/changes.ts"],"mappings":";;;cAqBa,gBACX,eACA,eACA,uBAAuB,oBACtB"}
1
+ {"version":3,"file":"changes.d.ts","names":[],"sources":["../../src/client/changes.ts"],"mappings":";;;cAWa,gBACX,eACA,eACA,uBAAuB,oBACtB,UAAU"}
@@ -1,20 +1,13 @@
1
+ import { readAtPath } from "../util/statePath.js";
1
2
  //#region src/client/changes.ts
2
- const lookupValue = (state, path) => {
3
- let node = state;
4
- for (const key of path) {
5
- if (typeof node !== "object" || node === null) return void 0;
6
- node = Object.hasOwn(node, key) ? node[key] : void 0;
7
- }
8
- return node;
9
- };
10
3
  const keysAt = (node) => typeof node === "object" && node !== null ? Object.keys(node) : [];
11
4
  const isPrefix = (prefix, path) => prefix.length <= path.length && prefix.every((key, i) => String(key) === String(path[i]));
12
5
  const createChanges = (prev, next, changedPaths) => ({
13
6
  isChangedAt: (path) => changedPaths.some((p) => isPrefix(p, path) || isPrefix(path, p)),
14
7
  getChangedKeys: (path) => {
15
8
  if (changedPaths.some((p) => p.length <= path.length && isPrefix(p, path))) {
16
- const keys = keysAt(lookupValue(next, path));
17
- for (const key of keysAt(lookupValue(prev, path))) if (!keys.includes(key)) keys.push(key);
9
+ const keys = keysAt(readAtPath(next, path));
10
+ for (const key of keysAt(readAtPath(prev, path))) if (!keys.includes(key)) keys.push(key);
18
11
  return keys;
19
12
  }
20
13
  const keys = [];
@@ -1 +1 @@
1
- {"version":3,"file":"changes.js","names":["StatewirePath","StatewireChanges","lookupValue","state","path","node","key","undefined","Object","hasOwn","Record","keysAt","keys","isPrefix","prefix","length","every","i","String","createChanges","prev","next","changedPaths","isChangedAt","some","p","getChangedKeys","wiped","includes","push"],"sources":["../../src/client/changes.ts"],"sourcesContent":["import type { StatewirePath } from \"../wire/ops\";\nimport type { StatewireChanges } from \"../types\";\n\nconst lookupValue = (state: unknown, path: StatewirePath): unknown => {\n let node = state;\n for (const key of path) {\n if (typeof node !== \"object\" || node === null) return undefined;\n node = Object.hasOwn(node, key)\n ? (node as Record<string, unknown>)[key]\n : undefined;\n }\n return node;\n};\n\nconst keysAt = (node: unknown): string[] =>\n typeof node === \"object\" && node !== null ? Object.keys(node) : [];\n\nconst isPrefix = (prefix: StatewirePath, path: StatewirePath): boolean =>\n prefix.length <= path.length &&\n prefix.every((key, i) => String(key) === String(path[i]));\n\nexport const createChanges = (\n prev: unknown,\n next: unknown,\n changedPaths: readonly StatewirePath[],\n): StatewireChanges => ({\n isChangedAt: (path) =>\n changedPaths.some((p) => isPrefix(p, path) || isPrefix(path, p)),\n getChangedKeys: (path) => {\n const wiped = changedPaths.some(\n (p) => p.length <= path.length && isPrefix(p, path),\n );\n if (wiped) {\n const keys = keysAt(lookupValue(next, path));\n for (const key of keysAt(lookupValue(prev, path))) {\n if (!keys.includes(key)) keys.push(key);\n }\n return keys;\n }\n const keys: string[] = [];\n for (const p of changedPaths) {\n if (p.length <= path.length || !isPrefix(path, p)) continue;\n const key = String(p[path.length]);\n if (!keys.includes(key)) keys.push(key);\n }\n return keys;\n },\n});\n"],"mappings":";AAGA,MAAME,eAAeC,OAAgBC,SAAiC;CACpE,IAAIC,OAAOF;CACX,KAAK,MAAMG,OAAOF,MAAM;EACtB,IAAI,OAAOC,SAAS,YAAYA,SAAS,MAAM,OAAOE,KAAAA;EACtDF,OAAOG,OAAOC,OAAOJ,MAAMC,GAAG,IACzBD,KAAiCC,OAClCC,KAAAA;CACN;CACA,OAAOF;AACT;AAEA,MAAMM,UAAUN,SACd,OAAOA,SAAS,YAAYA,SAAS,OAAOG,OAAOI,KAAKP,IAAI,IAAI,CAAA;AAElE,MAAMQ,YAAYC,QAAuBV,SACvCU,OAAOC,UAAUX,KAAKW,UACtBD,OAAOE,OAAOV,KAAKW,MAAMC,OAAOZ,GAAG,MAAMY,OAAOd,KAAKa,EAAE,CAAC;AAE1D,MAAaE,iBACXC,MACAC,MACAC,kBACsB;CACtBC,cAAcnB,SACZkB,aAAaE,MAAMC,MAAMZ,SAASY,GAAGrB,IAAI,KAAKS,SAAST,MAAMqB,CAAC,CAAC;CACjEC,iBAAiBtB,SAAS;EAIxB,IAHckB,aAAaE,MACxBC,MAAMA,EAAEV,UAAUX,KAAKW,UAAUF,SAASY,GAAGrB,IAAI,CAEhDuB,GAAO;GACT,MAAMf,OAAOD,OAAOT,YAAYmB,MAAMjB,IAAI,CAAC;GAC3C,KAAK,MAAME,OAAOK,OAAOT,YAAYkB,MAAMhB,IAAI,CAAC,GAC9C,IAAI,CAACQ,KAAKgB,SAAStB,GAAG,GAAGM,KAAKiB,KAAKvB,GAAG;GAExC,OAAOM;EACT;EACA,MAAMA,OAAiB,CAAA;EACvB,KAAK,MAAMa,KAAKH,cAAc;GAC5B,IAAIG,EAAEV,UAAUX,KAAKW,UAAU,CAACF,SAAST,MAAMqB,CAAC,GAAG;GACnD,MAAMnB,MAAMY,OAAOO,EAAErB,KAAKW,OAAO;GACjC,IAAI,CAACH,KAAKgB,SAAStB,GAAG,GAAGM,KAAKiB,KAAKvB,GAAG;EACxC;EACA,OAAOM;CACT;AACF"}
1
+ {"version":3,"file":"changes.js","names":["StatewirePath","Statewire","readAtPath","keysAt","node","Object","keys","isPrefix","prefix","path","length","every","key","i","String","createChanges","prev","next","changedPaths","Changes","isChangedAt","some","p","getChangedKeys","wiped","includes","push"],"sources":["../../src/client/changes.ts"],"sourcesContent":["import type { StatewirePath } from \"../wire/ops\";\nimport type { Statewire } from \"../types\";\nimport { readAtPath } from \"../util/statePath\";\n\nconst keysAt = (node: unknown): string[] =>\n typeof node === \"object\" && node !== null ? Object.keys(node) : [];\n\nconst isPrefix = (prefix: StatewirePath, path: StatewirePath): boolean =>\n prefix.length <= path.length &&\n prefix.every((key, i) => String(key) === String(path[i]));\n\nexport const createChanges = (\n prev: unknown,\n next: unknown,\n changedPaths: readonly StatewirePath[],\n): Statewire.Changes => ({\n isChangedAt: (path) =>\n changedPaths.some((p) => isPrefix(p, path) || isPrefix(path, p)),\n getChangedKeys: (path) => {\n const wiped = changedPaths.some(\n (p) => p.length <= path.length && isPrefix(p, path),\n );\n if (wiped) {\n const keys = keysAt(readAtPath(next, path));\n for (const key of keysAt(readAtPath(prev, path))) {\n if (!keys.includes(key)) keys.push(key);\n }\n return keys;\n }\n const keys: string[] = [];\n for (const p of changedPaths) {\n if (p.length <= path.length || !isPrefix(path, p)) continue;\n const key = String(p[path.length]);\n if (!keys.includes(key)) keys.push(key);\n }\n return keys;\n },\n});\n"],"mappings":";;AAIA,MAAMG,UAAUC,SACd,OAAOA,SAAS,YAAYA,SAAS,OAAOC,OAAOC,KAAKF,IAAI,IAAI,CAAA;AAElE,MAAMG,YAAYC,QAAuBC,SACvCD,OAAOE,UAAUD,KAAKC,UACtBF,OAAOG,OAAOC,KAAKC,MAAMC,OAAOF,GAAG,MAAME,OAAOL,KAAKI,EAAE,CAAC;AAE1D,MAAaE,iBACXC,MACAC,MACAC,kBACuB;CACvBE,cAAcX,SACZS,aAAaG,MAAMC,MAAMf,SAASe,GAAGb,IAAI,KAAKF,SAASE,MAAMa,CAAC,CAAC;CACjEC,iBAAiBd,SAAS;EAIxB,IAHcS,aAAaG,MACxBC,MAAMA,EAAEZ,UAAUD,KAAKC,UAAUH,SAASe,GAAGb,IAAI,CAEhDe,GAAO;GACT,MAAMlB,OAAOH,OAAOD,WAAWe,MAAMR,IAAI,CAAC;GAC1C,KAAK,MAAMG,OAAOT,OAAOD,WAAWc,MAAMP,IAAI,CAAC,GAC7C,IAAI,CAACH,KAAKmB,SAASb,GAAG,GAAGN,KAAKoB,KAAKd,GAAG;GAExC,OAAON;EACT;EACA,MAAMA,OAAiB,CAAA;EACvB,KAAK,MAAMgB,KAAKJ,cAAc;GAC5B,IAAII,EAAEZ,UAAUD,KAAKC,UAAU,CAACH,SAASE,MAAMa,CAAC,GAAG;GACnD,MAAMV,MAAME,OAAOQ,EAAEb,KAAKC,OAAO;GACjC,IAAI,CAACJ,KAAKmB,SAASb,GAAG,GAAGN,KAAKoB,KAAKd,GAAG;EACxC;EACA,OAAON;CACT;AACF"}
@@ -1,15 +1,11 @@
1
- import { ConnectionState, RemoteLink, StatewireConnection, StatewireTransportProps } from "../transports/sse.js";
1
+ import { StatewireHost } from "../host.js";
2
+ import { StatewireRemoteProps } from "../transports/sse.js";
3
+ import { StatewireClient } from "../statewire.js";
2
4
  //#region src/client/connection.d.ts
3
5
  type Episode = {
4
- cause: "dropped" | "ended" | "error";
6
+ cause: "dropped" | "evicted" | "error";
5
7
  message?: string;
6
8
  };
7
- type StatewireFinish = {
8
- reason: "ended" | "error" | "gone" | "superseded" | (string & {});
9
- message?: string;
10
- payload?: unknown;
11
- meta?: unknown;
12
- };
13
9
  type StatewireResponse = {
14
10
  seq: number;
15
11
  type: "accepted" | "rejected" | "pending" | "crashed" | "result-unavailable";
@@ -27,7 +23,7 @@ type StatewireEnvelope = {
27
23
  res?: StatewireResponse[];
28
24
  ack?: number;
29
25
  syn?: StatewireSyn;
30
- fin?: StatewireFinish;
26
+ fin?: StatewireHost.Fin;
31
27
  };
32
28
  declare const createGate: () => {
33
29
  take: () => boolean;
@@ -35,8 +31,8 @@ declare const createGate: () => {
35
31
  open: () => void;
36
32
  };
37
33
  type Gate = ReturnType<typeof createGate>;
38
- type ConnBase = {
39
- connection: StatewireConnection;
34
+ type Conn = {
35
+ connection: StatewireClient.Connection;
40
36
  hasSnapshot: boolean;
41
37
  lease: string | null;
42
38
  attempt: number;
@@ -44,41 +40,24 @@ type ConnBase = {
44
40
  gate: Gate;
45
41
  abort: AbortController | null;
46
42
  lifetime: AbortController | null;
47
- latest: {
48
- readonly current: {
49
- options: {
50
- onChange?: (connection: StatewireConnection) => void;
51
- };
52
- ctx: StatewireTransportProps;
53
- };
54
- };
55
- notify: (connection: StatewireConnection) => void;
56
- reconnect: () => void;
43
+ ctx: StatewireRemoteProps;
44
+ onChange: (connection: StatewireClient.Connection) => void;
57
45
  attemptOnce: (abort: AbortController) => Promise<"stop" | "reattach" | "ended">;
46
+ notify: (connection: StatewireClient.Connection) => void;
47
+ reconnect: () => void;
58
48
  };
59
- declare const setStatus: (c: ConnBase, next: ConnectionState) => void;
60
- declare const deliverEnvelope: (c: ConnBase, env: Pick<StatewireEnvelope, "ops" | "res" | "ack" | "syn">, attached: boolean) => void;
61
- declare const isTransientFinish: (reason: StatewireFinish["reason"]) => reason is "ended" | "error";
62
- declare const settleEnvelope: (c: ConnBase, env: StatewireEnvelope) => "stop" | "reattach" | null;
63
- declare const handleEnvelope: (c: ConnBase, env: StatewireEnvelope, attached: boolean) => "stop" | "reattach" | null;
64
- declare const scheduleRetry: (c: ConnBase, failure: string | undefined, immediate: boolean, retryAfterMs?: number) => number;
65
- declare const reconnectConn: (c: ConnBase) => void;
66
- declare const useStatewireConn: <TOptions extends {
49
+ declare const handleEnvelope: (c: Conn, env: StatewireEnvelope) => "stop" | "reattach" | null;
50
+ declare const useStatewireConn: (props: {
67
51
  url: string;
68
- onChange?: (connection: StatewireConnection) => void;
69
- }>(options: TOptions, ctx: StatewireTransportProps, create: (latest: {
70
- readonly current: {
71
- options: TOptions;
72
- ctx: StatewireTransportProps;
73
- };
74
- }, notify: (connection: StatewireConnection) => void) => ConnBase & {
75
- send: RemoteLink["send"];
76
- }) => RemoteLink;
52
+ onChange?: ((connection: StatewireClient.Connection) => void) | undefined;
53
+ ctx: StatewireRemoteProps;
54
+ attemptOnce: (c: Conn, abort: AbortController) => Promise<"stop" | "reattach" | "ended">;
55
+ }) => Conn;
77
56
  declare const classify: (timeout: AbortSignal) => Error;
78
57
  declare const parseRetryAfter: (header: string | null) => number | undefined;
79
58
  declare const overloadedError: (retryAfterMs?: number) => Error & {
80
59
  retryAfterMs: number | undefined;
81
60
  };
82
61
  //#endregion
83
- export { ConnBase, Episode, Gate, StatewireEnvelope, StatewireFinish, StatewireResponse, StatewireSyn, classify, createGate, deliverEnvelope, handleEnvelope, isTransientFinish, overloadedError, parseRetryAfter, reconnectConn, scheduleRetry, setStatus, settleEnvelope, useStatewireConn };
62
+ export { Conn, Episode, Gate, StatewireEnvelope, StatewireResponse, StatewireSyn, classify, handleEnvelope, overloadedError, parseRetryAfter, useStatewireConn };
84
63
  //# sourceMappingURL=connection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection.d.ts","names":[],"sources":["../../src/client/connection.ts"],"mappings":";;KAWY;EACV;EACA;;KAGU;EACV;EACA;EACA;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA;;KAGU;EACV;EACA,MAAM;EACN;EACA,MAAM;EACN,MAAM;;cAGK;;EASU,OAAA,uBAAM;;;KA2BjB,OAAO,kBAAkB;KAEzB;EACV,YAAY;EACZ;EACA;EACA;EACA,SAAS;EACT,MAAM;EACN,OAAO;EACP,UAAU;EACV;aACW;MACP;QAAW,YAAY,YAAY;;MACnC,KAAK;;;EAGT,SAAS,YAAY;EACrB;EACA,cACE,OAAO,oBACJ;;cAGM,YAAa,GAAG,UAAU,MAAM;cAOhC,kBACX,GAAG,UACH,KAAK,KAAK,mDACV;cAsBW,oBACX,QAAQ,8BACP;cAEU,iBACX,GAAG,UACH,KAAK;cA+BM,iBACX,GAAG,UACH,KAAK,mBACL;cAMW,gBACX,GAAG,UACH,6BACA,oBACA;cAiBW,gBAAiB,GAAG;cAwEpB,mBACX;EACE;EACA,YAAY,YAAY;GAG1B,SAAS,UACT,KAAK,yBACL,SACE;WACW;IACP,SAAS;IACT,KAAK;;GAGT,SAAS,YAAY,iCAClB;EAAa,MAAM;MACvB;cAqBU,WAAY,SAAS,gBAAW;cAGhC,kBAAmB;cAQnB,kBAAmB,0BAAqB"}
1
+ {"version":3,"file":"connection.d.ts","names":[],"sources":["../../src/client/connection.ts"],"mappings":";;;;KAQY;EACV;EACA;;KAGU;EACV;EACA;EACA;EACA;EACA;EACA;;KAGU;EACV;EACA;;KAGU;EACV;EACA,MAAM;EACN;EACA,MAAM;EACN,MAAM,cAAc;;cAGhB;;EASiB,OAAA,uBAAM;;;KA2BjB,OAAO,kBAAkB;KAEzB;EACV,YAAY,gBAAgB;EAC5B;EACA;EACA;EACA,SAAS;EACT,MAAM;EACN,OAAO;EACP,UAAU;EACV,KAAK;EACL,WAAW,YAAY,gBAAgB;EACvC,cACE,OAAO,oBACJ;EACL,SAAS,YAAY,gBAAgB;EACrC;;cAuEW,iBACX,GAAG,MACH,KAAK;cAyEM,mBAAoB;EAC/B;EACA,aAAa,YAAY,gBAAgB;EACzC,KAAK;EACL,cACE,GAAG,MACH,OAAO,oBACJ;MACH;cA8CS,WAAY,SAAS,gBAAW;cAGhC,kBAAmB;cAQnB,kBAAmB,0BAAqB"}
@@ -1,5 +1,5 @@
1
1
  import { reviveOps, reviveResponse, reviveValue } from "../wire/meta.js";
2
- import { backoff } from "./timing.js";
2
+ import { retryDelay } from "./timing.js";
3
3
  import { useEffect, useRef, useState } from "@assistant-ui/tap/react-shim";
4
4
  import { flushTapSync } from "@assistant-ui/tap";
5
5
  //#region src/client/connection.ts
@@ -42,25 +42,26 @@ const setStatus = (c, next) => {
42
42
  reconnect: c.reconnect
43
43
  };
44
44
  c.notify(c.connection);
45
- if (changed) c.latest.current.options.onChange?.(c.connection);
45
+ if (changed) c.onChange(c.connection);
46
46
  };
47
- const deliverEnvelope = (c, env, attached) => {
47
+ const deliverEnvelope = (c, env) => {
48
48
  if (env.syn?.lease !== void 0) c.lease = env.syn.lease;
49
- const ctx = c.latest.current.ctx;
49
+ const ctx = c.ctx;
50
50
  const ops = env.ops === void 0 ? [] : reviveOps(env.ops);
51
51
  const res = env.res?.map(reviveResponse);
52
- if (!attached) ctx.onSnapshot({
53
- ops,
54
- lastSeq: env.syn?.lastSeq ?? -1
55
- });
56
- else if (env.ops !== void 0 || env.res !== void 0 || env.ack !== void 0) ctx.onOps({
52
+ if (env.syn !== void 0) {
53
+ ctx.onSnapshot({
54
+ ops,
55
+ lastSeq: env.syn.lastSeq
56
+ });
57
+ c.hasSnapshot = true;
58
+ } else if (env.ops !== void 0 || env.res !== void 0 || env.ack !== void 0) ctx.onOps({
57
59
  ops,
58
60
  ...res !== void 0 && { res },
59
61
  ...env.ack !== void 0 && { ack: env.ack }
60
62
  });
61
- c.hasSnapshot = true;
62
63
  };
63
- const isTransientFinish = (reason) => reason === "ended" || reason === "error";
64
+ const isTransientFinish = (reason) => reason === "evicted" || reason === "error";
64
65
  const settleEnvelope = (c, env) => {
65
66
  let finish = env.fin;
66
67
  if (finish) {
@@ -71,7 +72,7 @@ const settleEnvelope = (c, env) => {
71
72
  payload: reviveValue(rest.payload, meta)
72
73
  };
73
74
  }
74
- c.latest.current.ctx.onFinish(finish);
75
+ c.ctx.onFinish(finish);
75
76
  if (isTransientFinish(finish.reason)) {
76
77
  c.episode = {
77
78
  cause: finish.reason,
@@ -93,14 +94,14 @@ const settleEnvelope = (c, env) => {
93
94
  }
94
95
  return null;
95
96
  };
96
- const handleEnvelope = (c, env, attached) => {
97
- deliverEnvelope(c, env, attached);
97
+ const handleEnvelope = (c, env) => {
98
+ deliverEnvelope(c, env);
98
99
  return settleEnvelope(c, env);
99
100
  };
100
- const scheduleRetry = (c, failure, immediate, retryAfterMs) => {
101
+ const scheduleRetry = (c, failure, immediate, cause) => {
101
102
  c.attempt += 1;
102
103
  c.episode ??= { cause: "dropped" };
103
- const delay = immediate ? 0 : retryAfterMs ?? backoff(c.attempt);
104
+ const delay = immediate ? 0 : retryDelay(cause, c.attempt);
104
105
  if (c.hasSnapshot) setStatus(c, {
105
106
  status: "reconnecting",
106
107
  ...c.episode,
@@ -129,14 +130,14 @@ const run = async (c, lifetime, gate) => {
129
130
  const abort = new AbortController();
130
131
  c.abort = abort;
131
132
  let failure;
132
- let retryAfterMs;
133
+ let cause;
133
134
  let gone = false;
134
135
  try {
135
136
  gone = await c.attemptOnce(abort) === "stop";
136
137
  } catch (error) {
137
138
  if (!abort.signal.aborted) {
138
139
  failure = error instanceof Error && error.message ? error.message : "network";
139
- if (error instanceof Error && "retryAfterMs" in error && typeof error.retryAfterMs === "number") retryAfterMs = error.retryAfterMs;
140
+ cause = error;
140
141
  }
141
142
  }
142
143
  abort.abort();
@@ -146,48 +147,54 @@ const run = async (c, lifetime, gate) => {
146
147
  continue;
147
148
  }
148
149
  const immediate = gate.take();
149
- const delay = flushTapSync(() => scheduleRetry(c, failure, immediate, retryAfterMs));
150
+ const delay = flushTapSync(() => scheduleRetry(c, failure, immediate, cause));
150
151
  if (delay === 0) continue;
151
152
  await gate.wait(delay);
152
153
  }
153
154
  };
154
- const startConn = (c) => {
155
- c.hasSnapshot = false;
156
- c.lease = null;
157
- c.attempt = 0;
158
- c.episode = null;
159
- if (c.connection.status !== "connecting") setStatus(c, { status: "connecting" });
160
- c.lifetime = new AbortController();
161
- c.gate = createGate();
162
- run(c, c.lifetime, c.gate);
163
- };
164
- const stopConn = (c) => {
165
- c.abort?.abort();
166
- c.lifetime?.abort();
167
- c.lifetime = null;
168
- c.gate.open();
169
- };
170
- const useStatewireConn = (options, ctx, create) => {
171
- const latest = useRef({
172
- options,
173
- ctx
174
- });
175
- const [connection, setConnection] = useState(null);
176
- const [c] = useState(() => create(latest, setConnection));
177
- useEffect(() => {
178
- latest.current = {
179
- options,
180
- ctx
155
+ const useStatewireConn = (props) => {
156
+ const latest = useRef(props);
157
+ latest.current = props;
158
+ const [, setConnection] = useState(null);
159
+ const [c] = useState(() => {
160
+ const conn = {
161
+ hasSnapshot: false,
162
+ lease: null,
163
+ attempt: 0,
164
+ episode: null,
165
+ abort: null,
166
+ gate: createGate(),
167
+ lifetime: null,
168
+ ctx: props.ctx,
169
+ onChange: (connection) => latest.current.onChange?.(connection),
170
+ attemptOnce: (abort) => latest.current.attemptOnce(conn, abort),
171
+ notify: setConnection,
172
+ reconnect: () => reconnectConn(conn),
173
+ connection: {
174
+ status: "connecting",
175
+ reconnect: () => conn.reconnect()
176
+ }
181
177
  };
178
+ return conn;
182
179
  });
183
180
  useEffect(() => {
184
- startConn(c);
185
- return () => stopConn(c);
186
- }, [c, options.url]);
187
- return {
188
- connection: connection ?? c.connection,
189
- send: c.send
190
- };
181
+ c.hasSnapshot = false;
182
+ c.lease = null;
183
+ c.attempt = 0;
184
+ c.episode = null;
185
+ if (c.connection.status !== "connecting") setStatus(c, { status: "connecting" });
186
+ const lifetime = new AbortController();
187
+ c.lifetime = lifetime;
188
+ c.gate = createGate();
189
+ run(c, lifetime, c.gate);
190
+ return () => {
191
+ c.abort?.abort();
192
+ lifetime.abort();
193
+ if (c.lifetime === lifetime) c.lifetime = null;
194
+ c.gate.open();
195
+ };
196
+ }, [c, props.url]);
197
+ return c;
191
198
  };
192
199
  const classify = (timeout) => /* @__PURE__ */ new Error(timeout.aborted ? "timeout" : "network");
193
200
  const parseRetryAfter = (header) => {
@@ -199,6 +206,6 @@ const parseRetryAfter = (header) => {
199
206
  };
200
207
  const overloadedError = (retryAfterMs) => Object.assign(/* @__PURE__ */ new Error("overloaded"), { retryAfterMs });
201
208
  //#endregion
202
- export { classify, createGate, deliverEnvelope, handleEnvelope, isTransientFinish, overloadedError, parseRetryAfter, reconnectConn, scheduleRetry, setStatus, settleEnvelope, useStatewireConn };
209
+ export { classify, handleEnvelope, overloadedError, parseRetryAfter, useStatewireConn };
203
210
 
204
211
  //# sourceMappingURL=connection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"connection.js","names":["useEffect","useRef","useState","flushTapSync","reviveOps","reviveResponse","reviveValue","backoff","ConnectionState","RemoteLink","StatewireConnection","StatewireTransportProps","Episode","cause","message","StatewireFinish","reason","payload","meta","StatewireResponse","seq","type","code","StatewireSyn","lastSeq","lease","StatewireEnvelope","ops","res","ack","syn","fin","createGate","latched","wake","take","was","wait","timeoutMs","Promise","resolve","timer","undefined","setTimeout","clearTimeout","open","Gate","ReturnType","ConnBase","connection","hasSnapshot","attempt","episode","gate","abort","AbortController","lifetime","latest","current","options","onChange","ctx","notify","reconnect","attemptOnce","setStatus","c","next","changed","status","deliverEnvelope","env","Pick","attached","map","onSnapshot","onOps","isTransientFinish","settleEnvelope","finish","rest","onFinish","handleEnvelope","scheduleRetry","failure","immediate","retryAfterMs","delay","nextRetryAt","Date","now","lastError","reconnectConn","run","alive","gone","error","signal","aborted","Error","startConn","stopConn","useStatewireConn","url","TOptions","create","send","setConnection","classify","timeout","AbortSignal","parseRetryAfter","header","value","trim","test","Number","date","parse","isNaN","Math","max","overloadedError","Object","assign"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveResponse, reviveValue } from \"../wire/meta\";\nimport { backoff } from \"./timing\";\nimport type {\n ConnectionState,\n RemoteLink,\n StatewireConnection,\n StatewireTransportProps,\n} from \"../transports/sse\";\n\nexport type Episode = {\n cause: \"dropped\" | \"ended\" | \"error\";\n message?: string;\n};\n\nexport type StatewireFinish = {\n reason: \"ended\" | \"error\" | \"gone\" | \"superseded\" | (string & {});\n message?: string;\n payload?: unknown;\n meta?: unknown;\n};\n\nexport type StatewireResponse = {\n seq: number;\n type: \"accepted\" | \"rejected\" | \"pending\" | \"crashed\" | \"result-unavailable\";\n code?: string;\n message?: string;\n payload?: unknown;\n meta?: unknown;\n};\n\nexport type StatewireSyn = {\n lastSeq: number;\n lease?: string;\n};\n\nexport type StatewireEnvelope = {\n ops?: unknown[];\n res?: StatewireResponse[];\n ack?: number;\n syn?: StatewireSyn;\n fin?: StatewireFinish;\n};\n\nexport const createGate = () => {\n let latched = false;\n let wake: (() => void) | undefined;\n return {\n take: () => {\n const was = latched;\n latched = false;\n return was;\n },\n wait: (timeoutMs?: number) => {\n if (latched) {\n latched = false;\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n wake = undefined;\n resolve();\n }, timeoutMs);\n wake = () => {\n clearTimeout(timer);\n wake = undefined;\n resolve();\n };\n });\n },\n open: () => {\n if (wake) wake();\n else latched = true;\n },\n };\n};\n\nexport type Gate = ReturnType<typeof createGate>;\n\nexport type ConnBase = {\n connection: StatewireConnection;\n hasSnapshot: boolean;\n lease: string | null;\n attempt: number;\n episode: Episode | null;\n gate: Gate;\n abort: AbortController | null;\n lifetime: AbortController | null;\n latest: {\n readonly current: {\n options: { onChange?: (connection: StatewireConnection) => void };\n ctx: StatewireTransportProps;\n };\n };\n notify: (connection: StatewireConnection) => void;\n reconnect: () => void;\n attemptOnce: (\n abort: AbortController,\n ) => Promise<\"stop\" | \"reattach\" | \"ended\">;\n};\n\nexport const setStatus = (c: ConnBase, next: ConnectionState) => {\n const changed = next.status !== c.connection.status;\n c.connection = { ...next, reconnect: c.reconnect };\n c.notify(c.connection);\n if (changed) c.latest.current.options.onChange?.(c.connection);\n};\n\nexport const deliverEnvelope = (\n c: ConnBase,\n env: Pick<StatewireEnvelope, \"ops\" | \"res\" | \"ack\" | \"syn\">,\n attached: boolean,\n) => {\n if (env.syn?.lease !== undefined) c.lease = env.syn.lease;\n const ctx = c.latest.current.ctx;\n const ops = env.ops === undefined ? [] : reviveOps(env.ops);\n const res = env.res?.map(reviveResponse);\n if (!attached) {\n ctx.onSnapshot({ ops, lastSeq: env.syn?.lastSeq ?? -1 });\n } else if (\n env.ops !== undefined ||\n env.res !== undefined ||\n env.ack !== undefined\n ) {\n ctx.onOps({\n ops,\n ...(res !== undefined && { res }),\n ...(env.ack !== undefined && { ack: env.ack }),\n });\n }\n c.hasSnapshot = true;\n};\n\nexport const isTransientFinish = (\n reason: StatewireFinish[\"reason\"],\n): reason is \"ended\" | \"error\" => reason === \"ended\" || reason === \"error\";\n\nexport const settleEnvelope = (\n c: ConnBase,\n env: StatewireEnvelope,\n): \"stop\" | \"reattach\" | null => {\n let finish = env.fin;\n if (finish) {\n if (finish.meta !== undefined) {\n const { meta, ...rest } = finish;\n finish = { ...rest, payload: reviveValue(rest.payload, meta) };\n }\n c.latest.current.ctx.onFinish(finish);\n if (isTransientFinish(finish.reason)) {\n c.episode = {\n cause: finish.reason,\n ...(finish.message !== undefined && { message: finish.message }),\n };\n return \"reattach\";\n }\n setStatus(c, {\n status: \"gone\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.payload !== undefined && { payload: finish.payload }),\n });\n return \"stop\";\n }\n if (c.connection.status !== \"live\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"live\" });\n }\n return null;\n};\n\nexport const handleEnvelope = (\n c: ConnBase,\n env: StatewireEnvelope,\n attached: boolean,\n): \"stop\" | \"reattach\" | null => {\n deliverEnvelope(c, env, attached);\n return settleEnvelope(c, env);\n};\n\nexport const scheduleRetry = (\n c: ConnBase,\n failure: string | undefined,\n immediate: boolean,\n retryAfterMs?: number,\n) => {\n c.attempt += 1;\n c.episode ??= { cause: \"dropped\" };\n const delay = immediate ? 0 : (retryAfterMs ?? backoff(c.attempt));\n if (c.hasSnapshot) {\n setStatus(c, {\n status: \"reconnecting\",\n ...c.episode,\n attempt: c.attempt,\n nextRetryAt: Date.now() + delay,\n ...(failure !== undefined && { lastError: failure }),\n });\n }\n return delay;\n};\n\nexport const reconnectConn = (c: ConnBase) => {\n if (!c.lifetime) return;\n if (c.connection.status === \"gone\") {\n c.attempt = 0;\n c.episode = { cause: \"dropped\" };\n flushTapSync(() => {\n if (c.hasSnapshot) scheduleRetry(c, undefined, true);\n else setStatus(c, { status: \"connecting\" });\n });\n }\n c.gate.open();\n c.abort?.abort();\n};\n\nconst run = async (c: ConnBase, lifetime: AbortController, gate: Gate) => {\n const alive = () => c.lifetime === lifetime;\n while (alive()) {\n const abort = new AbortController();\n c.abort = abort;\n let failure: string | undefined;\n let retryAfterMs: number | undefined;\n let gone = false;\n try {\n gone = (await c.attemptOnce(abort)) === \"stop\";\n } catch (error) {\n if (!abort.signal.aborted) {\n failure =\n error instanceof Error && error.message ? error.message : \"network\";\n if (\n error instanceof Error &&\n \"retryAfterMs\" in error &&\n typeof error.retryAfterMs === \"number\"\n ) {\n retryAfterMs = error.retryAfterMs;\n }\n }\n }\n abort.abort();\n if (!alive()) return;\n if (gone) {\n await gate.wait();\n continue;\n }\n const immediate = gate.take();\n const delay = flushTapSync(() =>\n scheduleRetry(c, failure, immediate, retryAfterMs),\n );\n if (delay === 0) continue;\n await gate.wait(delay);\n }\n};\n\nconst startConn = (c: ConnBase) => {\n c.hasSnapshot = false;\n c.lease = null;\n c.attempt = 0;\n c.episode = null;\n if (c.connection.status !== \"connecting\") {\n setStatus(c, { status: \"connecting\" });\n }\n c.lifetime = new AbortController();\n c.gate = createGate();\n void run(c, c.lifetime, c.gate);\n};\n\nconst stopConn = (c: ConnBase) => {\n c.abort?.abort();\n c.lifetime?.abort();\n c.lifetime = null;\n c.gate.open();\n};\n\nexport const useStatewireConn = <\n TOptions extends {\n url: string;\n onChange?: (connection: StatewireConnection) => void;\n },\n>(\n options: TOptions,\n ctx: StatewireTransportProps,\n create: (\n latest: {\n readonly current: {\n options: TOptions;\n ctx: StatewireTransportProps;\n };\n },\n notify: (connection: StatewireConnection) => void,\n ) => ConnBase & { send: RemoteLink[\"send\"] },\n): RemoteLink => {\n const latest = useRef({ options, ctx });\n const [connection, setConnection] = useState<StatewireConnection | null>(\n null,\n );\n const [c] = useState(() => create(latest, setConnection));\n\n useEffect(() => {\n latest.current = { options, ctx };\n });\n useEffect(() => {\n startConn(c);\n return () => stopConn(c);\n }, [c, options.url]);\n\n return {\n connection: connection ?? c.connection,\n send: c.send,\n };\n};\n\nexport const classify = (timeout: AbortSignal) =>\n new Error(timeout.aborted ? \"timeout\" : \"network\");\n\nexport const parseRetryAfter = (header: string | null): number | undefined => {\n if (!header) return undefined;\n const value = header.trim();\n if (/^\\d+$/.test(value)) return Number(value) * 1000;\n const date = Date.parse(value);\n return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());\n};\n\nexport const overloadedError = (retryAfterMs?: number) =>\n Object.assign(new Error(\"overloaded\"), { retryAfterMs });\n"],"mappings":"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"}
1
+ {"version":3,"file":"connection.js","names":["useEffect","useRef","useState","flushTapSync","reviveOps","reviveResponse","reviveValue","retryDelay","ConnectionState","StatewireRemoteProps","StatewireClient","StatewireHost","Episode","cause","message","StatewireResponse","seq","type","code","payload","meta","StatewireSyn","lastSeq","lease","StatewireEnvelope","ops","res","ack","syn","fin","Fin","createGate","latched","wake","take","was","wait","timeoutMs","Promise","resolve","timer","undefined","setTimeout","clearTimeout","open","Gate","ReturnType","Conn","connection","Connection","hasSnapshot","attempt","episode","gate","abort","AbortController","lifetime","ctx","onChange","attemptOnce","notify","reconnect","setStatus","c","next","changed","status","deliverEnvelope","env","Pick","map","onSnapshot","onOps","isTransientFinish","reason","settleEnvelope","finish","rest","onFinish","handleEnvelope","scheduleRetry","failure","immediate","delay","nextRetryAt","Date","now","lastError","reconnectConn","run","alive","gone","error","signal","aborted","Error","useStatewireConn","props","url","latest","current","setConnection","conn","classify","timeout","AbortSignal","parseRetryAfter","header","value","trim","test","Number","date","parse","isNaN","Math","max","overloadedError","retryAfterMs","Object","assign"],"sources":["../../src/client/connection.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { flushTapSync } from \"@assistant-ui/tap\";\nimport { reviveOps, reviveResponse, reviveValue } from \"../wire/meta\";\nimport { retryDelay } from \"./timing\";\nimport type { ConnectionState, StatewireRemoteProps } from \"../transports/sse\";\nimport type { StatewireClient } from \"../statewire\";\nimport type { StatewireHost } from \"../host\";\n\nexport type Episode = {\n cause: \"dropped\" | \"evicted\" | \"error\";\n message?: string;\n};\n\nexport type StatewireResponse = {\n seq: number;\n type: \"accepted\" | \"rejected\" | \"pending\" | \"crashed\" | \"result-unavailable\";\n code?: string;\n message?: string;\n payload?: unknown;\n meta?: unknown;\n};\n\nexport type StatewireSyn = {\n lastSeq: number;\n lease?: string;\n};\n\nexport type StatewireEnvelope = {\n ops?: unknown[];\n res?: StatewireResponse[];\n ack?: number;\n syn?: StatewireSyn;\n fin?: StatewireHost.Fin;\n};\n\nconst createGate = () => {\n let latched = false;\n let wake: (() => void) | undefined;\n return {\n take: () => {\n const was = latched;\n latched = false;\n return was;\n },\n wait: (timeoutMs?: number) => {\n if (latched) {\n latched = false;\n return Promise.resolve();\n }\n return new Promise<void>((resolve) => {\n const timer =\n timeoutMs === undefined\n ? undefined\n : setTimeout(() => {\n wake = undefined;\n resolve();\n }, timeoutMs);\n wake = () => {\n clearTimeout(timer);\n wake = undefined;\n resolve();\n };\n });\n },\n open: () => {\n if (wake) wake();\n else latched = true;\n },\n };\n};\n\nexport type Gate = ReturnType<typeof createGate>;\n\nexport type Conn = {\n connection: StatewireClient.Connection;\n hasSnapshot: boolean;\n lease: string | null;\n attempt: number;\n episode: Episode | null;\n gate: Gate;\n abort: AbortController | null;\n lifetime: AbortController | null;\n ctx: StatewireRemoteProps;\n onChange: (connection: StatewireClient.Connection) => void;\n attemptOnce: (\n abort: AbortController,\n ) => Promise<\"stop\" | \"reattach\" | \"ended\">;\n notify: (connection: StatewireClient.Connection) => void;\n reconnect: () => void;\n};\n\nconst setStatus = (c: Conn, next: ConnectionState) => {\n const changed = next.status !== c.connection.status;\n c.connection = { ...next, reconnect: c.reconnect };\n c.notify(c.connection);\n if (changed) c.onChange(c.connection);\n};\n\nconst deliverEnvelope = (\n c: Conn,\n env: Pick<StatewireEnvelope, \"ops\" | \"res\" | \"ack\" | \"syn\">,\n) => {\n if (env.syn?.lease !== undefined) c.lease = env.syn.lease;\n const ctx = c.ctx;\n const ops = env.ops === undefined ? [] : reviveOps(env.ops);\n const res = env.res?.map(reviveResponse);\n if (env.syn !== undefined) {\n ctx.onSnapshot({ ops, lastSeq: env.syn.lastSeq });\n c.hasSnapshot = true;\n } else if (\n env.ops !== undefined ||\n env.res !== undefined ||\n env.ack !== undefined\n ) {\n ctx.onOps({\n ops,\n ...(res !== undefined && { res }),\n ...(env.ack !== undefined && { ack: env.ack }),\n });\n }\n};\n\nconst isTransientFinish = (\n reason: StatewireHost.Fin[\"reason\"],\n): reason is \"evicted\" | \"error\" => reason === \"evicted\" || reason === \"error\";\n\nconst settleEnvelope = (\n c: Conn,\n env: StatewireEnvelope,\n): \"stop\" | \"reattach\" | null => {\n let finish = env.fin;\n if (finish) {\n if (finish.meta !== undefined) {\n const { meta, ...rest } = finish;\n finish = { ...rest, payload: reviveValue(rest.payload, meta) };\n }\n c.ctx.onFinish(finish);\n if (isTransientFinish(finish.reason)) {\n c.episode = {\n cause: finish.reason,\n ...(finish.message !== undefined && { message: finish.message }),\n };\n return \"reattach\";\n }\n setStatus(c, {\n status: \"gone\",\n ...(finish.message !== undefined && { message: finish.message }),\n ...(finish.payload !== undefined && { payload: finish.payload }),\n });\n return \"stop\";\n }\n if (c.connection.status !== \"live\") {\n c.attempt = 0;\n c.episode = null;\n setStatus(c, { status: \"live\" });\n }\n return null;\n};\n\nexport const handleEnvelope = (\n c: Conn,\n env: StatewireEnvelope,\n): \"stop\" | \"reattach\" | null => {\n deliverEnvelope(c, env);\n return settleEnvelope(c, env);\n};\n\nconst scheduleRetry = (\n c: Conn,\n failure: string | undefined,\n immediate: boolean,\n cause?: unknown,\n) => {\n c.attempt += 1;\n c.episode ??= { cause: \"dropped\" };\n const delay = immediate ? 0 : retryDelay(cause, c.attempt);\n if (c.hasSnapshot) {\n setStatus(c, {\n status: \"reconnecting\",\n ...c.episode,\n attempt: c.attempt,\n nextRetryAt: Date.now() + delay,\n ...(failure !== undefined && { lastError: failure }),\n });\n }\n return delay;\n};\n\nconst reconnectConn = (c: Conn) => {\n if (!c.lifetime) return;\n if (c.connection.status === \"gone\") {\n c.attempt = 0;\n c.episode = { cause: \"dropped\" };\n flushTapSync(() => {\n if (c.hasSnapshot) scheduleRetry(c, undefined, true);\n else setStatus(c, { status: \"connecting\" });\n });\n }\n c.gate.open();\n c.abort?.abort();\n};\n\nconst run = async (c: Conn, lifetime: AbortController, gate: Gate) => {\n const alive = () => c.lifetime === lifetime;\n while (alive()) {\n const abort = new AbortController();\n c.abort = abort;\n let failure: string | undefined;\n let cause: unknown;\n let gone = false;\n try {\n gone = (await c.attemptOnce(abort)) === \"stop\";\n } catch (error) {\n if (!abort.signal.aborted) {\n failure =\n error instanceof Error && error.message ? error.message : \"network\";\n cause = error;\n }\n }\n abort.abort();\n if (!alive()) return;\n if (gone) {\n await gate.wait();\n continue;\n }\n const immediate = gate.take();\n const delay = flushTapSync(() =>\n scheduleRetry(c, failure, immediate, cause),\n );\n if (delay === 0) continue;\n await gate.wait(delay);\n }\n};\n\nexport const useStatewireConn = (props: {\n url: string;\n onChange?: ((connection: StatewireClient.Connection) => void) | undefined;\n ctx: StatewireRemoteProps;\n attemptOnce: (\n c: Conn,\n abort: AbortController,\n ) => Promise<\"stop\" | \"reattach\" | \"ended\">;\n}): Conn => {\n const latest = useRef(props);\n latest.current = props;\n const [, setConnection] = useState<StatewireClient.Connection | null>(null);\n const [c] = useState((): Conn => {\n const conn: Conn = {\n hasSnapshot: false,\n lease: null,\n attempt: 0,\n episode: null,\n abort: null,\n gate: createGate(),\n lifetime: null,\n ctx: props.ctx,\n onChange: (connection) => latest.current.onChange?.(connection),\n attemptOnce: (abort) => latest.current.attemptOnce(conn, abort),\n notify: setConnection,\n reconnect: () => reconnectConn(conn),\n connection: { status: \"connecting\", reconnect: () => conn.reconnect() },\n };\n return conn;\n });\n\n useEffect(() => {\n c.hasSnapshot = false;\n c.lease = null;\n c.attempt = 0;\n c.episode = null;\n if (c.connection.status !== \"connecting\") {\n setStatus(c, { status: \"connecting\" });\n }\n const lifetime = new AbortController();\n c.lifetime = lifetime;\n c.gate = createGate();\n void run(c, lifetime, c.gate);\n return () => {\n c.abort?.abort();\n lifetime.abort();\n if (c.lifetime === lifetime) c.lifetime = null;\n c.gate.open();\n };\n }, [c, props.url]);\n\n return c;\n};\n\nexport const classify = (timeout: AbortSignal) =>\n new Error(timeout.aborted ? \"timeout\" : \"network\");\n\nexport const parseRetryAfter = (header: string | null): number | undefined => {\n if (!header) return undefined;\n const value = header.trim();\n if (/^\\d+$/.test(value)) return Number(value) * 1000;\n const date = Date.parse(value);\n return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());\n};\n\nexport const overloadedError = (retryAfterMs?: number) =>\n Object.assign(new Error(\"overloaded\"), { retryAfterMs });\n"],"mappings":"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"}
@@ -1,18 +1,14 @@
1
- import { StatewireConnection } from "../transports/sse.js";
2
- import { StatewireCommandsProxy, StatewireOptions, StatewireTransport } from "../types.js";
1
+ import { StatewireClient } from "../statewire.js";
2
+ import { Statewire } from "../types.js";
3
3
  //#region src/client/core.d.ts
4
- declare const LIVE_CONNECTION: StatewireConnection;
5
- type StatewireCore = ReturnType<typeof createStatewireCore>;
6
- declare const createStatewireCore: (getOptions: () => StatewireOptions<any, any, any>) => {
7
- attach: (next: StatewireTransport<unknown>) => void;
4
+ declare const LIVE_CONNECTION: StatewireClient.Connection;
5
+ declare const useStatewireCore: (getOptions: () => StatewireClient.Options<any, any, any>, value: Statewire<unknown>) => {
6
+ attach: (next: Statewire<unknown>) => void;
8
7
  detach: () => void;
9
- dispose: () => void;
10
8
  getState: () => unknown;
11
- getConnection: () => StatewireConnection;
12
- commands: StatewireCommandsProxy<any>;
13
- flush: () => void;
9
+ commands: Statewire.CommandsProxy<any>;
14
10
  subscribe: (listener: () => void) => () => void;
15
11
  };
16
12
  //#endregion
17
- export { LIVE_CONNECTION, StatewireCore, createStatewireCore };
13
+ export { LIVE_CONNECTION, useStatewireCore };
18
14
  //# sourceMappingURL=core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"core.d.ts","names":[],"sources":["../../src/client/core.ts"],"mappings":";;;cAkBa,iBAAiB;KA0ClB,gBAAgB,kBAAkB;cAEjC,sBACX,kBAAkB;EA8LI,SAAA,MAAA;;;;EAtGI,qBAAA;;;EA2LF,YAAA"}
1
+ {"version":3,"file":"core.d.ts","names":[],"sources":["../../src/client/core.ts"],"mappings":";;;cAYa,iBAAiB,gBAAgB;cA6RjC,mBACX,kBAAkB,gBAAgB,wBAClC,OAAO;EAjFe,SAAA,MAAA;;;;EAsEE,YAAA"}