@di-code/coding-agent 0.1.6 → 0.1.8

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 (338) hide show
  1. package/README.md +112 -68
  2. package/compositions/base.yml +54 -0
  3. package/compositions/interactive.yml +14 -0
  4. package/compositions/json.yml +6 -0
  5. package/compositions/print.yml +5 -0
  6. package/compositions/rpc.yml +12 -0
  7. package/compositions/webui.yml +9 -0
  8. package/dist/cli.d.ts +22 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +97 -3
  11. package/dist/cli.js.map +1 -1
  12. package/dist/composition-loader-entry.d.ts +11 -0
  13. package/dist/composition-loader-entry.d.ts.map +1 -0
  14. package/dist/composition-loader-entry.js +12 -0
  15. package/dist/composition-loader-entry.js.map +1 -0
  16. package/dist/compositions.d.ts +32 -0
  17. package/dist/compositions.d.ts.map +1 -0
  18. package/dist/compositions.js +173 -0
  19. package/dist/compositions.js.map +1 -0
  20. package/dist/core/session/session-manager.d.ts +9 -2
  21. package/dist/core/session/session-manager.d.ts.map +1 -1
  22. package/dist/core/session/session-manager.js +28 -0
  23. package/dist/core/session/session-manager.js.map +1 -1
  24. package/dist/core/session/session-storage.d.ts.map +1 -1
  25. package/dist/core/session/session-storage.js +20 -3
  26. package/dist/core/session/session-storage.js.map +1 -1
  27. package/dist/core/session/types.d.ts +11 -2
  28. package/dist/core/session/types.d.ts.map +1 -1
  29. package/dist/core/session/types.js.map +1 -1
  30. package/dist/core/session-tools.d.ts +5 -0
  31. package/dist/core/session-tools.d.ts.map +1 -0
  32. package/dist/core/session-tools.js +17 -0
  33. package/dist/core/session-tools.js.map +1 -0
  34. package/dist/core/session.d.ts +21 -7
  35. package/dist/core/session.d.ts.map +1 -1
  36. package/dist/core/session.js +77 -41
  37. package/dist/core/session.js.map +1 -1
  38. package/dist/core/tools/bash.d.ts +1 -38
  39. package/dist/core/tools/bash.d.ts.map +1 -1
  40. package/dist/core/tools/bash.js +1 -207
  41. package/dist/core/tools/bash.js.map +1 -1
  42. package/dist/core/tools/edit-diff.d.ts +1 -24
  43. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  44. package/dist/core/tools/edit-diff.js +1 -135
  45. package/dist/core/tools/edit-diff.js.map +1 -1
  46. package/dist/core/tools/edit.d.ts +1 -26
  47. package/dist/core/tools/edit.d.ts.map +1 -1
  48. package/dist/core/tools/edit.js +1 -140
  49. package/dist/core/tools/edit.js.map +1 -1
  50. package/dist/core/tools/file-mutation-queue.d.ts +1 -1
  51. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  52. package/dist/core/tools/file-mutation-queue.js +1 -23
  53. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  54. package/dist/core/tools/file-search.d.ts +1 -13
  55. package/dist/core/tools/file-search.d.ts.map +1 -1
  56. package/dist/core/tools/file-search.js +1 -98
  57. package/dist/core/tools/file-search.js.map +1 -1
  58. package/dist/core/tools/glob.d.ts +1 -10
  59. package/dist/core/tools/glob.d.ts.map +1 -1
  60. package/dist/core/tools/glob.js +1 -43
  61. package/dist/core/tools/glob.js.map +1 -1
  62. package/dist/core/tools/grep.d.ts +1 -12
  63. package/dist/core/tools/grep.d.ts.map +1 -1
  64. package/dist/core/tools/grep.js +1 -66
  65. package/dist/core/tools/grep.js.map +1 -1
  66. package/dist/core/tools/load-skill.d.ts +1 -9
  67. package/dist/core/tools/load-skill.d.ts.map +1 -1
  68. package/dist/core/tools/load-skill.js +1 -21
  69. package/dist/core/tools/load-skill.js.map +1 -1
  70. package/dist/core/tools/path-boundary.d.ts +1 -4
  71. package/dist/core/tools/path-boundary.d.ts.map +1 -1
  72. package/dist/core/tools/path-boundary.js +1 -65
  73. package/dist/core/tools/path-boundary.js.map +1 -1
  74. package/dist/core/tools/read.d.ts +1 -16
  75. package/dist/core/tools/read.d.ts.map +1 -1
  76. package/dist/core/tools/read.js +1 -131
  77. package/dist/core/tools/read.js.map +1 -1
  78. package/dist/core/tools/write.d.ts +1 -16
  79. package/dist/core/tools/write.d.ts.map +1 -1
  80. package/dist/core/tools/write.js +1 -44
  81. package/dist/core/tools/write.js.map +1 -1
  82. package/dist/entry.js +30 -28
  83. package/dist/entry.js.map +1 -1
  84. package/dist/i18n.d.ts.map +1 -1
  85. package/dist/i18n.js +2 -0
  86. package/dist/i18n.js.map +1 -1
  87. package/dist/index.d.ts +6 -3
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +6 -3
  90. package/dist/index.js.map +1 -1
  91. package/dist/interactive/builtin.d.ts +17 -0
  92. package/dist/interactive/builtin.d.ts.map +1 -0
  93. package/dist/interactive/builtin.js +47 -0
  94. package/dist/interactive/builtin.js.map +1 -0
  95. package/dist/interactive/controller.d.ts +85 -0
  96. package/dist/interactive/controller.d.ts.map +1 -0
  97. package/dist/interactive/controller.js +211 -0
  98. package/dist/interactive/controller.js.map +1 -0
  99. package/dist/interactive/index.d.ts +3 -0
  100. package/dist/interactive/index.d.ts.map +1 -0
  101. package/dist/interactive/index.js +3 -0
  102. package/dist/interactive/index.js.map +1 -0
  103. package/dist/interactive-host-entry.d.ts +7 -0
  104. package/dist/interactive-host-entry.d.ts.map +1 -0
  105. package/dist/interactive-host-entry.js +123 -0
  106. package/dist/interactive-host-entry.js.map +1 -0
  107. package/dist/interactive-profile.d.ts +18 -0
  108. package/dist/interactive-profile.d.ts.map +1 -0
  109. package/dist/interactive-profile.js +290 -0
  110. package/dist/interactive-profile.js.map +1 -0
  111. package/dist/interactive-resources-entry.d.ts +7 -0
  112. package/dist/interactive-resources-entry.d.ts.map +1 -0
  113. package/dist/interactive-resources-entry.js +42 -0
  114. package/dist/interactive-resources-entry.js.map +1 -0
  115. package/dist/legacy-main.d.ts +39 -0
  116. package/dist/legacy-main.d.ts.map +1 -0
  117. package/dist/legacy-main.js +611 -0
  118. package/dist/legacy-main.js.map +1 -0
  119. package/dist/main.d.ts +15 -34
  120. package/dist/main.d.ts.map +1 -1
  121. package/dist/main.js +130 -513
  122. package/dist/main.js.map +1 -1
  123. package/dist/mcp/entries.d.ts +42 -0
  124. package/dist/mcp/entries.d.ts.map +1 -0
  125. package/dist/mcp/entries.js +98 -0
  126. package/dist/mcp/entries.js.map +1 -0
  127. package/dist/mcp-client-entry.d.ts +5 -0
  128. package/dist/mcp-client-entry.d.ts.map +1 -0
  129. package/dist/mcp-client-entry.js +6 -0
  130. package/dist/mcp-client-entry.js.map +1 -0
  131. package/dist/mcp-config-entry.d.ts +5 -0
  132. package/dist/mcp-config-entry.d.ts.map +1 -0
  133. package/dist/mcp-config-entry.js +6 -0
  134. package/dist/mcp-config-entry.js.map +1 -0
  135. package/dist/mcp-tools-entry.d.ts +5 -0
  136. package/dist/mcp-tools-entry.d.ts.map +1 -0
  137. package/dist/mcp-tools-entry.js +6 -0
  138. package/dist/mcp-tools-entry.js.map +1 -0
  139. package/dist/mcp-transport-entry.d.ts +5 -0
  140. package/dist/mcp-transport-entry.d.ts.map +1 -0
  141. package/dist/mcp-transport-entry.js +6 -0
  142. package/dist/mcp-transport-entry.js.map +1 -0
  143. package/dist/modes/interactive-entry.d.ts +18 -0
  144. package/dist/modes/interactive-entry.d.ts.map +1 -0
  145. package/dist/modes/interactive-entry.js +21 -0
  146. package/dist/modes/interactive-entry.js.map +1 -0
  147. package/dist/modes/interactive-state.js +1 -1
  148. package/dist/modes/interactive-state.js.map +1 -1
  149. package/dist/modes/interactive.d.ts +16 -6
  150. package/dist/modes/interactive.d.ts.map +1 -1
  151. package/dist/modes/interactive.js +99 -33
  152. package/dist/modes/interactive.js.map +1 -1
  153. package/dist/modes/json-entry.d.ts +13 -0
  154. package/dist/modes/json-entry.d.ts.map +1 -0
  155. package/dist/modes/json-entry.js +14 -0
  156. package/dist/modes/json-entry.js.map +1 -0
  157. package/dist/modes/json.d.ts +4 -1
  158. package/dist/modes/json.d.ts.map +1 -1
  159. package/dist/modes/json.js +3 -3
  160. package/dist/modes/json.js.map +1 -1
  161. package/dist/modes/print-entry.d.ts +10 -0
  162. package/dist/modes/print-entry.d.ts.map +1 -0
  163. package/dist/modes/print-entry.js +11 -0
  164. package/dist/modes/print-entry.js.map +1 -0
  165. package/dist/modes/tree-selector.d.ts.map +1 -1
  166. package/dist/modes/tree-selector.js +4 -0
  167. package/dist/modes/tree-selector.js.map +1 -1
  168. package/dist/plugin-dump-composition.d.ts +6 -0
  169. package/dist/plugin-dump-composition.d.ts.map +1 -0
  170. package/dist/plugin-dump-composition.js +7 -0
  171. package/dist/plugin-dump-composition.js.map +1 -0
  172. package/dist/plugin-inventory.d.ts +7 -0
  173. package/dist/plugin-inventory.d.ts.map +1 -0
  174. package/dist/plugin-inventory.js +8 -0
  175. package/dist/plugin-inventory.js.map +1 -0
  176. package/dist/plugin-manager.d.ts +6 -0
  177. package/dist/plugin-manager.d.ts.map +1 -0
  178. package/dist/plugin-manager.js +7 -0
  179. package/dist/plugin-manager.js.map +1 -0
  180. package/dist/plugin-trace.d.ts +6 -0
  181. package/dist/plugin-trace.d.ts.map +1 -0
  182. package/dist/plugin-trace.js +7 -0
  183. package/dist/plugin-trace.js.map +1 -0
  184. package/dist/plugins/dynamic-broker.d.ts +76 -0
  185. package/dist/plugins/dynamic-broker.d.ts.map +1 -0
  186. package/dist/plugins/dynamic-broker.js +852 -0
  187. package/dist/plugins/dynamic-broker.js.map +1 -0
  188. package/dist/plugins/profile.d.ts +15 -0
  189. package/dist/plugins/profile.d.ts.map +1 -0
  190. package/dist/plugins/profile.js +34 -0
  191. package/dist/plugins/profile.js.map +1 -0
  192. package/dist/plugins/runtime-host.d.ts +37 -0
  193. package/dist/plugins/runtime-host.d.ts.map +1 -0
  194. package/dist/plugins/runtime-host.js +95 -0
  195. package/dist/plugins/runtime-host.js.map +1 -0
  196. package/dist/plugins/trust.d.ts +8 -0
  197. package/dist/plugins/trust.d.ts.map +1 -0
  198. package/dist/plugins/trust.js +59 -0
  199. package/dist/plugins/trust.js.map +1 -0
  200. package/dist/project-trust-entry.d.ts +15 -0
  201. package/dist/project-trust-entry.d.ts.map +1 -0
  202. package/dist/project-trust-entry.js +15 -0
  203. package/dist/project-trust-entry.js.map +1 -0
  204. package/dist/rpc/client.d.ts +78 -6
  205. package/dist/rpc/client.d.ts.map +1 -1
  206. package/dist/rpc/client.js +172 -4
  207. package/dist/rpc/client.js.map +1 -1
  208. package/dist/rpc/dispatcher.d.ts +121 -0
  209. package/dist/rpc/dispatcher.d.ts.map +1 -0
  210. package/dist/rpc/dispatcher.js +994 -0
  211. package/dist/rpc/dispatcher.js.map +1 -0
  212. package/dist/rpc/index.d.ts +2 -0
  213. package/dist/rpc/index.d.ts.map +1 -1
  214. package/dist/rpc/index.js +2 -0
  215. package/dist/rpc/index.js.map +1 -1
  216. package/dist/rpc/lifecycle.d.ts +6 -0
  217. package/dist/rpc/lifecycle.d.ts.map +1 -0
  218. package/dist/rpc/lifecycle.js +24 -0
  219. package/dist/rpc/lifecycle.js.map +1 -0
  220. package/dist/rpc/protocol.d.ts +112 -31
  221. package/dist/rpc/protocol.d.ts.map +1 -1
  222. package/dist/rpc/protocol.js +569 -117
  223. package/dist/rpc/protocol.js.map +1 -1
  224. package/dist/rpc/server-service.d.ts +7 -0
  225. package/dist/rpc/server-service.d.ts.map +1 -0
  226. package/dist/rpc/server-service.js +3 -0
  227. package/dist/rpc/server-service.js.map +1 -0
  228. package/dist/rpc/server.d.ts +16 -19
  229. package/dist/rpc/server.d.ts.map +1 -1
  230. package/dist/rpc/server.js +59 -115
  231. package/dist/rpc/server.js.map +1 -1
  232. package/dist/rpc-client-sdk-entry.d.ts +12 -0
  233. package/dist/rpc-client-sdk-entry.d.ts.map +1 -0
  234. package/dist/rpc-client-sdk-entry.js +11 -0
  235. package/dist/rpc-client-sdk-entry.js.map +1 -0
  236. package/dist/rpc-entry.js +50 -18
  237. package/dist/rpc-entry.js.map +1 -1
  238. package/dist/rpc-server-entry.d.ts +8 -0
  239. package/dist/rpc-server-entry.d.ts.map +1 -0
  240. package/dist/rpc-server-entry.js +67 -0
  241. package/dist/rpc-server-entry.js.map +1 -0
  242. package/dist/runtime/attachment-store.d.ts +13 -0
  243. package/dist/runtime/attachment-store.d.ts.map +1 -0
  244. package/dist/runtime/attachment-store.js +93 -0
  245. package/dist/runtime/attachment-store.js.map +1 -0
  246. package/dist/runtime/bootstrap.d.ts +14 -0
  247. package/dist/runtime/bootstrap.d.ts.map +1 -0
  248. package/dist/runtime/bootstrap.js +29 -0
  249. package/dist/runtime/bootstrap.js.map +1 -0
  250. package/dist/runtime/interactive-host-service.d.ts +22 -0
  251. package/dist/runtime/interactive-host-service.d.ts.map +1 -0
  252. package/dist/runtime/interactive-host-service.js +2 -0
  253. package/dist/runtime/interactive-host-service.js.map +1 -0
  254. package/dist/runtime/interactive-resource-service.d.ts +11 -0
  255. package/dist/runtime/interactive-resource-service.d.ts.map +1 -0
  256. package/dist/runtime/interactive-resource-service.js +3 -0
  257. package/dist/runtime/interactive-resource-service.js.map +1 -0
  258. package/dist/runtime/plugin-inventory-entry.d.ts +5 -0
  259. package/dist/runtime/plugin-inventory-entry.d.ts.map +1 -0
  260. package/dist/runtime/plugin-inventory-entry.js +18 -0
  261. package/dist/runtime/plugin-inventory-entry.js.map +1 -0
  262. package/dist/runtime/plugin-inventory-service.d.ts +8 -0
  263. package/dist/runtime/plugin-inventory-service.d.ts.map +1 -0
  264. package/dist/runtime/plugin-inventory-service.js +3 -0
  265. package/dist/runtime/plugin-inventory-service.js.map +1 -0
  266. package/dist/runtime/plugin-manager-entry.d.ts +20 -0
  267. package/dist/runtime/plugin-manager-entry.d.ts.map +1 -0
  268. package/dist/runtime/plugin-manager-entry.js +96 -0
  269. package/dist/runtime/plugin-manager-entry.js.map +1 -0
  270. package/dist/runtime/plugin-observability-entry.d.ts +12 -0
  271. package/dist/runtime/plugin-observability-entry.d.ts.map +1 -0
  272. package/dist/runtime/plugin-observability-entry.js +73 -0
  273. package/dist/runtime/plugin-observability-entry.js.map +1 -0
  274. package/dist/runtime/product-host.d.ts +91 -0
  275. package/dist/runtime/product-host.d.ts.map +1 -0
  276. package/dist/runtime/product-host.js +529 -0
  277. package/dist/runtime/product-host.js.map +1 -0
  278. package/dist/runtime/session-factory.d.ts +17 -0
  279. package/dist/runtime/session-factory.d.ts.map +1 -0
  280. package/dist/runtime/session-factory.js +75 -0
  281. package/dist/runtime/session-factory.js.map +1 -0
  282. package/dist/runtime/session-host.d.ts +152 -0
  283. package/dist/runtime/session-host.d.ts.map +1 -0
  284. package/dist/runtime/session-host.js +895 -0
  285. package/dist/runtime/session-host.js.map +1 -0
  286. package/dist/runtime-core-entry.d.ts +11 -0
  287. package/dist/runtime-core-entry.d.ts.map +1 -0
  288. package/dist/runtime-core-entry.js +9 -0
  289. package/dist/runtime-core-entry.js.map +1 -0
  290. package/dist/session-factory-entry.d.ts +7 -0
  291. package/dist/session-factory-entry.d.ts.map +1 -0
  292. package/dist/session-factory-entry.js +9 -0
  293. package/dist/session-factory-entry.js.map +1 -0
  294. package/dist/session-store-jsonl-entry.d.ts +7 -0
  295. package/dist/session-store-jsonl-entry.d.ts.map +1 -0
  296. package/dist/session-store-jsonl-entry.js +33 -0
  297. package/dist/session-store-jsonl-entry.js.map +1 -0
  298. package/dist/startup.d.ts +21 -1
  299. package/dist/startup.d.ts.map +1 -1
  300. package/dist/startup.js +179 -10
  301. package/dist/startup.js.map +1 -1
  302. package/dist/subagents/index.d.ts +2 -0
  303. package/dist/subagents/index.d.ts.map +1 -0
  304. package/dist/subagents/index.js +2 -0
  305. package/dist/subagents/index.js.map +1 -0
  306. package/dist/subagents/service.d.ts +50 -0
  307. package/dist/subagents/service.d.ts.map +1 -0
  308. package/dist/subagents/service.js +521 -0
  309. package/dist/subagents/service.js.map +1 -0
  310. package/dist/ui-host.d.ts +125 -0
  311. package/dist/ui-host.d.ts.map +1 -0
  312. package/dist/ui-host.js +275 -0
  313. package/dist/ui-host.js.map +1 -0
  314. package/dist/web/assets/index-BwfuGMvv.css +1 -0
  315. package/dist/web/assets/index-DPUaJqFJ.js +41 -0
  316. package/dist/web/assets/index-DPUaJqFJ.js.map +1 -0
  317. package/dist/web/index.html +14 -0
  318. package/dist/web-command.d.ts +11 -0
  319. package/dist/web-command.d.ts.map +1 -0
  320. package/dist/web-command.js +114 -0
  321. package/dist/web-command.js.map +1 -0
  322. package/dist/web-frontend.d.ts +73 -0
  323. package/dist/web-frontend.d.ts.map +1 -0
  324. package/dist/web-frontend.js +249 -0
  325. package/dist/web-frontend.js.map +1 -0
  326. package/dist/web.d.ts +254 -0
  327. package/dist/web.d.ts.map +1 -0
  328. package/dist/web.js +740 -0
  329. package/dist/web.js.map +1 -0
  330. package/dist/webui-entry.d.ts +3 -0
  331. package/dist/webui-entry.d.ts.map +1 -0
  332. package/dist/webui-entry.js +73 -0
  333. package/dist/webui-entry.js.map +1 -0
  334. package/dist/webui.d.ts +91 -0
  335. package/dist/webui.d.ts.map +1 -0
  336. package/dist/webui.js +882 -0
  337. package/dist/webui.js.map +1 -0
  338. package/package.json +89 -8
