agents 0.22.0 → 0.24.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.
Files changed (215) hide show
  1. package/README.md +20 -1
  2. package/dist/{agent-routing-CnkaHb-v.d.ts → agent-routing-B2XLNMxq.d.ts} +1094 -443
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +26 -26
  5. package/dist/{agent-tools-C0XJqWzB.d.ts → agent-tools-Dj5Mzlw7.d.ts} +7 -7
  6. package/dist/agent-tools.d.ts +21 -21
  7. package/dist/browser/ai.js +4 -1
  8. package/dist/browser/ai.js.map +1 -1
  9. package/dist/browser/tanstack-ai.js.map +1 -1
  10. package/dist/callable-decorator-DP__HhBA.d.ts +72 -0
  11. package/dist/callable-decorator.d.ts +18 -0
  12. package/dist/callable-decorator.js +71 -0
  13. package/dist/callable-decorator.js.map +1 -0
  14. package/dist/{capability-BjSKYpzg.js → capability-B4WbF81e.js} +2 -1
  15. package/dist/capability-B4WbF81e.js.map +1 -0
  16. package/dist/capability-runner-BUBa6Ake.d.ts +484 -0
  17. package/dist/channel-Bnm4S7T2.d.ts +491 -0
  18. package/dist/channels/ai-sdk.d.ts +46 -0
  19. package/dist/channels/ai-sdk.js +120 -0
  20. package/dist/channels/ai-sdk.js.map +1 -0
  21. package/dist/channels/email.d.ts +95 -0
  22. package/dist/channels/email.js +323 -0
  23. package/dist/channels/email.js.map +1 -0
  24. package/dist/channels/index.d.ts +233 -0
  25. package/dist/channels/index.js +608 -0
  26. package/dist/channels/index.js.map +1 -0
  27. package/dist/channels/slack.d.ts +140 -0
  28. package/dist/channels/slack.js +614 -0
  29. package/dist/channels/slack.js.map +1 -0
  30. package/dist/channels/tanstack-ai.d.ts +39 -0
  31. package/dist/channels/tanstack-ai.js +17 -0
  32. package/dist/channels/tanstack-ai.js.map +1 -0
  33. package/dist/channels/telegram.d.ts +106 -0
  34. package/dist/channels/telegram.js +427 -0
  35. package/dist/channels/telegram.js.map +1 -0
  36. package/dist/channels/voice.d.ts +45 -0
  37. package/dist/channels/voice.js +122 -0
  38. package/dist/channels/voice.js.map +1 -0
  39. package/dist/chat/index.d.ts +2319 -2010
  40. package/dist/chat/index.js +892 -518
  41. package/dist/chat/index.js.map +1 -1
  42. package/dist/chat-sdk/index.d.ts +7 -7
  43. package/dist/chat-sdk/index.js +1 -1
  44. package/dist/client-BxdkCuVy.d.ts +411 -0
  45. package/dist/client-C9DAjZIY.js +518 -0
  46. package/dist/client-C9DAjZIY.js.map +1 -0
  47. package/dist/{client-jagG8a9_.js → client-fyQrLGkD.js} +2 -2
  48. package/dist/{client-jagG8a9_.js.map → client-fyQrLGkD.js.map} +1 -1
  49. package/dist/client.d.ts +27 -283
  50. package/dist/client.js +2 -274
  51. package/dist/context/index.d.ts +216 -0
  52. package/dist/context/index.js +454 -0
  53. package/dist/context/index.js.map +1 -0
  54. package/dist/current-agent-C4w86kcN.d.ts +93 -0
  55. package/dist/current-agent-DhoDkSnH.js.map +1 -1
  56. package/dist/{diagnostics-CaBjfz4J.js → diagnostics-BzvaX2UT.js} +5 -1
  57. package/dist/diagnostics-BzvaX2UT.js.map +1 -0
  58. package/dist/diagnostics-C4jcz3VK.js +360 -0
  59. package/dist/diagnostics-C4jcz3VK.js.map +1 -0
  60. package/dist/durable-object-lifecycle-ei7M7lqB.d.ts +157 -0
  61. package/dist/index-BB0kqhIz.d.ts +101 -0
  62. package/dist/index-BVVgDSdq.d.ts +1 -0
  63. package/dist/index-Dlgtd3Mj.d.ts +78 -0
  64. package/dist/index-XDkuQ7zm.d.ts +89 -0
  65. package/dist/{index-DcSAZKsB.d.ts → index-YSKgfgg9.d.ts} +3 -1
  66. package/dist/index.d.ts +92 -83
  67. package/dist/index.js +4 -3
  68. package/dist/ingress-BfetZbMO.js +83 -0
  69. package/dist/ingress-BfetZbMO.js.map +1 -0
  70. package/dist/internal-CYlgHl1l.js +59 -0
  71. package/dist/internal-CYlgHl1l.js.map +1 -0
  72. package/dist/internal_context.d.ts +1 -1
  73. package/dist/lifecycle/index.d.ts +39 -19
  74. package/dist/lifecycle/index.js +2 -2
  75. package/dist/lifecycle-Mm_jQh7r.js +1314 -0
  76. package/dist/lifecycle-Mm_jQh7r.js.map +1 -0
  77. package/dist/mcp/client/index.d.ts +20 -20
  78. package/dist/mcp/client/index.js +1 -1
  79. package/dist/mcp/index.d.ts +35 -35
  80. package/dist/mcp/index.js +2 -2
  81. package/dist/observability/index.d.ts +1 -1
  82. package/dist/observability/index.js +1 -1
  83. package/dist/queue/index.d.ts +123 -0
  84. package/dist/queue/index.js +2 -0
  85. package/dist/queue-BC9F5cUo.js +406 -0
  86. package/dist/queue-BC9F5cUo.js.map +1 -0
  87. package/dist/react.d.ts +34 -16
  88. package/dist/react.js +31 -8
  89. package/dist/react.js.map +1 -1
  90. package/dist/{retries-CAvxtG9d.d.ts → retries-D9B2UCq3.d.ts} +23 -6
  91. package/dist/retries.d.ts +10 -6
  92. package/dist/retries.js +21 -1
  93. package/dist/retries.js.map +1 -1
  94. package/dist/routing/index.d.ts +137 -0
  95. package/dist/routing/index.js +244 -0
  96. package/dist/routing/index.js.map +1 -0
  97. package/dist/sanitize-D9TujEK8.js +79 -0
  98. package/dist/sanitize-D9TujEK8.js.map +1 -0
  99. package/dist/{scheduler-DQoTGoAW.d.ts → scheduler-BGq6M5Kd.d.ts} +20 -21
  100. package/dist/scheduler-D_KHqxBa.js +658 -0
  101. package/dist/scheduler-D_KHqxBa.js.map +1 -0
  102. package/dist/schedules/index.d.ts +1 -1
  103. package/dist/schedules/index.js +1 -1
  104. package/dist/sentence-chunker-BAidJ4DA.d.ts +68 -0
  105. package/dist/serializable.d.ts +1 -1
  106. package/dist/sessions/index.d.ts +441 -0
  107. package/dist/sessions/index.js +2063 -0
  108. package/dist/sessions/index.js.map +1 -0
  109. package/dist/skills/index.d.ts +99 -0
  110. package/dist/skills/index.js +254 -5
  111. package/dist/skills/index.js.map +1 -1
  112. package/dist/{src-5W6JNKVb.js → src-BNU3ZiJM.js} +1524 -1441
  113. package/dist/src-BNU3ZiJM.js.map +1 -0
  114. package/dist/state/index.d.ts +6 -0
  115. package/dist/state/index.js +137 -0
  116. package/dist/state/index.js.map +1 -0
  117. package/dist/streams/index.d.ts +120 -0
  118. package/dist/streams/index.js +107 -0
  119. package/dist/streams/index.js.map +1 -0
  120. package/dist/streams-BcE8JP2X.d.ts +370 -0
  121. package/dist/streams-CCPRV6dt.js +709 -0
  122. package/dist/streams-CCPRV6dt.js.map +1 -0
  123. package/dist/sub-routing.d.ts +12 -12
  124. package/dist/surface-bZZJqBka.js +17 -0
  125. package/dist/surface-bZZJqBka.js.map +1 -0
  126. package/dist/tasks/index.d.ts +64 -0
  127. package/dist/tasks/index.js +2 -0
  128. package/dist/tasks-D4nLqVSI.js +1656 -0
  129. package/dist/tasks-D4nLqVSI.js.map +1 -0
  130. package/dist/tasks-V2lCT8ZV.d.ts +517 -0
  131. package/dist/text-segment-joiner-BtAFQSA_.js +57 -0
  132. package/dist/text-segment-joiner-BtAFQSA_.js.map +1 -0
  133. package/dist/text-stream-CpdiKrJB.js +272 -0
  134. package/dist/text-stream-CpdiKrJB.js.map +1 -0
  135. package/dist/tokens-nHAKcN6M.js +52 -0
  136. package/dist/tokens-nHAKcN6M.js.map +1 -0
  137. package/dist/tool-schema-CBjGPrsQ.js +31 -0
  138. package/dist/tool-schema-CBjGPrsQ.js.map +1 -0
  139. package/dist/transport-protocol-BxyngQ_R.js +25 -0
  140. package/dist/transport-protocol-BxyngQ_R.js.map +1 -0
  141. package/dist/transport-protocol-ZTew5Wso.d.ts +27 -0
  142. package/dist/types-B7LojTe4.d.ts +202 -0
  143. package/dist/types-DCD6BNZH.d.ts +70 -0
  144. package/dist/types-_Faxb570.d.ts +439 -0
  145. package/dist/voice/client.d.ts +226 -0
  146. package/dist/voice/client.js +932 -0
  147. package/dist/voice/client.js.map +1 -0
  148. package/dist/voice/errors.d.ts +43 -0
  149. package/dist/voice/errors.js +41 -0
  150. package/dist/voice/errors.js.map +1 -0
  151. package/dist/voice/index.d.ts +271 -0
  152. package/dist/voice/index.js +1812 -0
  153. package/dist/voice/index.js.map +1 -0
  154. package/dist/voice/react.d.ts +167 -0
  155. package/dist/voice/react.js +234 -0
  156. package/dist/voice/react.js.map +1 -0
  157. package/dist/voice/sfu.d.ts +71 -0
  158. package/dist/voice/sfu.js +157 -0
  159. package/dist/voice/sfu.js.map +1 -0
  160. package/dist/voice/text.d.ts +6 -0
  161. package/dist/voice/text.js +2 -0
  162. package/dist/voice/types.d.ts +58 -0
  163. package/dist/voice/types.js +18 -0
  164. package/dist/voice/types.js.map +1 -0
  165. package/dist/voice/workers-ai.d.ts +136 -0
  166. package/dist/voice/workers-ai.js +568 -0
  167. package/dist/voice/workers-ai.js.map +1 -0
  168. package/dist/websockets/index.d.ts +301 -0
  169. package/dist/websockets/index.js +3 -0
  170. package/dist/websockets-D7IzWbZb.js +1005 -0
  171. package/dist/websockets-D7IzWbZb.js.map +1 -0
  172. package/dist/workflow-types.d.ts +25 -25
  173. package/dist/workflows.d.ts +21 -21
  174. package/dist/workflows.js +1 -1
  175. package/docs/agent-class.md +4 -4
  176. package/docs/agent-tools.md +2 -1
  177. package/docs/channels.md +323 -0
  178. package/docs/chat-agents.md +6 -13
  179. package/docs/client-sdk.md +30 -0
  180. package/docs/context.md +131 -0
  181. package/docs/index.md +16 -13
  182. package/docs/lifecycle.md +179 -57
  183. package/docs/long-running-agents.md +2 -2
  184. package/docs/mcp-servers.md +5 -1
  185. package/docs/queue.md +135 -241
  186. package/docs/resumable-streaming.md +1 -1
  187. package/docs/retries.md +1 -1
  188. package/docs/routing.md +105 -0
  189. package/docs/sessions.md +237 -871
  190. package/docs/streams.md +213 -0
  191. package/docs/sub-agents.md +184 -124
  192. package/docs/tasks.md +246 -0
  193. package/docs/voice.md +745 -0
  194. package/package.json +126 -14
  195. package/dist/capability-BjSKYpzg.js.map +0 -1
  196. package/dist/capability-runner-CvHGZqUu.d.ts +0 -150
  197. package/dist/client.js.map +0 -1
  198. package/dist/compaction-helpers-iiKMr2TQ.js +0 -340
  199. package/dist/compaction-helpers-iiKMr2TQ.js.map +0 -1
  200. package/dist/compaction-helpers-wUz6M3us.d.ts +0 -621
  201. package/dist/current-agent-CuMErtly.d.ts +0 -283
  202. package/dist/diagnostics-CaBjfz4J.js.map +0 -1
  203. package/dist/durable-object-lifecycle-D6nNQJJd.js +0 -862
  204. package/dist/durable-object-lifecycle-D6nNQJJd.js.map +0 -1
  205. package/dist/experimental/memory/session/index.d.ts +0 -671
  206. package/dist/experimental/memory/session/index.js +0 -2379
  207. package/dist/experimental/memory/session/index.js.map +0 -1
  208. package/dist/experimental/memory/utils/index.d.ts +0 -96
  209. package/dist/experimental/memory/utils/index.js +0 -79
  210. package/dist/experimental/memory/utils/index.js.map +0 -1
  211. package/dist/scheduler-CR9RHGos.js +0 -857
  212. package/dist/scheduler-CR9RHGos.js.map +0 -1
  213. package/dist/src-5W6JNKVb.js.map +0 -1
  214. package/dist/tool-output-truncation-CNnnGZQ3.js +0 -98
  215. package/dist/tool-output-truncation-CNnnGZQ3.js.map +0 -1
