@kiberon-labs/behave-graph-flow 1.0.0 → 3.0.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 (378) hide show
  1. package/.fallowrc.json +16 -0
  2. package/.storybook/main.ts +32 -0
  3. package/.storybook/manager.ts +6 -0
  4. package/.storybook/preview.ts +64 -0
  5. package/.storybook/styles.css +16 -0
  6. package/.turbo/turbo-build.log +7 -0
  7. package/CHANGELOG.md +368 -0
  8. package/LICENSE +6 -0
  9. package/README.md +2 -2
  10. package/data/Polynomial.json +510 -0
  11. package/data/sequence.json +337 -0
  12. package/data/trigger-event.json +241 -0
  13. package/data/variable-change.json +210 -0
  14. package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
  15. package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
  16. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
  17. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
  18. package/dist/entry.css +4 -0
  19. package/dist/index.css +42 -0
  20. package/dist/index.css.map +1 -0
  21. package/dist/index.d.ts +3597 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +18009 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/noteImpl-KkrrWgJd.js +242 -0
  26. package/dist/noteImpl-KkrrWgJd.js.map +1 -0
  27. package/dist/styles.module-CvmpDkZj.css +3 -0
  28. package/dist/styles.module-CvmpDkZj.css.map +1 -0
  29. package/dist/styles.module-DZxg8aW9.js +271 -0
  30. package/dist/styles.module-DZxg8aW9.js.map +1 -0
  31. package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
  32. package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
  33. package/docs/notifications.md +246 -0
  34. package/docs/protocol.md +702 -0
  35. package/docs/specifics.md +191 -0
  36. package/package.json +82 -22
  37. package/postcss.config.ts +3 -4
  38. package/src/annotations/index.ts +32 -0
  39. package/src/components/FloatingToolbar/index.module.css +37 -0
  40. package/src/components/FloatingToolbar/index.tsx +256 -0
  41. package/src/components/Flow.tsx +287 -75
  42. package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
  43. package/src/components/contextMenus/NodePicker.module.css +274 -0
  44. package/src/components/contextMenus/NodePicker.tsx +481 -0
  45. package/src/components/contextMenus/edge.tsx +22 -0
  46. package/src/components/contextMenus/node.tsx +15 -0
  47. package/src/components/contextMenus/selection.tsx +11 -0
  48. package/src/components/controls/any/AnyControlImpl.tsx +14 -0
  49. package/src/components/controls/any/index.tsx +19 -0
  50. package/src/components/controls/boolean/index.tsx +13 -0
  51. package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
  52. package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
  53. package/src/components/controls/colorPicker/index.module.css +18 -0
  54. package/src/components/controls/colorPicker/index.tsx +61 -0
  55. package/src/components/controls/number/index.tsx +35 -0
  56. package/src/components/controls/string/index.tsx +16 -0
  57. package/src/components/edges/index.tsx +475 -0
  58. package/src/components/edges/offsetBezier.ts +134 -0
  59. package/src/components/hotKeys.tsx +20 -0
  60. package/src/components/layoutController/index.module.css +13 -0
  61. package/src/components/layoutController/index.tsx +140 -0
  62. package/src/components/layoutController/utils.ts +248 -0
  63. package/src/components/menubar/defaults.tsx +516 -0
  64. package/src/components/menubar/index.tsx +49 -0
  65. package/src/components/menubar/menuItem.module.css +31 -0
  66. package/src/components/menubar/menuItem.tsx +65 -0
  67. package/src/components/nodes/behave/Node.module.css +23 -0
  68. package/src/components/nodes/behave/Node.tsx +176 -0
  69. package/src/components/nodes/behave/NodeContainer.module.css +88 -0
  70. package/src/components/nodes/behave/NodeContainer.tsx +46 -0
  71. package/src/components/nodes/behave/index.tsx +14 -0
  72. package/src/components/nodes/group/index.tsx +109 -0
  73. package/src/components/nodes/wrapper/index.tsx +73 -0
  74. package/src/components/nodes/wrapper/styles.module.css +87 -0
  75. package/src/components/notifications/NotificationProvider.tsx +81 -0
  76. package/src/components/notifications/index.ts +2 -0
  77. package/src/components/notifications/utils.ts +71 -0
  78. package/src/components/panels/alignment/index.module.css +10 -0
  79. package/src/components/panels/alignment/index.tsx +244 -0
  80. package/src/components/panels/base/index.tsx +5 -0
  81. package/src/components/panels/base/styles.module.css +12 -0
  82. package/src/components/panels/common/PanelHeader.module.css +24 -0
  83. package/src/components/panels/common/PanelHeader.tsx +22 -0
  84. package/src/components/panels/common/SectionTitle.module.css +13 -0
  85. package/src/components/panels/common/SectionTitle.tsx +10 -0
  86. package/src/components/panels/events/EditEventPanel.tsx +324 -0
  87. package/src/components/panels/events/ManageEventsPanel.tsx +101 -0
  88. package/src/components/panels/events/index.tsx +23 -0
  89. package/src/components/panels/events/styles.module.css +178 -0
  90. package/src/components/panels/graphProperties/index.tsx +125 -0
  91. package/src/components/panels/history/index.tsx +92 -0
  92. package/src/components/panels/history/styles.module.css +97 -0
  93. package/src/components/panels/keymaps/index.module.css +68 -0
  94. package/src/components/panels/keymaps/index.tsx +166 -0
  95. package/src/components/panels/layers/index.tsx +245 -0
  96. package/src/components/panels/layers/styles.module.css +107 -0
  97. package/src/components/panels/legend/index.module.css +6 -0
  98. package/src/components/panels/legend/index.tsx +76 -0
  99. package/src/components/panels/logs/index.module.css +218 -0
  100. package/src/components/panels/logs/index.tsx +288 -0
  101. package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
  102. package/src/components/panels/nodeInputs/InputsGroup.tsx +65 -0
  103. package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
  104. package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
  105. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
  106. package/src/components/panels/nodeInputs/OutputsGroup.tsx +55 -0
  107. package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
  108. package/src/components/panels/nodeInputs/index.module.css +308 -0
  109. package/src/components/panels/nodeInputs/index.tsx +349 -0
  110. package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
  111. package/src/components/panels/nodeInputs/useNodeInputsData.ts +153 -0
  112. package/src/components/panels/nodePicker/index.tsx +115 -0
  113. package/src/components/panels/panel/index.module.css +66 -0
  114. package/src/components/panels/panel/index.tsx +88 -0
  115. package/src/components/panels/search/index.module.css +16 -0
  116. package/src/components/panels/search/index.tsx +215 -0
  117. package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
  118. package/src/components/panels/systemSettings/index.tsx +251 -0
  119. package/src/components/panels/systemSettings/styles.module.css +138 -0
  120. package/src/components/panels/traces/GridLines.tsx +38 -0
  121. package/src/components/panels/traces/TimeGrid.tsx +48 -0
  122. package/src/components/panels/traces/TraceLane.tsx +62 -0
  123. package/src/components/panels/traces/TraceTooltip.tsx +22 -0
  124. package/src/components/panels/traces/TracesHeader.tsx +56 -0
  125. package/src/components/panels/traces/index.module.css +159 -0
  126. package/src/components/panels/traces/index.tsx +298 -0
  127. package/src/components/panels/traces/types.ts +48 -0
  128. package/src/components/panels/traces/useDerivedSpans.ts +307 -0
  129. package/src/components/panels/traces/utils.ts +33 -0
  130. package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
  131. package/src/components/panels/variables/ManageVariablesScreen.tsx +147 -0
  132. package/src/components/panels/variables/index.tsx +125 -0
  133. package/src/components/panels/variables/styles.module.css +149 -0
  134. package/src/components/primitives/icon.module.css +45 -0
  135. package/src/components/primitives/icon.tsx +38 -0
  136. package/src/components/sockets/input/index.tsx +83 -0
  137. package/src/components/sockets/input/styles.module.css +26 -0
  138. package/src/components/sockets/output/index.tsx +68 -0
  139. package/src/components/sockets/output/styles.module.css +22 -0
  140. package/src/css/notes.css +135 -0
  141. package/src/css/prosemirror.css +57 -0
  142. package/src/css/rc-dock.css +212 -0
  143. package/src/css/rc-menu.css +101 -0
  144. package/src/css/themes/kiberon.css +127 -0
  145. package/src/css/vars.css +198 -0
  146. package/src/css/vscode-elements.css +124 -0
  147. package/src/entry.css +4 -0
  148. package/src/generators/CallSubgraphGenerator.tsx +136 -0
  149. package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
  150. package/src/generators/GraphBoundaryGenerator.module.css +32 -0
  151. package/src/generators/GraphBoundaryGenerator.tsx +193 -0
  152. package/src/generators/SequenceGenerator.tsx +104 -0
  153. package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
  154. package/src/generators/SwitchOnStringGenerator.tsx +263 -0
  155. package/src/generators/callSubgraphSync.ts +126 -0
  156. package/src/generators/registerDefaultGenerators.ts +55 -0
  157. package/src/generators/registerDefaults.ts +26 -0
  158. package/src/hooks/useBehaveGraphFlow.ts +17 -16
  159. package/src/hooks/useFlowHandlers.ts +154 -30
  160. package/src/hooks/useWasdPan.ts +210 -0
  161. package/src/index.css +134 -0
  162. package/src/index.ts +53 -18
  163. package/src/manifest/contributionRegistry.ts +93 -0
  164. package/src/manifest/index.ts +4 -0
  165. package/src/manifest/loadManifest.ts +82 -0
  166. package/src/manifest/manifestPlugin.ts +29 -0
  167. package/src/manifest/passthroughValueType.ts +40 -0
  168. package/src/plugin/alignment/index.ts +91 -0
  169. package/src/plugin/autosave/controller.ts +366 -0
  170. package/src/plugin/autosave/index.tsx +114 -0
  171. package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
  172. package/src/plugin/autosave/panel/index.tsx +1 -0
  173. package/src/plugin/autosave/panel/styles.module.css +56 -0
  174. package/src/plugin/autosave/settings.ts +65 -0
  175. package/src/plugin/autosave/storage.ts +147 -0
  176. package/src/plugin/docs/index.tsx +297 -0
  177. package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
  178. package/src/plugin/docs/panel/index.tsx +21 -0
  179. package/src/plugin/docs/panel/styles.module.css +174 -0
  180. package/src/plugin/graphrunner/actions.ts +326 -0
  181. package/src/plugin/graphrunner/buttons.tsx +95 -0
  182. package/src/plugin/graphrunner/client.ts +707 -0
  183. package/src/plugin/graphrunner/index.tsx +184 -0
  184. package/src/plugin/graphrunner/panel.tsx +386 -0
  185. package/src/plugin/graphrunner/runController.ts +283 -0
  186. package/src/plugin/graphrunner/runner.ts +187 -0
  187. package/src/plugin/graphrunner/session.ts +243 -0
  188. package/src/plugin/graphrunner/store.ts +196 -0
  189. package/src/plugin/graphrunner/styles.module.css +171 -0
  190. package/src/plugin/graphrunner/transport.ts +250 -0
  191. package/src/plugin/graphrunner/types.ts +693 -0
  192. package/src/plugin/graphrunner-local/execution-utils.ts +637 -0
  193. package/src/plugin/graphrunner-local/index.tsx +172 -0
  194. package/src/plugin/graphrunner-local/panel.tsx +187 -0
  195. package/src/plugin/graphrunner-local/store.ts +41 -0
  196. package/src/plugin/graphrunner-local/styles.module.css +82 -0
  197. package/src/plugin/graphrunner-local/transport.ts +1339 -0
  198. package/src/plugin/graphrunner-local/types.ts +10 -0
  199. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +635 -0
  200. package/src/plugin/graphrunner-webworker/index.tsx +140 -0
  201. package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
  202. package/src/plugin/graphrunner-webworker/store.ts +98 -0
  203. package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
  204. package/src/plugin/kitchen-sink/index.ts +38 -0
  205. package/src/plugin/layout/dagre.ts +131 -0
  206. package/src/plugin/layout/elk.ts +216 -0
  207. package/src/plugin/layout/index.ts +80 -0
  208. package/src/plugin/notes/FormatToolbar.tsx +200 -0
  209. package/src/plugin/notes/index.tsx +191 -0
  210. package/src/plugin/notes/nodeActions.ts +100 -0
  211. package/src/plugin/notes/note.tsx +20 -0
  212. package/src/plugin/notes/noteImpl.tsx +89 -0
  213. package/src/plugin/realtime/realtimeRunner.ts +624 -0
  214. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
  215. package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
  216. package/src/specifics/VariableGetSpecific.tsx +110 -0
  217. package/src/specifics/VariableSetSpecific.tsx +110 -0
  218. package/src/store/actions.tsx +698 -0
  219. package/src/store/commands.ts +278 -0
  220. package/src/store/contextMenu.ts +192 -0
  221. package/src/store/controls.tsx +62 -0
  222. package/src/store/conversions.ts +47 -0
  223. package/src/store/documentation.tsx +69 -0
  224. package/src/store/events.tsx +116 -0
  225. package/src/store/flow.tsx +230 -0
  226. package/src/store/graphMeta.ts +39 -0
  227. package/src/store/hotKeys.tsx +364 -0
  228. package/src/store/layers.ts +259 -0
  229. package/src/store/legend.tsx +76 -0
  230. package/src/store/logs.ts +28 -0
  231. package/src/store/menubar.ts +41 -0
  232. package/src/store/refs.ts +84 -0
  233. package/src/store/registry.ts +51 -0
  234. package/src/store/selection.ts +22 -0
  235. package/src/store/settings.ts +99 -0
  236. package/src/store/settingsSchema.ts +210 -0
  237. package/src/store/socketGenerator.tsx +54 -0
  238. package/src/store/specific.tsx +75 -0
  239. package/src/store/specs.tsx +35 -0
  240. package/src/store/tabs.ts +282 -0
  241. package/src/store/toolbar.tsx +45 -0
  242. package/src/store/traces.ts +240 -0
  243. package/src/store/variables.ts +37 -0
  244. package/src/system/graph.ts +131 -0
  245. package/src/system/graphSession.ts +172 -0
  246. package/src/system/index.ts +6 -0
  247. package/src/system/notifications.ts +111 -0
  248. package/src/system/persistence.ts +82 -0
  249. package/src/system/plugin.ts +55 -0
  250. package/src/system/provider.tsx +86 -0
  251. package/src/system/pubsub.ts +323 -0
  252. package/src/system/system.ts +653 -0
  253. package/src/system/tabLoader.tsx +303 -0
  254. package/src/system/undoRedo.ts +103 -0
  255. package/src/transformers/Uigraph.ts +61 -0
  256. package/src/transformers/behaveToFlow.ts +16 -4
  257. package/src/transformers/contract.ts +87 -0
  258. package/src/transformers/flowToBehave.ts +40 -12
  259. package/src/types/NodeMetadata.ts +27 -0
  260. package/src/types/graph.ts +49 -0
  261. package/src/types/nodes.ts +50 -0
  262. package/src/types.ts +18 -0
  263. package/src/util/autoConvert.ts +200 -0
  264. package/src/util/colors.ts +1 -29
  265. package/src/util/downloadJson.ts +18 -0
  266. package/src/util/extractNodeMetadata.ts +16 -0
  267. package/src/util/getPickerFilters.ts +1 -1
  268. package/src/util/isBehaveNode.ts +6 -0
  269. package/src/util/isValidConnection.ts +51 -17
  270. package/src/util/mergeSockets.ts +29 -0
  271. package/src/util/serializeVariables.ts +66 -0
  272. package/src/util/sockets.ts +43 -0
  273. package/stories/apex/layoutController/example-graph.worker.ts +39 -0
  274. package/stories/apex/layoutController/index.stories.tsx +48 -0
  275. package/stories/apex/layoutController/webworker.stories.tsx +103 -0
  276. package/stories/apex/menubar/menubar.stories.tsx +19 -0
  277. package/stories/components/colorpicker/index.stories.tsx +20 -0
  278. package/stories/components/contextMenus/edge.stories.tsx +32 -0
  279. package/stories/components/contextMenus/node.stories.tsx +26 -0
  280. package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
  281. package/stories/components/controls/any/index.stories.tsx +19 -0
  282. package/stories/components/controls/boolean/index.stories.tsx +19 -0
  283. package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
  284. package/stories/components/controls/number/index.stories.tsx +19 -0
  285. package/stories/components/controls/string/index.stories.tsx +19 -0
  286. package/stories/components/nodes/behaveNode.stories.tsx +108 -0
  287. package/stories/components/panels/alignment.stories.tsx +24 -0
  288. package/stories/components/panels/events.stories.tsx +38 -0
  289. package/stories/components/panels/graphRunner.stories.tsx +317 -0
  290. package/stories/components/panels/history.stories.tsx +37 -0
  291. package/stories/components/panels/keymaps.stories.tsx +21 -0
  292. package/stories/components/panels/legend.stories.tsx +37 -0
  293. package/stories/components/panels/logs.stories.tsx +24 -0
  294. package/stories/components/panels/nodeInputs.stories.tsx +21 -0
  295. package/stories/components/panels/nodePicker.stories.tsx +37 -0
  296. package/stories/components/panels/panel.stories.tsx +39 -0
  297. package/stories/components/panels/search.stories.tsx +24 -0
  298. package/stories/components/panels/systemSettings.stories.tsx +26 -0
  299. package/stories/components/panels/traces.stories.tsx +225 -0
  300. package/stories/components/panels/variables.stories.tsx +24 -0
  301. package/stories/defaults/defaultStoryProvider.tsx +170 -0
  302. package/stories/defaults/systemGenerator.ts +43 -0
  303. package/stories/plugins/notes.stories.tsx +100 -0
  304. package/tests/autoConvert.test.ts +329 -0
  305. package/tests/autosavePlugin.test.ts +204 -0
  306. package/tests/callSubgraphSync.test.ts +148 -0
  307. package/tests/commandRegistry.test.ts +137 -0
  308. package/tests/components/edges/offsetBezier.test.ts +51 -0
  309. package/tests/components/layoutController/utils.test.ts +68 -0
  310. package/tests/components/panels/traces/utils.test.ts +52 -0
  311. package/tests/contract.test.ts +51 -0
  312. package/tests/contractSerialize.test.ts +62 -0
  313. package/tests/deriveSpans.test.ts +71 -0
  314. package/tests/flowToBehave.test.ts +27 -4
  315. package/tests/hotkeys.test.ts +79 -0
  316. package/tests/keepAliveLifecycle.test.ts +167 -0
  317. package/tests/loadManifest.test.ts +113 -0
  318. package/tests/noteMarkdown.test.ts +65 -0
  319. package/tests/notesPlugin.test.ts +162 -0
  320. package/tests/notifications.test.ts +87 -0
  321. package/tests/persistence.test.ts +51 -0
  322. package/tests/saveLoad.test.ts +373 -0
  323. package/tests/settings.test.ts +178 -0
  324. package/tests/traceStore.test.ts +46 -0
  325. package/tests/util/calculateNewEdge.test.ts +98 -0
  326. package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
  327. package/tests/util/hasPositionMetaData.test.ts +33 -0
  328. package/tests/util/isBehaveNode.test.ts +22 -0
  329. package/tests/util/isHandleConnected.test.ts +37 -0
  330. package/tests/util/mergeSockets.test.ts +43 -0
  331. package/tests/visual/README.md +64 -0
  332. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
  333. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  334. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  335. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  336. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  337. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  338. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  339. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
  340. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  341. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  342. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  343. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  344. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  345. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  346. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
  347. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  348. package/tests/visual/panels.visual.test.tsx +76 -0
  349. package/tests/wasdPan.test.ts +71 -0
  350. package/tsconfig.base.json +39 -0
  351. package/tsconfig.json +18 -59
  352. package/tsconfig.prod.json +23 -0
  353. package/tsdown.config.ts +15 -3
  354. package/typedoc.json +7 -7
  355. package/vite.config.js +7 -0
  356. package/vitest.config.ts +5 -2
  357. package/vitest.visual.config.ts +55 -0
  358. package/src/components/AutoSizeInput.tsx +0 -65
  359. package/src/components/Controls.tsx +0 -87
  360. package/src/components/InputSocket.tsx +0 -142
  361. package/src/components/Node.tsx +0 -68
  362. package/src/components/NodeContainer.tsx +0 -46
  363. package/src/components/NodePicker.tsx +0 -77
  364. package/src/components/OutputSocket.tsx +0 -58
  365. package/src/components/modals/ClearModal.tsx +0 -40
  366. package/src/components/modals/HelpModal.tsx +0 -36
  367. package/src/components/modals/LoadModal.tsx +0 -96
  368. package/src/components/modals/Modal.tsx +0 -64
  369. package/src/components/modals/SaveModal.tsx +0 -60
  370. package/src/hooks/useCustomNodeTypes.tsx +0 -31
  371. package/src/hooks/useGraphRunner.ts +0 -104
  372. package/src/hooks/useMergeMap.ts +0 -14
  373. package/src/hooks/useNodeSpecJson.ts +0 -20
  374. package/src/hooks/useQueriableDefinitions.ts +0 -22
  375. package/src/styles.css +0 -8
  376. package/tailwind.config.ts +0 -19
  377. package/tests/tsconfig.json +0 -10
  378. /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