package/dist/web.js ADDED
@@ -0,0 +1,740 @@
1
+ export const WEB_PROTOCOL_VERSION = 1;
2
+ export const WEB_MAX_ID_LENGTH = 128;
3
+ export const WEB_MAX_TOKEN_LENGTH = 4096;
4
+ export const WEB_MAX_PAYLOAD_BYTES = 1_048_576;
5
+ export const WEB_DEFAULT_REPLAY_LIMIT = 256;
6
+ function webSocketPayload(event) {
7
+ if (typeof event === "string")
8
+ return event;
9
+ if (event instanceof Uint8Array)
10
+ return new TextDecoder().decode(event);
11
+ const record = objectRecord(event);
12
+ if (record && typeof record.data === "string")
13
+ return record.data;
14
+ if (record && record.data instanceof Uint8Array)
15
+ return new TextDecoder().decode(record.data);
16
+ return String(event);
17
+ }
18
+ function webSocketListener(socket, type, listener) {
19
+ if (socket.addEventListener) {
20
+ socket.addEventListener(type, listener);
21
+ return () => socket.removeEventListener?.(type, listener);
22
+ }
23
+ if (socket.on) {
24
+ socket.on(type, listener);
25
+ return () => socket.off?.(type, listener);
26
+ }
27
+ const property = type === "message" ? "onmessage" : type === "close" ? "onclose" : "onopen";
28
+ const eventProperties = socket;
29
+ const previous = eventProperties[property];
30
+ eventProperties[property] = listener;
31
+ return () => {
32
+ if (eventProperties[property] === listener)
33
+ eventProperties[property] = previous ?? null;
34
+ };
35
+ }
36
+ /** Adapts a browser WebSocket or a Node `ws` instance to the host-neutral transport. */
37
+ export class WebSocketTransport {
38
+ socket;
39
+ removeMessage;
40
+ removeClose;
41
+ constructor(socket) {
42
+ this.socket = socket;
43
+ this.messageListeners = new Set();
44
+ this.closeListeners = new Set();
45
+ this.removeMessage = webSocketListener(socket, "message", (event) => {
46
+ const payload = webSocketPayload(event);
47
+ for (const listener of this.messageListeners)
48
+ listener(payload);
49
+ });
50
+ this.removeClose = webSocketListener(socket, "close", () => {
51
+ for (const listener of this.closeListeners)
52
+ listener();
53
+ });
54
+ }
55
+ messageListeners;
56
+ closeListeners;
57
+ send(message) {
58
+ this.socket.send(message);
59
+ }
60
+ close(code, reason) {
61
+ this.removeMessage();
62
+ this.removeClose();
63
+ this.socket.close?.(code, reason);
64
+ }
65
+ onMessage(listener) {
66
+ this.messageListeners.add(listener);
67
+ return () => this.messageListeners.delete(listener);
68
+ }
69
+ onClose(listener) {
70
+ this.closeListeners.add(listener);
71
+ return () => this.closeListeners.delete(listener);
72
+ }
73
+ }
74
+ /** Opens a browser WebSocket and resolves once its handshake is ready. */
75
+ export function connectWebSocketTransport(url, options = {}) {
76
+ const WebSocketClass = options.WebSocket ?? globalThis.WebSocket;
77
+ if (!WebSocketClass)
78
+ return Promise.reject(new Error("WebSocket is not available in this runtime."));
79
+ return new Promise((resolve, reject) => {
80
+ const socket = new WebSocketClass(url, options.protocols);
81
+ let settled = false;
82
+ const removeClose = webSocketListener(socket, "close", () => {
83
+ if (!settled) {
84
+ settled = true;
85
+ reject(new Error("WebSocket closed before connection."));
86
+ }
87
+ });
88
+ const record = socket;
89
+ const onOpen = () => {
90
+ if (settled)
91
+ return;
92
+ settled = true;
93
+ removeClose();
94
+ resolve(new WebSocketTransport(socket));
95
+ };
96
+ webSocketListener(record, "open", onOpen);
97
+ });
98
+ }
99
+ export class WebProtocolError extends Error {
100
+ code;
101
+ constructor(code, message) {
102
+ super(message);
103
+ this.name = "WebProtocolError";
104
+ this.code = code;
105
+ }
106
+ }
107
+ function objectRecord(value) {
108
+ return typeof value === "object" && value !== null && !Array.isArray(value)
109
+ ? value
110
+ : undefined;
111
+ }
112
+ function utf8ByteLength(value) {
113
+ return typeof TextEncoder === "function" ? new TextEncoder().encode(value).byteLength : value.length;
114
+ }
115
+ function requiredId(value, field) {
116
+ if (typeof value !== "string" ||
117
+ value.length === 0 ||
118
+ value.length > WEB_MAX_ID_LENGTH ||
119
+ value.trim() !== value ||
120
+ [...value].some((character) => {
121
+ const code = character.codePointAt(0) ?? 0;
122
+ return code <= 0x1f || code === 0x7f;
123
+ }))
124
+ throw new WebProtocolError("INVALID_MESSAGE", `${field} must be a non-empty identifier.`);
125
+ return value;
126
+ }
127
+ function optionalEventId(value, field) {
128
+ if (value === undefined)
129
+ return undefined;
130
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
131
+ throw new WebProtocolError("INVALID_MESSAGE", `${field} must be a non-negative safe integer.`);
132
+ return value;
133
+ }
134
+ function inputValue(value, field) {
135
+ if (typeof value === "string") {
136
+ if (!value.trim())
137
+ throw new WebProtocolError("INVALID_ACTION", `${field} must not be empty.`);
138
+ return value;
139
+ }
140
+ const record = objectRecord(value);
141
+ if (!record || typeof record.text !== "string" || !record.text.trim())
142
+ throw new WebProtocolError("INVALID_ACTION", `${field} must contain non-empty text.`);
143
+ if (record.images === undefined)
144
+ return { text: record.text };
145
+ if (!Array.isArray(record.images) || record.images.length > 4)
146
+ throw new WebProtocolError("INVALID_ACTION", `${field}.images must contain at most four images.`);
147
+ const images = record.images.map((image, index) => {
148
+ const item = objectRecord(image);
149
+ if (!item ||
150
+ item.type !== "image" ||
151
+ typeof item.mimeType !== "string" ||
152
+ typeof item.data !== "string" ||
153
+ item.data.length === 0)
154
+ throw new WebProtocolError("INVALID_ACTION", `${field}.images[${index}] is invalid.`);
155
+ return { type: "image", mimeType: item.mimeType, data: item.data };
156
+ });
157
+ return { text: record.text, images };
158
+ }
159
+ export function parseWebClientMessage(input) {
160
+ let value = input;
161
+ if (typeof input === "string") {
162
+ if (utf8ByteLength(input) > WEB_MAX_PAYLOAD_BYTES)
163
+ throw new WebProtocolError("INVALID_MESSAGE", "Web message is too large.");
164
+ try {
165
+ value = JSON.parse(input);
166
+ }
167
+ catch {
168
+ throw new WebProtocolError("INVALID_MESSAGE", "Web message must be valid JSON.");
169
+ }
170
+ }
171
+ const record = objectRecord(value);
172
+ if (!record || record.version !== WEB_PROTOCOL_VERSION)
173
+ throw new WebProtocolError("INVALID_MESSAGE", "Unsupported web protocol message.");
174
+ const requestId = requiredId(record.requestId, "requestId");
175
+ if (record.kind === "connect") {
176
+ const token = record.token;
177
+ if (typeof token !== "string" || token.length === 0 || token.length > WEB_MAX_TOKEN_LENGTH)
178
+ throw new WebProtocolError("INVALID_MESSAGE", "connect.token is invalid.");
179
+ return {
180
+ version: WEB_PROTOCOL_VERSION,
181
+ kind: "connect",
182
+ requestId,
183
+ token,
184
+ frontendId: requiredId(record.frontendId, "frontendId"),
185
+ ...(optionalEventId(record.lastEventId, "lastEventId") === undefined
186
+ ? {}
187
+ : { lastEventId: record.lastEventId }),
188
+ };
189
+ }
190
+ if (record.kind === "disconnect")
191
+ return { version: WEB_PROTOCOL_VERSION, kind: "disconnect", requestId };
192
+ if (record.kind !== "action")
193
+ throw new WebProtocolError("INVALID_MESSAGE", "Unknown web message kind.");
194
+ const action = objectRecord(record.action);
195
+ if (!action || typeof action.type !== "string")
196
+ throw new WebProtocolError("INVALID_ACTION", "Web action is invalid.");
197
+ let normalized;
198
+ switch (action.type) {
199
+ case "submit":
200
+ normalized = { type: "submit", input: inputValue(action.input, "submit.input") };
201
+ break;
202
+ case "steer":
203
+ normalized = { type: "steer", input: inputValue(action.input, "steer.input") };
204
+ break;
205
+ case "cancel":
206
+ case "retry":
207
+ case "create_session":
208
+ case "compact":
209
+ normalized = { type: action.type };
210
+ break;
211
+ case "run_command":
212
+ normalized = {
213
+ type: action.type,
214
+ name: requiredId(action.name, "action.name"),
215
+ args: typeof action.args === "string" ? action.args : "",
216
+ };
217
+ break;
218
+ case "select_model":
219
+ normalized = { type: action.type, modelId: requiredId(action.modelId, "action.modelId") };
220
+ break;
221
+ case "open_session":
222
+ normalized = { type: action.type, sessionId: requiredId(action.sessionId, "action.sessionId") };
223
+ break;
224
+ case "slot_action":
225
+ normalized = { type: action.type, slotId: requiredId(action.slotId, "action.slotId"), payload: action.payload };
226
+ break;
227
+ default:
228
+ throw new WebProtocolError("INVALID_ACTION", "Unknown web action.");
229
+ }
230
+ return {
231
+ version: WEB_PROTOCOL_VERSION,
232
+ kind: "action",
233
+ requestId,
234
+ action: normalized,
235
+ ...(optionalEventId(record.baseEventId, "baseEventId") === undefined
236
+ ? {}
237
+ : { baseEventId: record.baseEventId }),
238
+ };
239
+ }
240
+ export function parseWebServerMessage(input) {
241
+ let value = input;
242
+ if (typeof input === "string") {
243
+ if (utf8ByteLength(input) > WEB_MAX_PAYLOAD_BYTES)
244
+ throw new WebProtocolError("INVALID_MESSAGE", "Web message is too large.");
245
+ try {
246
+ value = JSON.parse(input);
247
+ }
248
+ catch {
249
+ throw new WebProtocolError("INVALID_MESSAGE", "Web message must be valid JSON.");
250
+ }
251
+ }
252
+ const record = objectRecord(value);
253
+ if (!record || record.version !== WEB_PROTOCOL_VERSION || typeof record.kind !== "string")
254
+ throw new WebProtocolError("INVALID_MESSAGE", "Web server message is invalid.");
255
+ if (!["hello", "event", "slots", "response", "error", "closed"].includes(record.kind))
256
+ throw new WebProtocolError("INVALID_MESSAGE", "Unknown web server message kind.");
257
+ if (record.kind === "event") {
258
+ if (optionalEventId(record.eventId, "eventId") === undefined)
259
+ throw new WebProtocolError("INVALID_MESSAGE", "Web event message must contain eventId.");
260
+ const event = objectRecord(record.event);
261
+ if (!event || typeof event.type !== "string")
262
+ throw new WebProtocolError("INVALID_MESSAGE", "Web event message is invalid.");
263
+ }
264
+ if (record.kind === "slots") {
265
+ if (!Array.isArray(record.slots))
266
+ throw new WebProtocolError("INVALID_MESSAGE", "Web slots message is invalid.");
267
+ for (const slot of record.slots) {
268
+ const item = objectRecord(slot);
269
+ if (!item || typeof item.id !== "string" || typeof item.title !== "string" || !Object.hasOwn(item, "data"))
270
+ throw new WebProtocolError("INVALID_MESSAGE", "Web slot is invalid.");
271
+ requiredId(item.id, "slot.id");
272
+ }
273
+ }
274
+ if (record.kind === "error") {
275
+ if (typeof record.code !== "string" ||
276
+ ![
277
+ "INVALID_MESSAGE",
278
+ "UNAUTHORIZED",
279
+ "FORBIDDEN",
280
+ "EXPIRED",
281
+ "STALE_EVENT",
282
+ "INVALID_ACTION",
283
+ "INTERNAL_ERROR",
284
+ ].includes(record.code) ||
285
+ typeof record.message !== "string" ||
286
+ record.message.length === 0)
287
+ throw new WebProtocolError("INVALID_MESSAGE", "Web error message is invalid.");
288
+ }
289
+ if (record.kind === "response") {
290
+ requiredId(record.requestId, "requestId");
291
+ if (record.ok !== true)
292
+ throw new WebProtocolError("INVALID_MESSAGE", "Web response message is invalid.");
293
+ }
294
+ if (record.kind === "hello") {
295
+ requiredId(record.requestId, "requestId");
296
+ requiredId(record.connectionId, "connectionId");
297
+ requiredId(record.sessionId, "sessionId");
298
+ optionalEventId(record.eventId, "eventId");
299
+ if (!Array.isArray(record.slots) || !objectRecord(record.state))
300
+ throw new WebProtocolError("INVALID_MESSAGE", "Web hello message is invalid.");
301
+ }
302
+ return record;
303
+ }
304
+ function sameSecret(actual, expected) {
305
+ if (actual.length !== expected.length)
306
+ return false;
307
+ let difference = 0;
308
+ for (let index = 0; index < actual.length; index++)
309
+ difference |= actual.charCodeAt(index) ^ expected.charCodeAt(index);
310
+ return difference === 0;
311
+ }
312
+ function connectionId() {
313
+ const cryptoObject = globalThis.crypto;
314
+ if (typeof cryptoObject?.randomUUID === "function")
315
+ return cryptoObject.randomUUID();
316
+ return `web-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
317
+ }
318
+ function validateAuthorization(value) {
319
+ if (typeof value.token !== "string" || value.token.length === 0 || value.token.length > WEB_MAX_TOKEN_LENGTH)
320
+ throw new Error("Web authorization token is invalid.");
321
+ if ([...value.token].some((character) => (character.codePointAt(0) ?? 0) <= 0x1f || character === "\u007f"))
322
+ throw new Error("Web authorization token contains a control character.");
323
+ for (const id of value.allowedFrontendIds)
324
+ requiredId(id, "allowedFrontendIds item");
325
+ for (const id of value.allowedSlotIds)
326
+ requiredId(id, "allowedSlotIds item");
327
+ if (value.allowedActions?.some((action) => ![
328
+ "submit",
329
+ "steer",
330
+ "cancel",
331
+ "retry",
332
+ "run_command",
333
+ "select_model",
334
+ "open_session",
335
+ "create_session",
336
+ "compact",
337
+ "slot_action",
338
+ ].includes(action)))
339
+ throw new Error("Web authorization contains an unknown action.");
340
+ if (value.expiresAt !== undefined && (!Number.isSafeInteger(value.expiresAt) || value.expiresAt < 0))
341
+ throw new Error("Web authorization expiry must be a non-negative safe integer.");
342
+ }
343
+ function cloneSlots(controller, allowed) {
344
+ const allow = new Set(allowed);
345
+ const slots = [];
346
+ for (const panel of controller.ui.panels) {
347
+ if (!allow.has(panel.id))
348
+ continue;
349
+ try {
350
+ slots.push({ id: panel.id, title: panel.title, data: structuredClone(panel.data) });
351
+ }
352
+ catch {
353
+ // Non-serializable plugin panel data is not exposed to the browser.
354
+ }
355
+ }
356
+ return slots;
357
+ }
358
+ /** Versioned Web projection. Disconnecting a page only detaches its transport. */
359
+ export class WebFrontendHost {
360
+ controller;
361
+ authorization;
362
+ replayLimit;
363
+ now;
364
+ slotActions;
365
+ events = [];
366
+ connections = new Set();
367
+ eventId = 0;
368
+ disposed = false;
369
+ unsubscribeController;
370
+ constructor(options) {
371
+ validateAuthorization(options.authorization);
372
+ this.controller = options.controller;
373
+ this.authorization = {
374
+ ...options.authorization,
375
+ allowedFrontendIds: [...options.authorization.allowedFrontendIds],
376
+ allowedSlotIds: [...options.authorization.allowedSlotIds],
377
+ ...(options.authorization.allowedActions === undefined
378
+ ? {}
379
+ : { allowedActions: [...options.authorization.allowedActions] }),
380
+ };
381
+ this.replayLimit = Math.max(1, Math.min(options.replayLimit ?? WEB_DEFAULT_REPLAY_LIMIT, 4096));
382
+ this.now = options.now ?? Date.now;
383
+ this.slotActions = options.slotActions;
384
+ this.unsubscribeController = options.controller.subscribe((event) => this.publish(event));
385
+ }
386
+ attach(transport) {
387
+ if (this.disposed)
388
+ throw new Error("Web frontend host is disposed.");
389
+ const connection = new WebConnection(this, transport);
390
+ this.connections.add(connection);
391
+ connection.onDispose = () => this.connections.delete(connection);
392
+ return connection;
393
+ }
394
+ get latestEventId() {
395
+ return this.eventId;
396
+ }
397
+ async dispose() {
398
+ if (this.disposed)
399
+ return;
400
+ this.disposed = true;
401
+ for (const connection of [...this.connections])
402
+ connection.dispose();
403
+ this.unsubscribeController.dispose();
404
+ this.controller.dispose();
405
+ }
406
+ publish(event) {
407
+ if (this.disposed)
408
+ return;
409
+ const envelope = { eventId: ++this.eventId, event: structuredClone(event) };
410
+ this.events.push(envelope);
411
+ while (this.events.length > this.replayLimit)
412
+ this.events.shift();
413
+ for (const connection of this.connections) {
414
+ connection.sendEvent(envelope);
415
+ if (connection.authorized)
416
+ connection.sendSlots(cloneSlots(this.controller, this.authorization.allowedSlotIds));
417
+ }
418
+ }
419
+ authorize(token, frontendId) {
420
+ if (this.authorization.expiresAt !== undefined && this.now() >= this.authorization.expiresAt)
421
+ throw new WebProtocolError("EXPIRED", "Web authorization has expired.");
422
+ if (!sameSecret(token, this.authorization.token))
423
+ throw new WebProtocolError("UNAUTHORIZED", "Web authorization failed.");
424
+ if (!this.authorization.allowedFrontendIds.includes(frontendId))
425
+ throw new WebProtocolError("FORBIDDEN", "Frontend is not authorized.");
426
+ }
427
+ _handleConnect(connection, request) {
428
+ this.authorize(request.token, request.frontendId);
429
+ connection.authorized = true;
430
+ const current = this.eventId;
431
+ const replayFrom = request.lastEventId;
432
+ const oldest = this.events[0]?.eventId;
433
+ const canReplay = replayFrom !== undefined && (oldest === undefined || replayFrom >= oldest - 1);
434
+ connection.send({
435
+ version: WEB_PROTOCOL_VERSION,
436
+ kind: "hello",
437
+ requestId: request.requestId,
438
+ connectionId: connection.id,
439
+ sessionId: this.controller.state.sessionId,
440
+ state: structuredClone(this.controller.state),
441
+ slots: cloneSlots(this.controller, this.authorization.allowedSlotIds),
442
+ eventId: current,
443
+ ...(canReplay && replayFrom !== undefined ? { replayedFrom: replayFrom } : {}),
444
+ ...(replayFrom !== undefined && !canReplay ? { resyncRequired: true } : {}),
445
+ });
446
+ if (canReplay && replayFrom !== undefined)
447
+ for (const event of this.events)
448
+ if (event.eventId > replayFrom)
449
+ connection.sendEvent(event);
450
+ }
451
+ async _handleAction(connection, request) {
452
+ if (!connection.authorized)
453
+ throw new WebProtocolError("UNAUTHORIZED", "Connect before sending actions.");
454
+ if (this.authorization.allowedActions !== undefined &&
455
+ !this.authorization.allowedActions.includes(request.action.type))
456
+ throw new WebProtocolError("FORBIDDEN", "Web action is not authorized.");
457
+ if (request.baseEventId !== undefined && request.baseEventId < this.eventId - this.replayLimit)
458
+ throw new WebProtocolError("STALE_EVENT", "Action references an expired event.");
459
+ const action = request.action;
460
+ switch (action.type) {
461
+ case "submit":
462
+ await this.controller.submit(action.input);
463
+ break;
464
+ case "steer":
465
+ this.controller.steer(action.input);
466
+ break;
467
+ case "cancel":
468
+ this.controller.cancel();
469
+ break;
470
+ case "retry":
471
+ await this.controller.retry();
472
+ break;
473
+ case "run_command":
474
+ await this.controller.runCommand(action.name, action.args);
475
+ break;
476
+ case "select_model":
477
+ this.controller.selectModel(action.modelId);
478
+ break;
479
+ case "open_session":
480
+ await this.controller.openSession(action.sessionId);
481
+ break;
482
+ case "create_session":
483
+ await this.controller.createSession();
484
+ break;
485
+ case "compact":
486
+ await this.controller.requestCompaction();
487
+ break;
488
+ case "slot_action":
489
+ if (!this.authorization.allowedSlotIds.includes(action.slotId) || !this.slotActions?.[action.slotId])
490
+ throw new WebProtocolError("FORBIDDEN", "Slot action is not authorized.");
491
+ await this.slotActions[action.slotId](action.payload, { sessionId: this.controller.state.sessionId });
492
+ break;
493
+ }
494
+ connection.send({
495
+ version: WEB_PROTOCOL_VERSION,
496
+ kind: "response",
497
+ requestId: request.requestId,
498
+ ok: true,
499
+ result: { accepted: true, eventId: this.eventId },
500
+ });
501
+ }
502
+ }
503
+ export class WebConnection {
504
+ id = connectionId();
505
+ authorized = false;
506
+ onDispose;
507
+ transport;
508
+ removeMessage;
509
+ removeClose;
510
+ disposed = false;
511
+ constructor(host, transport) {
512
+ this.transport = transport;
513
+ this.removeMessage = transport.onMessage((raw) => {
514
+ try {
515
+ const message = parseWebClientMessage(raw);
516
+ if (message.kind === "connect")
517
+ host._handleConnect(this, message);
518
+ else if (message.kind === "disconnect")
519
+ this.dispose();
520
+ else
521
+ void host._handleAction(this, message).catch((cause) => this.error(cause));
522
+ }
523
+ catch (cause) {
524
+ this.error(cause);
525
+ }
526
+ });
527
+ this.removeClose = transport.onClose(() => this.dispose());
528
+ }
529
+ send(message) {
530
+ if (!this.disposed)
531
+ this.transport.send(JSON.stringify(message));
532
+ }
533
+ sendEvent(envelope) {
534
+ this.send({ version: WEB_PROTOCOL_VERSION, kind: "event", eventId: envelope.eventId, event: envelope.event });
535
+ }
536
+ sendSlots(slots) {
537
+ this.send({ version: WEB_PROTOCOL_VERSION, kind: "slots", slots });
538
+ }
539
+ dispose() {
540
+ if (this.disposed)
541
+ return;
542
+ this.disposed = true;
543
+ try {
544
+ this.transport.send(JSON.stringify({ version: WEB_PROTOCOL_VERSION, kind: "closed" }));
545
+ }
546
+ catch {
547
+ // The page may already have disappeared; cleanup must still run.
548
+ }
549
+ finally {
550
+ this.removeMessage();
551
+ this.removeClose();
552
+ try {
553
+ this.transport.close?.(1000, "page detached");
554
+ }
555
+ catch {
556
+ // Transport teardown is best effort.
557
+ }
558
+ finally {
559
+ this.onDispose?.();
560
+ }
561
+ }
562
+ }
563
+ error(cause) {
564
+ const error = cause instanceof WebProtocolError
565
+ ? cause
566
+ : new WebProtocolError("INTERNAL_ERROR", cause instanceof Error ? cause.message : String(cause));
567
+ this.send({ version: WEB_PROTOCOL_VERSION, kind: "error", code: error.code, message: error.message });
568
+ }
569
+ }
570
+ /** Small browser-side state adapter. It never owns or disposes the Host. */
571
+ export class WebClient {
572
+ transport;
573
+ listeners = new Set();
574
+ pending = new Map();
575
+ removeMessage;
576
+ removeClose;
577
+ closed = false;
578
+ transportClosed = false;
579
+ _state;
580
+ _slots = [];
581
+ _eventId = 0;
582
+ constructor(transport) {
583
+ this.transport = transport;
584
+ this.removeMessage = () => undefined;
585
+ this.removeClose = () => undefined;
586
+ this.installTransport(transport);
587
+ }
588
+ get state() {
589
+ return this._state;
590
+ }
591
+ get slots() {
592
+ return this._slots;
593
+ }
594
+ get eventId() {
595
+ return this._eventId;
596
+ }
597
+ subscribe(listener) {
598
+ this.listeners.add(listener);
599
+ return () => this.listeners.delete(listener);
600
+ }
601
+ connect(token, frontendId, lastEventId) {
602
+ this.transportClosed = false;
603
+ return this.request({
604
+ version: WEB_PROTOCOL_VERSION,
605
+ kind: "connect",
606
+ requestId: connectionId(),
607
+ token,
608
+ frontendId,
609
+ ...(lastEventId === undefined ? {} : { lastEventId }),
610
+ }).then((message) => message);
611
+ }
612
+ /** Replaces a disconnected transport and requests a snapshot/replay from the last event. */
613
+ reconnect(transport, token, frontendId) {
614
+ if (this.closed)
615
+ return Promise.reject(new Error("Web client is closed."));
616
+ this.removeTransport();
617
+ this.transport = transport;
618
+ this.transportClosed = false;
619
+ this.installTransport(transport);
620
+ return this.connect(token, frontendId, this._eventId);
621
+ }
622
+ action(action, baseEventId = this._eventId) {
623
+ return this.request({
624
+ version: WEB_PROTOCOL_VERSION,
625
+ kind: "action",
626
+ requestId: connectionId(),
627
+ action,
628
+ baseEventId,
629
+ }).then(() => undefined);
630
+ }
631
+ close() {
632
+ if (this.closed)
633
+ return;
634
+ this.closed = true;
635
+ this.removeTransport();
636
+ this.transport.close?.(1000, "client closed");
637
+ for (const pending of this.pending.values())
638
+ pending.reject(new Error("Web client is closed."));
639
+ this.pending.clear();
640
+ }
641
+ request(message) {
642
+ if (this.closed)
643
+ return Promise.reject(new Error("Web client is closed."));
644
+ return new Promise((resolve, reject) => {
645
+ this.pending.set(message.requestId, { resolve, reject });
646
+ try {
647
+ this.transport.send(JSON.stringify(message));
648
+ }
649
+ catch (cause) {
650
+ this.pending.delete(message.requestId);
651
+ reject(cause instanceof Error ? cause : new Error(String(cause)));
652
+ }
653
+ });
654
+ }
655
+ accept(raw) {
656
+ try {
657
+ const message = parseWebServerMessage(raw);
658
+ if (message.kind === "hello") {
659
+ this._state = structuredClone(message.state);
660
+ this._slots = [...(message.slots ?? [])];
661
+ this._eventId = message.eventId ?? this._eventId;
662
+ this.resolve(message.requestId, message);
663
+ this.emit({ type: "hello", message: message });
664
+ }
665
+ else if (message.kind === "event") {
666
+ this._eventId = Math.max(this._eventId, message.eventId ?? 0);
667
+ this.emit({ type: "event", message: message });
668
+ }
669
+ else if (message.kind === "slots") {
670
+ this._slots = [...(message.slots ?? [])];
671
+ this.emit({ type: "slots", slots: this._slots });
672
+ }
673
+ else if (message.kind === "response")
674
+ this.resolve(message.requestId, message);
675
+ else if (message.kind === "error") {
676
+ const error = new WebProtocolError(message.code ?? "INTERNAL_ERROR", message.message ?? "Web request failed.");
677
+ this.reject(message.requestId, error);
678
+ this.emit({ type: "error", code: error.code, message: error.message });
679
+ }
680
+ else
681
+ this.emit({ type: "closed" });
682
+ }
683
+ catch (cause) {
684
+ this.fail(cause instanceof Error ? cause : new Error(String(cause)));
685
+ }
686
+ }
687
+ resolve(requestId, value) {
688
+ if (!requestId)
689
+ return;
690
+ const pending = this.pending.get(requestId);
691
+ if (pending) {
692
+ this.pending.delete(requestId);
693
+ pending.resolve(value);
694
+ }
695
+ }
696
+ reject(requestId, cause) {
697
+ if (!requestId)
698
+ return;
699
+ const pending = this.pending.get(requestId);
700
+ if (pending) {
701
+ this.pending.delete(requestId);
702
+ pending.reject(cause);
703
+ }
704
+ }
705
+ emit(event) {
706
+ for (const listener of this.listeners)
707
+ listener(event);
708
+ }
709
+ fail(cause) {
710
+ if (this.closed || this.transportClosed)
711
+ return;
712
+ this.transportClosed = true;
713
+ this.removeTransport();
714
+ for (const pending of this.pending.values())
715
+ pending.reject(cause);
716
+ this.pending.clear();
717
+ this.emit({ type: "error", code: "INTERNAL_ERROR", message: cause.message });
718
+ }
719
+ installTransport(transport) {
720
+ this.removeMessage = transport.onMessage((raw) => this.accept(raw));
721
+ this.removeClose = transport.onClose(() => this.fail(new Error("Web transport closed.")));
722
+ }
723
+ removeTransport() {
724
+ this.removeMessage();
725
+ this.removeClose();
726
+ this.removeMessage = () => undefined;
727
+ this.removeClose = () => undefined;
728
+ }
729
+ }
730
+ export function createWebAuthorization(options) {
731
+ const value = {
732
+ token: options.token,
733
+ allowedFrontendIds: [...(options.allowedFrontendIds ?? [])],
734
+ allowedSlotIds: [...(options.allowedSlotIds ?? [])],
735
+ ...(options.expiresAt === undefined ? {} : { expiresAt: options.expiresAt }),
736
+ };
737
+ validateAuthorization(value);
738
+ return value;
739
+ }
740
+ //# sourceMappingURL=web.js.map