@@ -0,0 +1,6 @@
1
+ import {
2
+ n as StateChangeSource,
3
+ r as StateOptions,
4
+ t as State
5
+ } from "../index-Dlgtd3Mj.js";
6
+ export { State, StateChangeSource, StateOptions };
@@ -0,0 +1,137 @@
1
+ import { i as _classPrivateFieldInitSpec, n as _classPrivateFieldSet2, r as _assertClassBrand, t as _classPrivateFieldGet2 } from "../classPrivateFieldGet2-DZBYAB34.js";
2
+ import { t as LifecycleCapability } from "../capability-B4WbF81e.js";
3
+ import { t as _classPrivateMethodInitSpec } from "../classPrivateMethodInitSpec-qMjJ6sHQ.js";
4
+ //#region src/state/index.ts
5
+ /**
6
+ * Namespaced KV key holding this capability's schema version. Kept separate
7
+ * from the host's global schema version so State owns its own migrations
8
+ * without gating the host's DDL.
9
+ */
10
+ const STATE_SCHEMA_VERSION_KEY = "cf_agents:state_schema_version";
11
+ const CURRENT_STATE_SCHEMA_VERSION = 1;
12
+ /** Row id under which the single state value is stored in `cf_agents_state`. */
13
+ const STATE_ROW_ID = "cf_state_row_id";
14
+ /**
15
+ * Legacy row written by SDKs that predate the single-row state optimization.
16
+ * Never written now; the v1 migration deletes it.
17
+ */
18
+ const LEGACY_WAS_CHANGED_ROW_ID = "cf_state_was_changed";
19
+ /**
20
+ * Sentinel distinguishing "state not yet loaded / never set" from a stored
21
+ * value. A distinct object reference means falsy states (null, 0, false, "")
22
+ * still read back as set.
23
+ */
24
+ const DEFAULT_STATE = {};
25
+ var _state = /* @__PURE__ */ new WeakMap();
26
+ var _tableEnsured = /* @__PURE__ */ new WeakMap();
27
+ var _options = /* @__PURE__ */ new WeakMap();
28
+ var _State_brand = /* @__PURE__ */ new WeakSet();
29
+ /**
30
+ * Durable state storage for a Lifecycle Object.
31
+ *
32
+ * Owns the `cf_agents_state` state row, lazy load with an in-memory cache, and
33
+ * validated persistence. Install the instance with `Lifecycle.use()`. State
34
+ * validation and the post-change notification hook stay on the host, which
35
+ * injects both callbacks. This capability never touches connections.
36
+ *
37
+ * @experimental The API surface may change before stabilizing.
38
+ */
39
+ var State = class extends LifecycleCapability {
40
+ /**
41
+ * Create a durable state capability.
42
+ *
43
+ * @param options - Optional initial state and a synchronous validation hook
44
+ * injected by the host.
45
+ */
46
+ constructor(options = {}) {
47
+ super("state");
48
+ _classPrivateMethodInitSpec(this, _State_brand);
49
+ _classPrivateFieldInitSpec(this, _state, DEFAULT_STATE);
50
+ _classPrivateFieldInitSpec(this, _tableEnsured, false);
51
+ _classPrivateFieldInitSpec(this, _options, void 0);
52
+ _classPrivateFieldSet2(_options, this, options);
53
+ }
54
+ /** Initialize state storage during Lifecycle startup. */
55
+ async onStart() {
56
+ if ((await this.lifecycle.storage.get(STATE_SCHEMA_VERSION_KEY) ?? 0) >= CURRENT_STATE_SCHEMA_VERSION) {
57
+ _classPrivateFieldSet2(_tableEnsured, this, true);
58
+ return;
59
+ }
60
+ _assertClassBrand(_State_brand, this, _ensureTable).call(this);
61
+ this.lifecycle.storage.sql.exec("DELETE FROM cf_agents_state WHERE id = ?", LEGACY_WAS_CHANGED_ROW_ID);
62
+ await this.lifecycle.storage.put(STATE_SCHEMA_VERSION_KEY, CURRENT_STATE_SCHEMA_VERSION);
63
+ }
64
+ /**
65
+ * Current state.
66
+ *
67
+ * Loads lazily from storage on first access and caches in memory. Row
68
+ * existence in `cf_agents_state` is the signal that state was previously
69
+ * set, so falsy values persist correctly. On a corrupt row, falls back to
70
+ * the initial state (re-persisting it) or clears the row.
71
+ */
72
+ get() {
73
+ if (_classPrivateFieldGet2(_state, this) !== DEFAULT_STATE) return _classPrivateFieldGet2(_state, this);
74
+ _assertClassBrand(_State_brand, this, _ensureTable).call(this);
75
+ const result = this.lifecycle.storage.sql.exec("SELECT state FROM cf_agents_state WHERE id = ?", STATE_ROW_ID).toArray();
76
+ if (result.length > 0) {
77
+ const state = result[0].state;
78
+ try {
79
+ _classPrivateFieldSet2(_state, this, JSON.parse(state));
80
+ } catch (e) {
81
+ console.error("Failed to parse stored state, falling back to initialState:", e);
82
+ const initial = _classPrivateFieldGet2(_options, this).initialState;
83
+ if (initial !== void 0) {
84
+ _classPrivateFieldSet2(_state, this, initial);
85
+ this.set(initial, "server");
86
+ } else {
87
+ this.lifecycle.storage.sql.exec("DELETE FROM cf_agents_state WHERE id = ?", STATE_ROW_ID);
88
+ return;
89
+ }
90
+ }
91
+ return _classPrivateFieldGet2(_state, this);
92
+ }
93
+ const initial = _classPrivateFieldGet2(_options, this).initialState;
94
+ if (initial === void 0) return;
95
+ this.set(initial, "server");
96
+ return initial;
97
+ }
98
+ /**
99
+ * Validate and persist a state change, then call the change hook.
100
+ *
101
+ * @param nextState - The new state to persist.
102
+ * @param source - `"server"` for host-originated changes, or the originating
103
+ * connection for client-originated changes.
104
+ * @throws Whatever the injected `validateStateChange` throws.
105
+ */
106
+ set(nextState, source = "server") {
107
+ _classPrivateFieldGet2(_options, this).validateStateChange?.(nextState, source);
108
+ _assertClassBrand(_State_brand, this, _ensureTable).call(this);
109
+ const serialized = JSON.stringify(nextState);
110
+ this.lifecycle.storage.sql.exec("INSERT OR REPLACE INTO cf_agents_state (id, state) VALUES (?, ?)", STATE_ROW_ID, serialized);
111
+ _classPrivateFieldSet2(_state, this, nextState);
112
+ let pending;
113
+ try {
114
+ pending = _classPrivateFieldGet2(_options, this).onChanged?.(nextState, source);
115
+ } catch (error) {
116
+ console.error("State onChanged hook failed:", error);
117
+ return;
118
+ }
119
+ if (pending) Promise.resolve(pending).catch((error) => {
120
+ console.error("State onChanged hook failed:", error);
121
+ });
122
+ }
123
+ };
124
+ function _ensureTable() {
125
+ if (_classPrivateFieldGet2(_tableEnsured, this)) return;
126
+ this.lifecycle.storage.sql.exec(`
127
+ CREATE TABLE IF NOT EXISTS cf_agents_state (
128
+ id TEXT PRIMARY KEY NOT NULL,
129
+ state TEXT
130
+ )
131
+ `);
132
+ _classPrivateFieldSet2(_tableEnsured, this, true);
133
+ }
134
+ //#endregion
135
+ export { State };
136
+
137
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/state/index.ts"],"sourcesContent":["import { LifecycleCapability } from \"../lifecycle/capability\";\nimport type { Connection } from \"../lifecycle/durable-object-lifecycle\";\n\n/**\n * Source of a state change: `\"server\"` for host code (e.g. `setState()`), or\n * the {@link Connection} the change arrived from. Hosts use it to exclude the\n * originating connection from a broadcast.\n */\nexport type StateChangeSource = Connection | \"server\";\n\n/**\n * Options for a {@link State} capability. Validation and the post-change hook\n * stay on the host, which passes them in; the capability owns storage and\n * change ordering.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport interface StateOptions<T = unknown> {\n /** Seeded on first access when nothing is stored. `undefined` seeds nothing. */\n readonly initialState?: T;\n\n /** Called after a change is validated and persisted. May be async. */\n readonly onChanged?: (\n state: T,\n source: StateChangeSource\n ) => void | Promise<void>;\n\n /**\n * Synchronous gating hook run before a change is persisted. Throw to reject\n * the change; the throw propagates to the caller of {@link State.set}.\n */\n readonly validateStateChange?: (\n nextState: T,\n source: StateChangeSource\n ) => void;\n}\n\n/**\n * Namespaced KV key holding this capability's schema version. Kept separate\n * from the host's global schema version so State owns its own migrations\n * without gating the host's DDL.\n */\nconst STATE_SCHEMA_VERSION_KEY = \"cf_agents:state_schema_version\";\nconst CURRENT_STATE_SCHEMA_VERSION = 1;\n\n/** Row id under which the single state value is stored in `cf_agents_state`. */\nconst STATE_ROW_ID = \"cf_state_row_id\";\n\n/**\n * Legacy row written by SDKs that predate the single-row state optimization.\n * Never written now; the v1 migration deletes it.\n */\nconst LEGACY_WAS_CHANGED_ROW_ID = \"cf_state_was_changed\";\n\n/**\n * Sentinel distinguishing \"state not yet loaded / never set\" from a stored\n * value. A distinct object reference means falsy states (null, 0, false, \"\")\n * still read back as set.\n */\nconst DEFAULT_STATE = {} as unknown;\n\n/**\n * Durable state storage for a Lifecycle Object.\n *\n * Owns the `cf_agents_state` state row, lazy load with an in-memory cache, and\n * validated persistence. Install the instance with `Lifecycle.use()`. State\n * validation and the post-change notification hook stay on the host, which\n * injects both callbacks. This capability never touches connections.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport class State<T = unknown> extends LifecycleCapability {\n #state = DEFAULT_STATE as T;\n #tableEnsured = false;\n readonly #options: StateOptions<T>;\n\n /**\n * Create a durable state capability.\n *\n * @param options - Optional initial state and a synchronous validation hook\n * injected by the host.\n */\n constructor(options: StateOptions<T> = {}) {\n super(\"state\");\n this.#options = options;\n }\n\n // ── Lifecycle capability hooks ─────────────────────────────────────────────\n\n /** Initialize state storage during Lifecycle startup. */\n async onStart(): Promise<void> {\n const version =\n (await this.lifecycle.storage.get<number>(STATE_SCHEMA_VERSION_KEY)) ?? 0;\n if (version >= CURRENT_STATE_SCHEMA_VERSION) {\n this.#tableEnsured = true;\n return;\n }\n\n // v1: own the table and clear the legacy wasChanged row left behind by\n // pre-optimization SDKs (state itself lives in STATE_ROW_ID).\n this.#ensureTable();\n this.lifecycle.storage.sql.exec(\n \"DELETE FROM cf_agents_state WHERE id = ?\",\n LEGACY_WAS_CHANGED_ROW_ID\n );\n await this.lifecycle.storage.put(\n STATE_SCHEMA_VERSION_KEY,\n CURRENT_STATE_SCHEMA_VERSION\n );\n }\n\n #ensureTable(): void {\n if (this.#tableEnsured) return;\n this.lifecycle.storage.sql.exec(`\n CREATE TABLE IF NOT EXISTS cf_agents_state (\n id TEXT PRIMARY KEY NOT NULL,\n state TEXT\n )\n `);\n this.#tableEnsured = true;\n }\n\n // ── State access ───────────────────────────────────────────────────────────\n\n /**\n * Current state.\n *\n * Loads lazily from storage on first access and caches in memory. Row\n * existence in `cf_agents_state` is the signal that state was previously\n * set, so falsy values persist correctly. On a corrupt row, falls back to\n * the initial state (re-persisting it) or clears the row.\n */\n get(): T | undefined {\n if (this.#state !== DEFAULT_STATE) {\n // state was previously set, and populated internal state\n return this.#state;\n }\n // looks like this is the first time the state is being accessed\n // check if the state was set in a previous life\n this.#ensureTable();\n const result = this.lifecycle.storage.sql\n .exec(\"SELECT state FROM cf_agents_state WHERE id = ?\", STATE_ROW_ID)\n .toArray() as { state: string | null }[];\n\n // Row existence is the signal that state was previously set.\n // This handles all values including falsy ones (null, 0, false, \"\").\n if (result.length > 0) {\n const state = result[0].state as string;\n\n try {\n this.#state = JSON.parse(state);\n } catch (e) {\n console.error(\n \"Failed to parse stored state, falling back to initialState:\",\n e\n );\n const initial = this.#options.initialState;\n if (initial !== undefined) {\n this.#state = initial;\n // Persist the fixed state to prevent future parse errors\n this.set(initial, \"server\");\n } else {\n // No initialState defined - clear corrupted data to prevent infinite retry loop\n this.lifecycle.storage.sql.exec(\n \"DELETE FROM cf_agents_state WHERE id = ?\",\n STATE_ROW_ID\n );\n return undefined;\n }\n }\n return this.#state;\n }\n\n // ok, this is the first time the state is being accessed\n // and the state was not set in a previous life\n // so we need to set the initial state (if provided)\n const initial = this.#options.initialState;\n if (initial === undefined) {\n // no initial state provided, so we return undefined\n return undefined;\n }\n // initial state provided, so we set the state,\n // update db and return the initial state\n this.set(initial, \"server\");\n return initial;\n }\n\n /**\n * Validate and persist a state change, then call the change hook.\n *\n * @param nextState - The new state to persist.\n * @param source - `\"server\"` for host-originated changes, or the originating\n * connection for client-originated changes.\n * @throws Whatever the injected `validateStateChange` throws.\n */\n set(nextState: T, source: StateChangeSource = \"server\"): void {\n // Validation/gating hook (sync only)\n this.#options.validateStateChange?.(nextState, source);\n this.#ensureTable();\n\n // Persist first, cache second: a value that fails to serialize or to\n // write must not be served by later get() calls. Row existence in\n // cf_agents_state is the signal that state was set.\n const serialized = JSON.stringify(nextState);\n this.lifecycle.storage.sql.exec(\n \"INSERT OR REPLACE INTO cf_agents_state (id, state) VALUES (?, ?)\",\n STATE_ROW_ID,\n serialized\n );\n this.#state = nextState;\n\n let pending: void | Promise<void>;\n try {\n pending = this.#options.onChanged?.(nextState, source);\n } catch (error) {\n console.error(\"State onChanged hook failed:\", error);\n return;\n }\n\n if (pending) {\n // Durable Objects remain active for pending I/O without waitUntil. Keep\n // set() synchronous while ensuring asynchronous failures are observed.\n // Promise.resolve normalizes thenables from other realms or libraries.\n void Promise.resolve(pending).catch((error) => {\n console.error(\"State onChanged hook failed:\", error);\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;AA0CA,MAAM,2BAA2B;AACjC,MAAM,+BAA+B;;AAGrC,MAAM,eAAe;;;;;AAMrB,MAAM,4BAA4B;;;;;;AAOlC,MAAM,gBAAgB,CAAC;;;;;;;;;;;;;;;AAYvB,IAAa,QAAb,cAAwC,oBAAoB;;;;;;;CAW1D,YAAY,UAA2B,CAAC,GAAG;EACzC,MAAM,OAAO;;2CAXN,aAAA;kDACO,KAAA;;EAWd,uBAAA,UAAA,MAAgB,OAAA;CAClB;;CAKA,MAAM,UAAyB;EAG7B,KADG,MAAM,KAAK,UAAU,QAAQ,IAAY,wBAAwB,KAAM,MAC3D,8BAA8B;GAC3C,uBAAA,eAAA,MAAqB,IAAA;GACrB;EACF;EAIA,kBAAA,cAAA,MAAA,YAAA,CAAA,CAAA,KAAA,IAAkB;EAClB,KAAK,UAAU,QAAQ,IAAI,KACzB,4CACA,yBACF;EACA,MAAM,KAAK,UAAU,QAAQ,IAC3B,0BACA,4BACF;CACF;;;;;;;;;CAuBA,MAAqB;EACnB,IAAA,uBAAA,QAAI,IAAA,MAAgB,eAElB,OAAA,uBAAA,QAAO,IAAA;EAIT,kBAAA,cAAA,MAAA,YAAA,CAAA,CAAA,KAAA,IAAkB;EAClB,MAAM,SAAS,KAAK,UAAU,QAAQ,IACnC,KAAK,kDAAkD,YAAY,CAAC,CACpE,QAAQ;EAIX,IAAI,OAAO,SAAS,GAAG;GACrB,MAAM,QAAQ,OAAO,EAAE,CAAC;GAExB,IAAI;IACF,uBAAA,QAAA,MAAc,KAAK,MAAM,KAAK,CAAA;GAChC,SAAS,GAAG;IACV,QAAQ,MACN,+DACA,CACF;IACA,MAAM,UAAA,uBAAA,UAAU,IAAA,CAAA,CAAc;IAC9B,IAAI,YAAY,KAAA,GAAW;KACzB,uBAAA,QAAA,MAAc,OAAA;KAEd,KAAK,IAAI,SAAS,QAAQ;IAC5B,OAAO;KAEL,KAAK,UAAU,QAAQ,IAAI,KACzB,4CACA,YACF;KACA;IACF;GACF;GACA,OAAA,uBAAA,QAAO,IAAA;EACT;EAKA,MAAM,UAAA,uBAAA,UAAU,IAAA,CAAA,CAAc;EAC9B,IAAI,YAAY,KAAA,GAEd;EAIF,KAAK,IAAI,SAAS,QAAQ;EAC1B,OAAO;CACT;;;;;;;;;CAUA,IAAI,WAAc,SAA4B,UAAgB;EAE5D,uBAAA,UAAA,IAAA,CAAA,CAAc,sBAAsB,WAAW,MAAM;EACrD,kBAAA,cAAA,MAAA,YAAA,CAAA,CAAA,KAAA,IAAkB;EAKlB,MAAM,aAAa,KAAK,UAAU,SAAS;EAC3C,KAAK,UAAU,QAAQ,IAAI,KACzB,oEACA,cACA,UACF;EACA,uBAAA,QAAA,MAAc,SAAA;EAEd,IAAI;EACJ,IAAI;GACF,UAAA,uBAAA,UAAU,IAAA,CAAA,CAAc,YAAY,WAAW,MAAM;EACvD,SAAS,OAAO;GACd,QAAQ,MAAM,gCAAgC,KAAK;GACnD;EACF;EAEA,IAAI,SAIF,QAAa,QAAQ,OAAO,CAAC,CAAC,OAAO,UAAU;GAC7C,QAAQ,MAAM,gCAAgC,KAAK;EACrD,CAAC;CAEL;AACF;AArHE,SAAA,eAAqB;CACnB,IAAA,uBAAA,eAAI,IAAA,GAAoB;CACxB,KAAK,UAAU,QAAQ,IAAI,KAAK;;;;;KAK/B;CACD,uBAAA,eAAA,MAAqB,IAAA;AACvB"}
@@ -0,0 +1,120 @@
1
+ import {
2
+ a as StreamJson,
3
+ c as StreamReadBatchesOptions,
4
+ d as StreamState,
5
+ f as StreamStatus,
6
+ i as StreamChunk,
7
+ l as StreamReadOptions,
8
+ n as Streams,
9
+ o as StreamListOptions,
10
+ p as StreamWriter,
11
+ r as StreamsOptions,
12
+ s as StreamOpenOptions,
13
+ t as DEFAULT_MAX_CHUNK_BYTES,
14
+ u as StreamSettleOptions
15
+ } from "../streams-BcE8JP2X.js";
16
+
17
+ //#region src/streams/errors.d.ts
18
+ /**
19
+ * Error classes for the Streams capability. Each carries a stable `name` so
20
+ * hosts and tests can classify failures without depending on message text.
21
+ */
22
+ /**
23
+ * Thrown when `open()` targets a terminal stream, or an append reaches a
24
+ * stream that settled (or was deleted) after the writer was created.
25
+ *
26
+ * @experimental The API surface may change before stabilizing.
27
+ */
28
+ declare class StreamClosedError extends Error {
29
+ /** The stream that no longer accepts writes. */
30
+ readonly streamId: string;
31
+ constructor(streamId: string, detail: string);
32
+ }
33
+ /**
34
+ * Thrown when `read()` targets a stream that was never opened (or was
35
+ * deleted). `status()` returns `null` instead, for existence probes.
36
+ *
37
+ * @experimental The API surface may change before stabilizing.
38
+ */
39
+ declare class StreamNotFoundError extends Error {
40
+ readonly streamId: string;
41
+ constructor(streamId: string);
42
+ }
43
+ /**
44
+ * Thrown when a chunk or metadata value is not JSON-serializable or exceeds
45
+ * the configured size limit.
46
+ *
47
+ * @experimental The API surface may change before stabilizing.
48
+ */
49
+ declare class StreamSerializationError extends Error {
50
+ constructor(context: string, detail: string);
51
+ }
52
+ //#endregion
53
+ //#region src/streams/sse.d.ts
54
+ /**
55
+ * Options accepted by {@link sseResponse}.
56
+ *
57
+ * @experimental The API surface may change before stabilizing.
58
+ */
59
+ interface SSEResponseOptions {
60
+ /**
61
+ * The incoming request. Used for resume (the `Last-Event-ID` header a
62
+ * reconnecting `EventSource` sends, or a `?from=` query parameter) and to
63
+ * abort the tail when the client disconnects (`request.signal`).
64
+ */
65
+ request?: Request;
66
+ /** First sequence number to yield. Overrides request-derived resume. */
67
+ from?: number;
68
+ /** Extra abort signal; composed with `request.signal`. */
69
+ signal?: AbortSignal;
70
+ /** Maximum chunks per write. Defaults to the read batch size (100). */
71
+ batchSize?: number;
72
+ /**
73
+ * Milliseconds between `: heartbeat` comment frames while tailing, keeping
74
+ * idle proxies from killing the connection. 0 disables. Default: 30000.
75
+ */
76
+ heartbeatMs?: number;
77
+ }
78
+ /**
79
+ * Serve one durable stream as a Server-Sent Events response: replay from the
80
+ * resume point, emit an `up-to-date` control event on reaching the tail,
81
+ * tail live appends, and finish with `done` (completed) or `error` (errored,
82
+ * carrying the recorded reason). Returns a 404 response when the stream does
83
+ * not exist.
84
+ *
85
+ * ```ts
86
+ * async onRequest(request: Request) {
87
+ * return sseResponse(this.streams, "reply:123", { request });
88
+ * }
89
+ * // client: new EventSource(url) — reconnect resume is automatic.
90
+ * ```
91
+ *
92
+ * @experimental The API surface may change before stabilizing.
93
+ */
94
+ declare function sseResponse(
95
+ streams: Streams,
96
+ streamId: string,
97
+ options?: SSEResponseOptions
98
+ ): Promise<Response>;
99
+ //#endregion
100
+ export {
101
+ DEFAULT_MAX_CHUNK_BYTES,
102
+ type SSEResponseOptions,
103
+ type StreamChunk,
104
+ StreamClosedError,
105
+ type StreamJson,
106
+ type StreamListOptions,
107
+ StreamNotFoundError,
108
+ type StreamOpenOptions,
109
+ type StreamReadBatchesOptions,
110
+ type StreamReadOptions,
111
+ StreamSerializationError,
112
+ type StreamSettleOptions,
113
+ type StreamState,
114
+ type StreamStatus,
115
+ type StreamWriter,
116
+ Streams,
117
+ type StreamsOptions,
118
+ sseResponse
119
+ };
120
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,107 @@
1
+ import { a as StreamSerializationError, i as StreamNotFoundError, n as Streams, r as StreamClosedError, t as DEFAULT_MAX_CHUNK_BYTES } from "../streams-CCPRV6dt.js";
2
+ //#region src/streams/sse.ts
3
+ const encoder = new TextEncoder();
4
+ function resumeFrom(options) {
5
+ if (options.from !== void 0) return Math.max(0, options.from);
6
+ const request = options.request;
7
+ if (request) {
8
+ const header = request.headers.get("Last-Event-ID");
9
+ if (header !== null && header !== "") {
10
+ const lastEventId = Number(header);
11
+ if (Number.isInteger(lastEventId) && lastEventId >= 0) return lastEventId + 1;
12
+ }
13
+ const fromParam = new URL(request.url).searchParams.get("from");
14
+ if (fromParam !== null) {
15
+ const from = Number(fromParam);
16
+ if (Number.isInteger(from) && from >= 0) return from;
17
+ }
18
+ }
19
+ return 0;
20
+ }
21
+ function frame(seq, chunk) {
22
+ return `id: ${seq}\ndata: ${JSON.stringify(chunk)}\n\n`;
23
+ }
24
+ function controlFrame(event, data) {
25
+ return `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
26
+ }
27
+ /**
28
+ * Serve one durable stream as a Server-Sent Events response: replay from the
29
+ * resume point, emit an `up-to-date` control event on reaching the tail,
30
+ * tail live appends, and finish with `done` (completed) or `error` (errored,
31
+ * carrying the recorded reason). Returns a 404 response when the stream does
32
+ * not exist.
33
+ *
34
+ * ```ts
35
+ * async onRequest(request: Request) {
36
+ * return sseResponse(this.streams, "reply:123", { request });
37
+ * }
38
+ * // client: new EventSource(url) — reconnect resume is automatic.
39
+ * ```
40
+ *
41
+ * @experimental The API surface may change before stabilizing.
42
+ */
43
+ async function sseResponse(streams, streamId, options = {}) {
44
+ if (await streams.status(streamId) === null) return new Response(`Stream "${streamId}" does not exist`, { status: 404 });
45
+ const from = resumeFrom(options);
46
+ const heartbeatMs = options.heartbeatMs ?? 3e4;
47
+ const abort = new AbortController();
48
+ const onUpstreamAbort = () => abort.abort();
49
+ if (options.signal?.aborted || options.request?.signal.aborted) abort.abort();
50
+ else {
51
+ options.signal?.addEventListener("abort", onUpstreamAbort, { once: true });
52
+ options.request?.signal.addEventListener("abort", onUpstreamAbort, { once: true });
53
+ }
54
+ let open = true;
55
+ const body = new ReadableStream({
56
+ start: (controller) => {
57
+ const write = (text) => {
58
+ if (!open) return;
59
+ try {
60
+ controller.enqueue(encoder.encode(text));
61
+ } catch {
62
+ open = false;
63
+ }
64
+ };
65
+ const heartbeat = heartbeatMs > 0 ? setInterval(() => write(": heartbeat\n\n"), heartbeatMs) : null;
66
+ const finish = () => {
67
+ if (heartbeat !== null) clearInterval(heartbeat);
68
+ options.signal?.removeEventListener("abort", onUpstreamAbort);
69
+ options.request?.signal.removeEventListener("abort", onUpstreamAbort);
70
+ if (open) {
71
+ open = false;
72
+ try {
73
+ controller.close();
74
+ } catch {}
75
+ }
76
+ };
77
+ (async () => {
78
+ try {
79
+ const batches = streams.readBatches(streamId, {
80
+ from,
81
+ signal: abort.signal,
82
+ batchSize: options.batchSize,
83
+ onUpToDate: () => write(controlFrame("up-to-date", {}))
84
+ });
85
+ for await (const batch of batches) write(batch.map((chunk) => frame(chunk.seq, chunk.chunk)).join(""));
86
+ const status = await streams.status(streamId);
87
+ if (status?.state === "errored") write(controlFrame("error", { reason: status.error ?? null }));
88
+ else write(controlFrame("done", {}));
89
+ } catch {} finally {
90
+ finish();
91
+ }
92
+ })();
93
+ },
94
+ cancel: () => {
95
+ open = false;
96
+ abort.abort();
97
+ }
98
+ });
99
+ return new Response(body, { headers: {
100
+ "content-type": "text/event-stream; charset=utf-8",
101
+ "cache-control": "no-store"
102
+ } });
103
+ }
104
+ //#endregion
105
+ export { DEFAULT_MAX_CHUNK_BYTES, StreamClosedError, StreamNotFoundError, StreamSerializationError, Streams, sseResponse };
106
+
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/streams/sse.ts"],"sourcesContent":["/**\n * Server-Sent Events serving for durable streams: turn one stream into an\n * SSE `Response` with resume built into the protocol. Every chunk is emitted\n * with its sequence number as the SSE `id:` field, so a browser\n * `EventSource` that reconnects sends `Last-Event-ID` automatically and the\n * helper resumes from the next chunk — cursor persistence with zero client\n * code. Control events mark the replay→live transition (`up-to-date`) and\n * settlement (`done` / `error`), mirroring the stream's own lifecycle.\n */\n\nimport type { Streams } from \"./streams\";\nimport type { StreamJson } from \"./types\";\n\nconst encoder = new TextEncoder();\n\n/**\n * Options accepted by {@link sseResponse}.\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport interface SSEResponseOptions {\n /**\n * The incoming request. Used for resume (the `Last-Event-ID` header a\n * reconnecting `EventSource` sends, or a `?from=` query parameter) and to\n * abort the tail when the client disconnects (`request.signal`).\n */\n request?: Request;\n /** First sequence number to yield. Overrides request-derived resume. */\n from?: number;\n /** Extra abort signal; composed with `request.signal`. */\n signal?: AbortSignal;\n /** Maximum chunks per write. Defaults to the read batch size (100). */\n batchSize?: number;\n /**\n * Milliseconds between `: heartbeat` comment frames while tailing, keeping\n * idle proxies from killing the connection. 0 disables. Default: 30000.\n */\n heartbeatMs?: number;\n}\n\nfunction resumeFrom(options: SSEResponseOptions): number {\n if (options.from !== undefined) return Math.max(0, options.from);\n const request = options.request;\n if (request) {\n // A fresh EventSource sends no Last-Event-ID at all; Number(null) is 0,\n // so the header must be checked for presence before parsing or every\n // first connection would skip chunk 0.\n const header = request.headers.get(\"Last-Event-ID\");\n if (header !== null && header !== \"\") {\n const lastEventId = Number(header);\n // Last-Event-ID names the last chunk the client received; resume after.\n if (Number.isInteger(lastEventId) && lastEventId >= 0) {\n return lastEventId + 1;\n }\n }\n const fromParam = new URL(request.url).searchParams.get(\"from\");\n if (fromParam !== null) {\n const from = Number(fromParam);\n if (Number.isInteger(from) && from >= 0) return from;\n }\n }\n return 0;\n}\n\nfunction frame(seq: number, chunk: StreamJson): string {\n // JSON.stringify never emits raw newlines, so one data line is always safe.\n return `id: ${seq}\\ndata: ${JSON.stringify(chunk)}\\n\\n`;\n}\n\nfunction controlFrame(event: string, data: StreamJson): string {\n return `event: ${event}\\ndata: ${JSON.stringify(data)}\\n\\n`;\n}\n\n/**\n * Serve one durable stream as a Server-Sent Events response: replay from the\n * resume point, emit an `up-to-date` control event on reaching the tail,\n * tail live appends, and finish with `done` (completed) or `error` (errored,\n * carrying the recorded reason). Returns a 404 response when the stream does\n * not exist.\n *\n * ```ts\n * async onRequest(request: Request) {\n * return sseResponse(this.streams, \"reply:123\", { request });\n * }\n * // client: new EventSource(url) — reconnect resume is automatic.\n * ```\n *\n * @experimental The API surface may change before stabilizing.\n */\nexport async function sseResponse(\n streams: Streams,\n streamId: string,\n options: SSEResponseOptions = {}\n): Promise<Response> {\n if ((await streams.status(streamId)) === null) {\n return new Response(`Stream \"${streamId}\" does not exist`, { status: 404 });\n }\n\n const from = resumeFrom(options);\n const heartbeatMs = options.heartbeatMs ?? 30_000;\n const abort = new AbortController();\n const onUpstreamAbort = () => abort.abort();\n // A listener added to an already-aborted signal never fires: check first,\n // or a pre-aborted request would tail a live stream forever.\n if (options.signal?.aborted || options.request?.signal.aborted) {\n abort.abort();\n } else {\n options.signal?.addEventListener(\"abort\", onUpstreamAbort, { once: true });\n options.request?.signal.addEventListener(\"abort\", onUpstreamAbort, {\n once: true\n });\n }\n\n let open = true;\n const body = new ReadableStream<Uint8Array>({\n start: (controller) => {\n const write = (text: string) => {\n if (!open) return;\n try {\n controller.enqueue(encoder.encode(text));\n } catch {\n // The stream was cancelled between the check and the write (a\n // heartbeat tick racing a client disconnect): stop writing.\n open = false;\n }\n };\n const heartbeat =\n heartbeatMs > 0\n ? setInterval(() => write(\": heartbeat\\n\\n\"), heartbeatMs)\n : null;\n const finish = () => {\n if (heartbeat !== null) clearInterval(heartbeat);\n options.signal?.removeEventListener(\"abort\", onUpstreamAbort);\n options.request?.signal.removeEventListener(\"abort\", onUpstreamAbort);\n if (open) {\n open = false;\n try {\n controller.close();\n } catch {\n // Already cancelled by the consumer.\n }\n }\n };\n\n void (async () => {\n try {\n const batches = streams.readBatches(streamId, {\n from,\n signal: abort.signal,\n batchSize: options.batchSize,\n onUpToDate: () => write(controlFrame(\"up-to-date\", {}))\n });\n for await (const batch of batches) {\n write(batch.map((chunk) => frame(chunk.seq, chunk.chunk)).join(\"\"));\n }\n const status = await streams.status(streamId);\n if (status?.state === \"errored\") {\n write(controlFrame(\"error\", { reason: status.error ?? null }));\n } else {\n write(controlFrame(\"done\", {}));\n }\n } catch {\n // The client disconnected or the caller aborted: nothing to send.\n } finally {\n finish();\n }\n })();\n },\n cancel: () => {\n open = false;\n abort.abort();\n }\n });\n\n return new Response(body, {\n headers: {\n \"content-type\": \"text/event-stream; charset=utf-8\",\n \"cache-control\": \"no-store\"\n }\n });\n}\n"],"mappings":";;AAaA,MAAM,UAAU,IAAI,YAAY;AA2BhC,SAAS,WAAW,SAAqC;CACvD,IAAI,QAAQ,SAAS,KAAA,GAAW,OAAO,KAAK,IAAI,GAAG,QAAQ,IAAI;CAC/D,MAAM,UAAU,QAAQ;CACxB,IAAI,SAAS;EAIX,MAAM,SAAS,QAAQ,QAAQ,IAAI,eAAe;EAClD,IAAI,WAAW,QAAQ,WAAW,IAAI;GACpC,MAAM,cAAc,OAAO,MAAM;GAEjC,IAAI,OAAO,UAAU,WAAW,KAAK,eAAe,GAClD,OAAO,cAAc;EAEzB;EACA,MAAM,YAAY,IAAI,IAAI,QAAQ,GAAG,CAAC,CAAC,aAAa,IAAI,MAAM;EAC9D,IAAI,cAAc,MAAM;GACtB,MAAM,OAAO,OAAO,SAAS;GAC7B,IAAI,OAAO,UAAU,IAAI,KAAK,QAAQ,GAAG,OAAO;EAClD;CACF;CACA,OAAO;AACT;AAEA,SAAS,MAAM,KAAa,OAA2B;CAErD,OAAO,OAAO,IAAI,UAAU,KAAK,UAAU,KAAK,EAAE;AACpD;AAEA,SAAS,aAAa,OAAe,MAA0B;CAC7D,OAAO,UAAU,MAAM,UAAU,KAAK,UAAU,IAAI,EAAE;AACxD;;;;;;;;;;;;;;;;;AAkBA,eAAsB,YACpB,SACA,UACA,UAA8B,CAAC,GACZ;CACnB,IAAK,MAAM,QAAQ,OAAO,QAAQ,MAAO,MACvC,OAAO,IAAI,SAAS,WAAW,SAAS,mBAAmB,EAAE,QAAQ,IAAI,CAAC;CAG5E,MAAM,OAAO,WAAW,OAAO;CAC/B,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,QAAQ,IAAI,gBAAgB;CAClC,MAAM,wBAAwB,MAAM,MAAM;CAG1C,IAAI,QAAQ,QAAQ,WAAW,QAAQ,SAAS,OAAO,SACrD,MAAM,MAAM;MACP;EACL,QAAQ,QAAQ,iBAAiB,SAAS,iBAAiB,EAAE,MAAM,KAAK,CAAC;EACzE,QAAQ,SAAS,OAAO,iBAAiB,SAAS,iBAAiB,EACjE,MAAM,KACR,CAAC;CACH;CAEA,IAAI,OAAO;CACX,MAAM,OAAO,IAAI,eAA2B;EAC1C,QAAQ,eAAe;GACrB,MAAM,SAAS,SAAiB;IAC9B,IAAI,CAAC,MAAM;IACX,IAAI;KACF,WAAW,QAAQ,QAAQ,OAAO,IAAI,CAAC;IACzC,QAAQ;KAGN,OAAO;IACT;GACF;GACA,MAAM,YACJ,cAAc,IACV,kBAAkB,MAAM,iBAAiB,GAAG,WAAW,IACvD;GACN,MAAM,eAAe;IACnB,IAAI,cAAc,MAAM,cAAc,SAAS;IAC/C,QAAQ,QAAQ,oBAAoB,SAAS,eAAe;IAC5D,QAAQ,SAAS,OAAO,oBAAoB,SAAS,eAAe;IACpE,IAAI,MAAM;KACR,OAAO;KACP,IAAI;MACF,WAAW,MAAM;KACnB,QAAQ,CAER;IACF;GACF;GAEA,CAAM,YAAY;IAChB,IAAI;KACF,MAAM,UAAU,QAAQ,YAAY,UAAU;MAC5C;MACA,QAAQ,MAAM;MACd,WAAW,QAAQ;MACnB,kBAAkB,MAAM,aAAa,cAAc,CAAC,CAAC,CAAC;KACxD,CAAC;KACD,WAAW,MAAM,SAAS,SACxB,MAAM,MAAM,KAAK,UAAU,MAAM,MAAM,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;KAEpE,MAAM,SAAS,MAAM,QAAQ,OAAO,QAAQ;KAC5C,IAAI,QAAQ,UAAU,WACpB,MAAM,aAAa,SAAS,EAAE,QAAQ,OAAO,SAAS,KAAK,CAAC,CAAC;UAE7D,MAAM,aAAa,QAAQ,CAAC,CAAC,CAAC;IAElC,QAAQ,CAER,UAAU;KACR,OAAO;IACT;GACF,EAAA,CAAG;EACL;EACA,cAAc;GACZ,OAAO;GACP,MAAM,MAAM;EACd;CACF,CAAC;CAED,OAAO,IAAI,SAAS,MAAM,EACxB,SAAS;EACP,gBAAgB;EAChB,iBAAiB;CACnB,EACF,CAAC;AACH"}