@@ -0,0 +1,283 @@
1
+ import { createStore, type StoreApi } from 'zustand';
2
+ import type { GraphSession } from '@/system/graphSession';
3
+ import type { GraphRunner } from './runner';
4
+ import { buildUIGraphJSON } from '../../transformers/Uigraph';
5
+ import { isBehaveNode } from '@/util/isBehaveNode';
6
+ import { supportsExecutionControl } from './transport';
7
+
8
+ // Contribute the per-session run controller to the graph session as a typed,
9
+ // plugin-owned property. Core no longer declares this field , the graph runner
10
+ // plugin attaches it via `session.decorate('runController', …)` from a session
11
+ // extension (see ./index.tsx).
12
+ declare module '@/system/graphSession' {
13
+ interface IGraphSession {
14
+ runController?: GraphRunController;
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Per-run state for a single graph. Each {@link GraphSession} owns one of these,
20
+ * so multiple graphs can run independently and concurrently.
21
+ */
22
+ export interface RunControllerStore {
23
+ currentRunId: string | null;
24
+ currentGraphId: string | null;
25
+ isExecuting: boolean;
26
+ isPaused: boolean;
27
+ setCurrentRunId: (runId: string | null) => void;
28
+ setCurrentGraphId: (graphId: string | null) => void;
29
+ setIsExecuting: (isExecuting: boolean) => void;
30
+ setIsPaused: (isPaused: boolean) => void;
31
+ }
32
+
33
+ const runControllerStoreFactory = (): StoreApi<RunControllerStore> =>
34
+ createStore<RunControllerStore>((set) => ({
35
+ currentRunId: null,
36
+ currentGraphId: null,
37
+ isExecuting: false,
38
+ isPaused: false,
39
+ setCurrentRunId: (currentRunId) => set({ currentRunId }),
40
+ setCurrentGraphId: (currentGraphId) => set({ currentGraphId }),
41
+ setIsExecuting: (isExecuting) => set({ isExecuting }),
42
+ setIsPaused: (isPaused) => set({ isPaused })
43
+ }));
44
+
45
+ /**
46
+ * Drives execution for a single graph session. Run lifecycle and run state are
47
+ * per-session; the underlying connection/client is shared via {@link GraphRunner}.
48
+ * Incoming server messages are routed back to the originating controller by run
49
+ * id (see `GraphRunner.runIndex`).
50
+ */
51
+ export class GraphRunController {
52
+ public readonly session: GraphSession;
53
+ public readonly runner: GraphRunner;
54
+ public readonly store: StoreApi<RunControllerStore> =
55
+ runControllerStoreFactory();
56
+ private readonly disposers: Array<() => void> = [];
57
+
58
+ constructor(session: GraphSession, runner: GraphRunner) {
59
+ this.session = session;
60
+ this.runner = runner;
61
+ this.setupRealtimeForwarding();
62
+ }
63
+
64
+ private get notifications() {
65
+ return this.session.editor.notifications;
66
+ }
67
+
68
+ /** Run the graph for this session. */
69
+ async play(): Promise<void> {
70
+ const { clearLogsOnRun, clearTracesOnRun } = this.runner.store.getState();
71
+
72
+ if (clearLogsOnRun) {
73
+ this.session.logsStore.getState().clear();
74
+ }
75
+ if (clearTracesOnRun) {
76
+ this.session.traceStore.getState().clear();
77
+ }
78
+
79
+ const graphId = this.session.id;
80
+ const uiGraphData = buildUIGraphJSON(this.session);
81
+ try {
82
+ await this.runRemotely(graphId, { graph: uiGraphData.flow });
83
+ } catch {
84
+ // Error already surfaced in runRemotely
85
+ }
86
+ }
87
+
88
+ async runRemotely(
89
+ graphId: string,
90
+ options?: { graph?: unknown; inputs?: unknown }
91
+ ): Promise<void> {
92
+ const client = this.runner.store.getState().client;
93
+ const { enableTracing } = this.runner.store.getState();
94
+ const { setCurrentRunId, setCurrentGraphId, setIsExecuting, setIsPaused } =
95
+ this.store.getState();
96
+
97
+ if (!client) {
98
+ this.notifications.error('No graph runner connection');
99
+ throw new Error('No graph runner connection');
100
+ }
101
+ if (this.store.getState().isExecuting) {
102
+ return;
103
+ }
104
+
105
+ try {
106
+ const runId = await client.runGraph(graphId, {
107
+ ...options,
108
+ trace: enableTracing
109
+ });
110
+
111
+ setCurrentRunId(runId);
112
+ setCurrentGraphId(graphId);
113
+ setIsExecuting(true);
114
+ setIsPaused(false);
115
+ this.runner.registerRun(runId, this);
116
+
117
+ this.notifications.info(`Graph execution started: ${graphId}`);
118
+ } catch (error) {
119
+ const message = error instanceof Error ? error.message : String(error);
120
+ setIsExecuting(false);
121
+ setIsPaused(false);
122
+ setCurrentRunId(null);
123
+ setCurrentGraphId(null);
124
+ this.notifications.error(`Failed to run graph: ${message}`);
125
+ throw error;
126
+ }
127
+ }
128
+
129
+ async stop(): Promise<void> {
130
+ const client = this.runner.store.getState().client;
131
+ const { currentRunId } = this.store.getState();
132
+ if (!client || !currentRunId) return;
133
+
134
+ try {
135
+ await client.stopGraph(currentRunId);
136
+ this.notifications.info('Stopping graph execution');
137
+ this.finishRun();
138
+ } catch (error) {
139
+ const message = error instanceof Error ? error.message : String(error);
140
+ this.notifications.error(`Failed to stop graph: ${message}`);
141
+ }
142
+ }
143
+
144
+ async pause(): Promise<void> {
145
+ const client = this.runner.store.getState().client;
146
+ const { currentRunId, setIsPaused } = this.store.getState();
147
+ if (!client || !currentRunId) return;
148
+
149
+ try {
150
+ const transport = client.transport;
151
+ if (supportsExecutionControl(transport)) {
152
+ transport.pauseExecution(currentRunId);
153
+ setIsPaused(true);
154
+ this.notifications.info('Execution paused');
155
+ } else {
156
+ await this.stop();
157
+ }
158
+ } catch (error) {
159
+ const message = error instanceof Error ? error.message : String(error);
160
+ this.notifications.error(`Failed to pause graph: ${message}`);
161
+ }
162
+ }
163
+
164
+ async resume(): Promise<void> {
165
+ const client = this.runner.store.getState().client;
166
+ const { currentRunId, setIsPaused } = this.store.getState();
167
+ if (!client || !currentRunId) return;
168
+
169
+ try {
170
+ const transport = client.transport;
171
+ if (supportsExecutionControl(transport)) {
172
+ setIsPaused(false);
173
+ this.notifications.info('Resuming execution');
174
+ await transport.resumeExecution(currentRunId);
175
+ }
176
+ } catch (error) {
177
+ const message = error instanceof Error ? error.message : String(error);
178
+ this.notifications.error(`Failed to resume graph: ${message}`);
179
+ }
180
+ }
181
+
182
+ async step(): Promise<void> {
183
+ const client = this.runner.store.getState().client;
184
+ const { currentRunId, setIsPaused } = this.store.getState();
185
+ if (!client || !currentRunId) return;
186
+
187
+ try {
188
+ const transport = client.transport;
189
+ if (supportsExecutionControl(transport)) {
190
+ setIsPaused(true);
191
+ await transport.stepExecution(currentRunId);
192
+ } else {
193
+ this.notifications.info(
194
+ 'Step execution not supported for this transport'
195
+ );
196
+ }
197
+ } catch (error) {
198
+ const message = error instanceof Error ? error.message : String(error);
199
+ this.notifications.error(`Failed to step graph: ${message}`);
200
+ }
201
+ }
202
+
203
+ /** Reset run state after completion/stop/error and unregister the run. */
204
+ finishRun(): void {
205
+ const runId = this.store.getState().currentRunId;
206
+ if (runId) this.runner.unregisterRun(runId);
207
+ const s = this.store.getState();
208
+ s.setIsExecuting(false);
209
+ s.setIsPaused(false);
210
+ s.setCurrentRunId(null);
211
+ s.setCurrentGraphId(null);
212
+ }
213
+
214
+ /**
215
+ * Forward live graph edits to the server while this graph is running, tagged
216
+ * with this controller's run id so concurrent graphs stay isolated.
217
+ */
218
+ private setupRealtimeForwarding(): void {
219
+ const pubsub = this.session.pubsub;
220
+ const canForward = () => {
221
+ const client = this.runner.store.getState().client;
222
+ const runId = this.store.getState().currentRunId;
223
+ const caps = this.runner.store.getState().connectionInfo.capabilities;
224
+ return client && runId && caps?.realtime ? { client, runId } : null;
225
+ };
226
+
227
+ const tokens = [
228
+ pubsub.subscribe('node:added', (_, node) => {
229
+ if (!isBehaveNode(node)) return;
230
+ const ctx = canForward();
231
+ if (!ctx) return;
232
+ ctx.client.addNode(
233
+ ctx.runId,
234
+ node.id,
235
+ node.data.type,
236
+ node.data as Record<string, unknown>,
237
+ node.position
238
+ );
239
+ }),
240
+ pubsub.subscribe('edge:added', (_, edge) => {
241
+ const ctx = canForward();
242
+ if (!ctx || !edge.source || !edge.target) return;
243
+ ctx.client.createLink(
244
+ ctx.runId,
245
+ edge.source,
246
+ edge.sourceHandle || '',
247
+ edge.target,
248
+ edge.targetHandle || ''
249
+ );
250
+ }),
251
+ pubsub.subscribe('edge:removed', (_, edge) => {
252
+ const ctx = canForward();
253
+ if (!ctx || !edge.source || !edge.target) return;
254
+ ctx.client.removeLink(
255
+ ctx.runId,
256
+ edge.source,
257
+ edge.sourceHandle || '',
258
+ edge.target,
259
+ edge.targetHandle || ''
260
+ );
261
+ }),
262
+ pubsub.subscribe('node:removed', (_, node) => {
263
+ if (!isBehaveNode(node)) return;
264
+ const ctx = canForward();
265
+ if (!ctx) return;
266
+ ctx.client.removeNode(ctx.runId, node.id);
267
+ })
268
+ ];
269
+
270
+ for (const token of tokens) {
271
+ if (typeof token === 'string') {
272
+ this.disposers.push(() => pubsub.unsubscribe(token));
273
+ }
274
+ }
275
+ }
276
+
277
+ dispose(): void {
278
+ const runId = this.store.getState().currentRunId;
279
+ if (runId) this.runner.unregisterRun(runId);
280
+ this.disposers.forEach((d) => d());
281
+ this.disposers.length = 0;
282
+ }
283
+ }
@@ -0,0 +1,187 @@
1
+ import type { System } from '../../system/system';
2
+ import type { StoreApi } from 'zustand';
3
+ import type { GraphRunnerClientStore } from './store';
4
+ import { GraphRunnerClient } from './client';
5
+ import { setupClientEventListeners } from './actions';
6
+ import type { GraphRunController } from './runController';
7
+
8
+ declare module '@/system/system' {
9
+ interface System {
10
+ runner: GraphRunner;
11
+ }
12
+ }
13
+
14
+ /**
15
+ * Shared connection to the graph runner server. Owns the client, connection
16
+ * lifecycle and server metadata; per-graph run state and run lifecycle live on
17
+ * {@link GraphRunController}. Incoming server messages are dispatched back to the
18
+ * owning controller via {@link GraphRunner.runIndex}, keyed by run id, so
19
+ * multiple graphs can run concurrently and independently.
20
+ */
21
+ export class GraphRunner {
22
+ private system: System;
23
+ public readonly store: StoreApi<GraphRunnerClientStore>;
24
+ /** runId -> the controller that started it. */
25
+ public readonly runIndex = new Map<string, GraphRunController>();
26
+
27
+ constructor(system: System, store: StoreApi<GraphRunnerClientStore>) {
28
+ this.system = system;
29
+ this.store = store;
30
+ }
31
+
32
+ registerRun(runId: string, controller: GraphRunController): void {
33
+ this.runIndex.set(runId, controller);
34
+ }
35
+
36
+ unregisterRun(runId: string): void {
37
+ this.runIndex.delete(runId);
38
+ }
39
+
40
+ /**
41
+ * Connect to the graph runner server
42
+ */
43
+ async connect(): Promise<void> {
44
+ const {
45
+ client,
46
+ connectionConfig,
47
+ setClient,
48
+ setConnectionState,
49
+ setConnectionInfo,
50
+ setError,
51
+ clearServerMetadata,
52
+ addMessageActivity
53
+ } = this.store.getState();
54
+
55
+ try {
56
+ setError(null);
57
+ setConnectionState('connecting');
58
+
59
+ const theClient =
60
+ client ??
61
+ new GraphRunnerClient({
62
+ url: connectionConfig.url,
63
+ auth: connectionConfig.auth,
64
+ autoReconnect: connectionConfig.autoReconnect,
65
+ onMessageActivity: (direction, message) => {
66
+ addMessageActivity(direction, message);
67
+ }
68
+ });
69
+
70
+ setClient(theClient);
71
+
72
+ await theClient.connect();
73
+
74
+ // Setup persistent event listeners for trace, logs, and run completion.
75
+ // Messages are routed to the originating session by run id.
76
+ setupClientEventListeners(theClient, this);
77
+
78
+ setConnectionState('connected');
79
+ setConnectionInfo({
80
+ serverId: theClient.getServerId(),
81
+ userId: theClient.getUserId(),
82
+ sessionId: null,
83
+ authenticated: theClient.isAuthenticated(),
84
+ capabilities: null
85
+ });
86
+
87
+ // Create session
88
+ const sessionId = await theClient.createSession();
89
+ setConnectionInfo({ sessionId });
90
+
91
+ // Get capabilities
92
+ const capabilities = await theClient.getCapabilities();
93
+ setConnectionInfo({ capabilities });
94
+
95
+ // Fetch metadata if supported
96
+ if (capabilities.runtimeMetadata) {
97
+ await this.refreshMetadata();
98
+ }
99
+
100
+ // Notify successful connection
101
+ this.system.notifications.success(
102
+ `Connected to ${theClient.getServerId() || 'graph runner server'}`
103
+ );
104
+ } catch (error) {
105
+ setConnectionState('disconnected');
106
+ const errorMessage =
107
+ error instanceof Error ? error.message : String(error);
108
+ setError(errorMessage);
109
+ setClient(null);
110
+ clearServerMetadata();
111
+
112
+ // Notify connection error
113
+ this.system.notifications.error(`Failed to connect: ${errorMessage}`);
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Disconnect from the graph runner server
119
+ */
120
+ async disconnect(): Promise<void> {
121
+ const {
122
+ client,
123
+ setClient,
124
+ setConnectionState,
125
+ setConnectionInfo,
126
+ clearServerMetadata
127
+ } = this.store.getState();
128
+
129
+ console.log('Disconnecting from graph runner server...');
130
+ if (client) {
131
+ try {
132
+ await client.closeSession();
133
+ client.disconnect();
134
+ } catch (error) {
135
+ console.error('Error disconnecting:', error);
136
+ }
137
+ }
138
+
139
+ setClient(null);
140
+ setConnectionState('disconnected');
141
+ setConnectionInfo({
142
+ serverId: null,
143
+ userId: null,
144
+ sessionId: null,
145
+ authenticated: false,
146
+ capabilities: null
147
+ });
148
+ clearServerMetadata();
149
+ }
150
+
151
+ /**
152
+ * Refresh server metadata (variables, events, node types)
153
+ */
154
+ async refreshMetadata(): Promise<void> {
155
+ const {
156
+ client,
157
+ setServerVariables,
158
+ setServerEvents,
159
+ setNodeTypes,
160
+ setError
161
+ } = this.store.getState();
162
+ if (!client) {
163
+ return;
164
+ }
165
+
166
+ try {
167
+ const capabilities = client.getCachedCapabilities();
168
+ if (!capabilities?.runtimeMetadata) {
169
+ return;
170
+ }
171
+
172
+ const [variables, events, nodeTypes] = await Promise.all([
173
+ client.getServerVariables(),
174
+ client.getServerEvents(),
175
+ client.getNodeTypes()
176
+ ]);
177
+
178
+ setServerVariables(variables);
179
+ setServerEvents(events);
180
+ setNodeTypes(nodeTypes);
181
+
182
+ setError(null);
183
+ } catch (error) {
184
+ setError(error instanceof Error ? error.message : String(error));
185
+ }
186
+ }
187
+ }
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Session management for local graph runner
3
+ * Allows customization of execution context and configuration per session
4
+ */
5
+
6
+ import type { IRegistry } from '@kiberon-labs/behave-graph';
7
+ import type {
8
+ GraphRunnerCapabilities,
9
+ EventFilter
10
+ } from '../graphrunner/types.js';
11
+
12
+ /**
13
+ * Session configuration for graph execution
14
+ */
15
+ export interface SessionConfig {
16
+ /** Custom metadata attached to the session */
17
+ metadata?: Record<string, unknown>;
18
+ /** Default execution options for all runs in this session */
19
+ defaultExecutionOptions?: {
20
+ autoEnd?: boolean;
21
+ trace?: boolean;
22
+ eventFilter?: EventFilter;
23
+ maxExecutionTimeMs?: number;
24
+ };
25
+ /** Session-level execution settings */
26
+ executionSettings?: {
27
+ /** Delay between execution steps in milliseconds */
28
+ stepDelay?: number;
29
+ /** Execution speed multiplier (0.1 to 2.0) */
30
+ executionSpeed?: number;
31
+ /** Interval between tick events in milliseconds */
32
+ tickInterval?: number;
33
+ /** Maximum number of concurrent runs allowed */
34
+ maxConcurrentRuns?: number;
35
+ };
36
+ /** Custom hook for handling tick timing/delays */
37
+ tickStrategy?: () => Promise<void>;
38
+ /** Custom registry overrides for this session */
39
+ registryOverrides?: Partial<IRegistry>;
40
+ /** Session lifecycle hooks */
41
+ hooks?: SessionHooks;
42
+ /** Session-specific capabilities override */
43
+ capabilities?: Partial<GraphRunnerCapabilities>;
44
+ }
45
+
46
+ /**
47
+ * Lifecycle hooks for session events
48
+ */
49
+ export interface SessionHooks {
50
+ /** Called when the session is created */
51
+ onSessionCreated?: (session: Session) => void | Promise<void>;
52
+ /** Called when a run starts in this session */
53
+ onRunStarted?: (
54
+ session: Session,
55
+ runId: string,
56
+ graphId: string
57
+ ) => void | Promise<void>;
58
+ /** Called when a run completes in this session */
59
+ onRunCompleted?: (
60
+ session: Session,
61
+ runId: string,
62
+ graphId: string,
63
+ result: unknown
64
+ ) => void | Promise<void>;
65
+ /** Called when a run fails in this session */
66
+ onRunError?: (
67
+ session: Session,
68
+ runId: string,
69
+ graphId: string,
70
+ error: Error
71
+ ) => void | Promise<void>;
72
+ /** Called when the session is closed */
73
+ onSessionClosed?: (session: Session) => void | Promise<void>;
74
+ }
75
+
76
+ /**
77
+ * Session state
78
+ */
79
+ export interface Session {
80
+ /** Unique session identifier */
81
+ readonly sessionId: string;
82
+ /** Session expiration timestamp */
83
+ readonly expiresAt: number;
84
+ /** Session creation timestamp */
85
+ readonly createdAt: number;
86
+ /** Session configuration */
87
+ readonly config: SessionConfig;
88
+ /** Active run IDs in this session */
89
+ readonly activeRuns: Set<string>;
90
+ /** Custom session state (user-definable) */
91
+ state: Record<string, unknown>;
92
+ /** Session metadata */
93
+ metadata: Record<string, unknown>;
94
+ }
95
+
96
+ /**
97
+ * Factory for creating sessions with custom configuration
98
+ */
99
+ export interface SessionFactory {
100
+ /**
101
+ * Create a new session with optional configuration
102
+ */
103
+ createSession(sessionId: string, config?: SessionConfig): Session;
104
+ }
105
+
106
+ /**
107
+ * Default session factory implementation
108
+ */
109
+ export class DefaultSessionFactory implements SessionFactory {
110
+ private defaultConfig?: SessionConfig;
111
+
112
+ constructor(defaultConfig?: SessionConfig) {
113
+ this.defaultConfig = defaultConfig;
114
+ }
115
+
116
+ createSession(sessionId: string, config?: SessionConfig): Session {
117
+ const mergedConfig: SessionConfig = {
118
+ ...this.defaultConfig,
119
+ ...config,
120
+ metadata: {
121
+ ...this.defaultConfig?.metadata,
122
+ ...config?.metadata
123
+ },
124
+ defaultExecutionOptions: {
125
+ ...this.defaultConfig?.defaultExecutionOptions,
126
+ ...config?.defaultExecutionOptions
127
+ },
128
+ executionSettings: {
129
+ ...this.defaultConfig?.executionSettings,
130
+ ...config?.executionSettings
131
+ },
132
+ hooks: {
133
+ ...this.defaultConfig?.hooks,
134
+ ...config?.hooks
135
+ }
136
+ };
137
+
138
+ const session: Session = {
139
+ sessionId,
140
+ expiresAt: Date.now() + 24 * 60 * 60 * 1000, // 24 hours default
141
+ createdAt: Date.now(),
142
+ config: mergedConfig,
143
+ activeRuns: new Set(),
144
+ state: {},
145
+ metadata: mergedConfig.metadata ?? {}
146
+ };
147
+
148
+ // Call creation hook
149
+ if (mergedConfig.hooks?.onSessionCreated) {
150
+ void mergedConfig.hooks.onSessionCreated(session);
151
+ }
152
+
153
+ return session;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Session manager to track and manage multiple sessions
159
+ */
160
+ export class SessionManager {
161
+ private sessions = new Map<string, Session>();
162
+ private sessionFactory: SessionFactory;
163
+
164
+ constructor(sessionFactory?: SessionFactory) {
165
+ this.sessionFactory = sessionFactory ?? new DefaultSessionFactory();
166
+ }
167
+
168
+ /**
169
+ * Create a new session
170
+ */
171
+ createSession(sessionId: string, config?: SessionConfig): Session {
172
+ const session = this.sessionFactory.createSession(sessionId, config);
173
+ this.sessions.set(sessionId, session);
174
+ return session;
175
+ }
176
+
177
+ /**
178
+ * Get an existing session
179
+ */
180
+ getSession(sessionId: string): Session | undefined {
181
+ return this.sessions.get(sessionId);
182
+ }
183
+
184
+ /**
185
+ * Check if a session exists
186
+ */
187
+ hasSession(sessionId: string): boolean {
188
+ return this.sessions.has(sessionId);
189
+ }
190
+
191
+ /**
192
+ * Close and remove a session
193
+ */
194
+ async closeSession(sessionId: string): Promise<void> {
195
+ const session = this.sessions.get(sessionId);
196
+ if (session) {
197
+ // Call close hook
198
+ if (session.config.hooks?.onSessionClosed) {
199
+ await session.config.hooks.onSessionClosed(session);
200
+ }
201
+ this.sessions.delete(sessionId);
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Add a run to a session
207
+ */
208
+ addRunToSession(sessionId: string, runId: string): void {
209
+ const session = this.sessions.get(sessionId);
210
+ if (session) {
211
+ session.activeRuns.add(runId);
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Remove a run from a session
217
+ */
218
+ removeRunFromSession(sessionId: string, runId: string): void {
219
+ const session = this.sessions.get(sessionId);
220
+ if (session) {
221
+ session.activeRuns.delete(runId);
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Get all active sessions
227
+ */
228
+ getActiveSessions(): Session[] {
229
+ return Array.from(this.sessions.values());
230
+ }
231
+
232
+ /**
233
+ * Clean up expired sessions
234
+ */
235
+ cleanupExpiredSessions(): void {
236
+ const now = Date.now();
237
+ for (const [sessionId, session] of this.sessions.entries()) {
238
+ if (session.expiresAt < now) {
239
+ void this.closeSession(sessionId);
240
+ }
241
+ }
242
+ }
243
+ }