@kiberon-labs/behave-graph-flow 1.0.0 → 2.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 (314) hide show
  1. package/.fallowrc.json +16 -0
  2. package/.storybook/main.ts +32 -0
  3. package/.storybook/preview.ts +16 -0
  4. package/.storybook/styles.css +10 -0
  5. package/.storybook/vscode.css +814 -0
  6. package/.turbo/turbo-build.log +7 -0
  7. package/LICENSE +6 -0
  8. package/README.md +2 -2
  9. package/data/Polynomial.json +510 -0
  10. package/data/sequence.json +337 -0
  11. package/data/trigger-event.json +241 -0
  12. package/data/variable-change.json +210 -0
  13. package/dist/entry.css +4 -0
  14. package/dist/index.css +39 -0
  15. package/dist/index.css.map +1 -0
  16. package/dist/index.d.ts +2282 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +14873 -0
  19. package/dist/index.js.map +1 -0
  20. package/docs/notifications.md +246 -0
  21. package/docs/protocol.md +679 -0
  22. package/docs/specifics.md +191 -0
  23. package/package.json +85 -21
  24. package/postcss.config.ts +3 -4
  25. package/src/annotations/index.ts +32 -0
  26. package/src/components/FloatingToolbar/index.module.css +45 -0
  27. package/src/components/FloatingToolbar/index.tsx +256 -0
  28. package/src/components/Flow.tsx +276 -75
  29. package/src/components/contextMenus/NodePicker.module.css +274 -0
  30. package/src/components/contextMenus/NodePicker.tsx +481 -0
  31. package/src/components/contextMenus/edge.tsx +108 -0
  32. package/src/components/contextMenus/node.tsx +155 -0
  33. package/src/components/contextMenus/selection.tsx +77 -0
  34. package/src/components/controls/any/index.tsx +8 -0
  35. package/src/components/controls/boolean/index.tsx +13 -0
  36. package/src/components/controls/colorPicker/InputPopover.module.css +100 -0
  37. package/src/components/controls/colorPicker/InputPopover.tsx +31 -0
  38. package/src/components/controls/colorPicker/index.module.css +18 -0
  39. package/src/components/controls/colorPicker/index.tsx +61 -0
  40. package/src/components/controls/number/index.tsx +35 -0
  41. package/src/components/controls/string/index.tsx +16 -0
  42. package/src/components/edges/index.tsx +469 -0
  43. package/src/components/edges/offsetBezier.ts +134 -0
  44. package/src/components/hotKeys.tsx +20 -0
  45. package/src/components/layoutController/index.module.css +10 -0
  46. package/src/components/layoutController/index.tsx +117 -0
  47. package/src/components/layoutController/utils.ts +205 -0
  48. package/src/components/menubar/defaults.tsx +480 -0
  49. package/src/components/menubar/index.tsx +49 -0
  50. package/src/components/menubar/menuItem.module.css +16 -0
  51. package/src/components/menubar/menuItem.tsx +32 -0
  52. package/src/components/nodes/behave/Node.module.css +23 -0
  53. package/src/components/nodes/behave/Node.tsx +176 -0
  54. package/src/components/nodes/behave/NodeContainer.module.css +87 -0
  55. package/src/components/nodes/behave/NodeContainer.tsx +46 -0
  56. package/src/components/nodes/behave/index.tsx +14 -0
  57. package/src/components/nodes/comment/FormatToolbar.tsx +118 -0
  58. package/src/components/nodes/comment/comment.tsx +103 -0
  59. package/src/components/nodes/comment/styles.module.css +150 -0
  60. package/src/components/nodes/group/index.tsx +109 -0
  61. package/src/components/nodes/wrapper/index.tsx +73 -0
  62. package/src/components/nodes/wrapper/styles.module.css +113 -0
  63. package/src/components/notifications/NotificationProvider.tsx +81 -0
  64. package/src/components/notifications/index.ts +2 -0
  65. package/src/components/notifications/utils.ts +71 -0
  66. package/src/components/panels/alignment/index.module.css +20 -0
  67. package/src/components/panels/alignment/index.tsx +244 -0
  68. package/src/components/panels/base/index.tsx +5 -0
  69. package/src/components/panels/base/styles.module.css +12 -0
  70. package/src/components/panels/conversation/index.module.css +151 -0
  71. package/src/components/panels/conversation/index.tsx +162 -0
  72. package/src/components/panels/events/CustomEventsEditor.tsx +384 -0
  73. package/src/components/panels/events/EditEventPanel.tsx +315 -0
  74. package/src/components/panels/events/ManageEventsPanel.tsx +98 -0
  75. package/src/components/panels/events/index.tsx +23 -0
  76. package/src/components/panels/events/styles.module.css +236 -0
  77. package/src/components/panels/history/index.tsx +92 -0
  78. package/src/components/panels/history/styles.module.css +106 -0
  79. package/src/components/panels/keymaps/index.module.css +78 -0
  80. package/src/components/panels/keymaps/index.tsx +167 -0
  81. package/src/components/panels/layers/index.tsx +240 -0
  82. package/src/components/panels/layers/styles.module.css +110 -0
  83. package/src/components/panels/legend/index.module.css +6 -0
  84. package/src/components/panels/legend/index.tsx +76 -0
  85. package/src/components/panels/logs/index.module.css +212 -0
  86. package/src/components/panels/logs/index.tsx +288 -0
  87. package/src/components/panels/nodeInputs/InputControl.tsx +63 -0
  88. package/src/components/panels/nodeInputs/InputsGroup.tsx +64 -0
  89. package/src/components/panels/nodeInputs/MultipleNodesView.tsx +37 -0
  90. package/src/components/panels/nodeInputs/NodeSettings.tsx +92 -0
  91. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +125 -0
  92. package/src/components/panels/nodeInputs/OutputsGroup.tsx +65 -0
  93. package/src/components/panels/nodeInputs/SocketGenerators.tsx +32 -0
  94. package/src/components/panels/nodeInputs/index.module.css +284 -0
  95. package/src/components/panels/nodeInputs/index.tsx +339 -0
  96. package/src/components/panels/nodeInputs/useNodeHandlers.ts +76 -0
  97. package/src/components/panels/nodeInputs/useNodeInputsData.ts +173 -0
  98. package/src/components/panels/nodePicker/index.tsx +115 -0
  99. package/src/components/panels/panel/index.module.css +66 -0
  100. package/src/components/panels/panel/index.tsx +88 -0
  101. package/src/components/panels/search/index.module.css +66 -0
  102. package/src/components/panels/search/index.tsx +215 -0
  103. package/src/components/panels/systemSettings/index.tsx +206 -0
  104. package/src/components/panels/systemSettings/styles.module.css +11 -0
  105. package/src/components/panels/traces/GridLines.tsx +38 -0
  106. package/src/components/panels/traces/TimeGrid.tsx +48 -0
  107. package/src/components/panels/traces/TraceLane.tsx +62 -0
  108. package/src/components/panels/traces/TraceTooltip.tsx +22 -0
  109. package/src/components/panels/traces/TracesHeader.tsx +56 -0
  110. package/src/components/panels/traces/index.module.css +166 -0
  111. package/src/components/panels/traces/index.tsx +294 -0
  112. package/src/components/panels/traces/types.ts +48 -0
  113. package/src/components/panels/traces/useDerivedSpans.ts +212 -0
  114. package/src/components/panels/traces/utils.ts +25 -0
  115. package/src/components/panels/variables/CreateVariableScreen.tsx +162 -0
  116. package/src/components/panels/variables/ManageVariablesScreen.tsx +144 -0
  117. package/src/components/panels/variables/index.tsx +125 -0
  118. package/src/components/panels/variables/styles.module.css +236 -0
  119. package/src/components/primitives/icon.module.css +45 -0
  120. package/src/components/primitives/icon.tsx +38 -0
  121. package/src/components/sockets/input/index.tsx +76 -0
  122. package/src/components/sockets/input/styles.module.css +27 -0
  123. package/src/components/sockets/output/index.tsx +61 -0
  124. package/src/components/sockets/output/styles.module.css +27 -0
  125. package/src/css/prosemirror.css +57 -0
  126. package/src/css/rc-dock.css +112 -0
  127. package/src/css/rc-menu.css +100 -0
  128. package/src/css/vars.css +14 -0
  129. package/src/css/vscode.css +13 -0
  130. package/src/entry.css +4 -0
  131. package/src/generators/CustomEventOnTriggeredGenerator.tsx +85 -0
  132. package/src/generators/SequenceGenerator.tsx +104 -0
  133. package/src/generators/SwitchOnIntegerGenerator.tsx +256 -0
  134. package/src/generators/SwitchOnStringGenerator.tsx +263 -0
  135. package/src/generators/registerDefaultGenerators.ts +34 -0
  136. package/src/hooks/useBehaveGraphFlow.ts +17 -16
  137. package/src/hooks/useDetachNodes.ts +39 -0
  138. package/src/hooks/useFlowHandlers.ts +115 -29
  139. package/src/hooks/useWasdPan.ts +188 -0
  140. package/src/index.css +146 -0
  141. package/src/index.ts +36 -18
  142. package/src/layout/dagre.tsx +119 -0
  143. package/src/layout/elk.ts +200 -0
  144. package/src/plugin/alignment/index.ts +81 -0
  145. package/src/plugin/docs/index.tsx +299 -0
  146. package/src/plugin/docs/panel/index.tsx +200 -0
  147. package/src/plugin/docs/panel/styles.module.css +174 -0
  148. package/src/plugin/graphrunner/actions.ts +253 -0
  149. package/src/plugin/graphrunner/buttons.tsx +87 -0
  150. package/src/plugin/graphrunner/client.ts +704 -0
  151. package/src/plugin/graphrunner/index.tsx +255 -0
  152. package/src/plugin/graphrunner/panel.tsx +386 -0
  153. package/src/plugin/graphrunner/runner.ts +358 -0
  154. package/src/plugin/graphrunner/session.ts +243 -0
  155. package/src/plugin/graphrunner/store.ts +206 -0
  156. package/src/plugin/graphrunner/styles.module.css +211 -0
  157. package/src/plugin/graphrunner/transport.ts +224 -0
  158. package/src/plugin/graphrunner/types.ts +672 -0
  159. package/src/plugin/graphrunner-local/execution-utils.ts +457 -0
  160. package/src/plugin/graphrunner-local/index.tsx +166 -0
  161. package/src/plugin/graphrunner-local/panel.tsx +231 -0
  162. package/src/plugin/graphrunner-local/store.ts +41 -0
  163. package/src/plugin/graphrunner-local/styles.module.css +101 -0
  164. package/src/plugin/graphrunner-local/transport.ts +1372 -0
  165. package/src/plugin/graphrunner-local/types.ts +10 -0
  166. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +633 -0
  167. package/src/plugin/graphrunner-webworker/index.tsx +146 -0
  168. package/src/plugin/graphrunner-webworker/panel.tsx +173 -0
  169. package/src/plugin/graphrunner-webworker/store.ts +89 -0
  170. package/src/plugin/graphrunner-webworker/types.ts +17 -0
  171. package/src/plugin/graphrunner-webworker/worker-transport.ts +123 -0
  172. package/src/plugin/realtime/realtimeRunner.ts +570 -0
  173. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +92 -0
  174. package/src/specifics/CustomEventTriggerSpecific.tsx +141 -0
  175. package/src/specifics/VariableGetSpecific.tsx +110 -0
  176. package/src/specifics/VariableSetSpecific.tsx +110 -0
  177. package/src/specifics/registerDefaultSpecifics.ts +5 -0
  178. package/src/store/actions.tsx +698 -0
  179. package/src/store/chat.ts +73 -0
  180. package/src/store/controls.tsx +62 -0
  181. package/src/store/documentation.tsx +69 -0
  182. package/src/store/events.tsx +116 -0
  183. package/src/store/flow.tsx +245 -0
  184. package/src/store/graphRunnerClient.ts +110 -0
  185. package/src/store/hotKeys.tsx +323 -0
  186. package/src/store/layers.ts +259 -0
  187. package/src/store/legend.tsx +76 -0
  188. package/src/store/logs.ts +28 -0
  189. package/src/store/menubar.ts +41 -0
  190. package/src/store/refs.ts +84 -0
  191. package/src/store/registry.ts +43 -0
  192. package/src/store/selection.ts +22 -0
  193. package/src/store/settings.ts +99 -0
  194. package/src/store/socketGenerator.tsx +54 -0
  195. package/src/store/specific.tsx +75 -0
  196. package/src/store/specs.tsx +35 -0
  197. package/src/store/tabs.ts +278 -0
  198. package/src/store/toolbar.tsx +45 -0
  199. package/src/store/traces.ts +240 -0
  200. package/src/store/variables.ts +37 -0
  201. package/src/system/graph.ts +134 -0
  202. package/src/system/index.ts +3 -0
  203. package/src/system/notifications.ts +98 -0
  204. package/src/system/plugin.ts +27 -0
  205. package/src/system/provider.tsx +22 -0
  206. package/src/system/pubsub.ts +323 -0
  207. package/src/system/system.ts +223 -0
  208. package/src/system/tabLoader.tsx +265 -0
  209. package/src/system/undoRedo.ts +103 -0
  210. package/src/transformers/Uigraph.ts +60 -0
  211. package/src/transformers/behaveToFlow.ts +16 -4
  212. package/src/transformers/flowToBehave.ts +32 -12
  213. package/src/types/NodeMetadata.ts +27 -0
  214. package/src/types/graph.ts +49 -0
  215. package/src/types/nodes.ts +45 -0
  216. package/src/types.ts +16 -0
  217. package/src/util/colors.ts +1 -29
  218. package/src/util/downloadJson.ts +18 -0
  219. package/src/util/extractNodeMetadata.ts +16 -0
  220. package/src/util/getPickerFilters.ts +1 -1
  221. package/src/util/isBehaveNode.ts +6 -0
  222. package/src/util/isValidConnection.ts +28 -15
  223. package/src/util/mergeSockets.ts +29 -0
  224. package/src/util/serializeVariables.ts +66 -0
  225. package/src/util/sockets.ts +43 -0
  226. package/stories/apex/layoutController/example-graph.worker.ts +39 -0
  227. package/stories/apex/layoutController/index.stories.tsx +48 -0
  228. package/stories/apex/layoutController/webworker.stories.tsx +103 -0
  229. package/stories/apex/menubar/menubar.stories.tsx +19 -0
  230. package/stories/components/colorpicker/index.stories.tsx +20 -0
  231. package/stories/components/contextMenus/edge.stories.tsx +32 -0
  232. package/stories/components/contextMenus/node.stories.tsx +26 -0
  233. package/stories/components/contextMenus/nodePicker.stories.tsx +115 -0
  234. package/stories/components/controls/any/index.stories.tsx +19 -0
  235. package/stories/components/controls/boolean/index.stories.tsx +19 -0
  236. package/stories/components/controls/colorPicker/index.stories.tsx +49 -0
  237. package/stories/components/controls/number/index.stories.tsx +19 -0
  238. package/stories/components/controls/string/index.stories.tsx +19 -0
  239. package/stories/components/nodes/behaveNode.stories.tsx +108 -0
  240. package/stories/components/nodes/comment.stories.tsx +106 -0
  241. package/stories/components/panels/alignment.stories.tsx +24 -0
  242. package/stories/components/panels/events.stories.tsx +38 -0
  243. package/stories/components/panels/graphRunner.stories.tsx +317 -0
  244. package/stories/components/panels/history.stories.tsx +37 -0
  245. package/stories/components/panels/keymaps.stories.tsx +21 -0
  246. package/stories/components/panels/legend.stories.tsx +37 -0
  247. package/stories/components/panels/logs.stories.tsx +24 -0
  248. package/stories/components/panels/nodeInputs.stories.tsx +21 -0
  249. package/stories/components/panels/nodePicker.stories.tsx +37 -0
  250. package/stories/components/panels/panel.stories.tsx +39 -0
  251. package/stories/components/panels/search.stories.tsx +24 -0
  252. package/stories/components/panels/systemSettings.stories.tsx +26 -0
  253. package/stories/components/panels/traces.stories.tsx +225 -0
  254. package/stories/components/panels/variables.stories.tsx +24 -0
  255. package/stories/defaults/defaultStoryProvider.tsx +167 -0
  256. package/stories/defaults/systemGenerator.ts +38 -0
  257. package/tests/components/edges/offsetBezier.test.ts +51 -0
  258. package/tests/components/layoutController/utils.test.ts +68 -0
  259. package/tests/components/panels/traces/utils.test.ts +52 -0
  260. package/tests/flowToBehave.test.ts +26 -4
  261. package/tests/notifications.test.ts +87 -0
  262. package/tests/saveLoad.test.ts +372 -0
  263. package/tests/util/calculateNewEdge.test.ts +98 -0
  264. package/tests/util/getSocketsByNodeTypeAndHandleType.test.ts +31 -0
  265. package/tests/util/hasPositionMetaData.test.ts +33 -0
  266. package/tests/util/isBehaveNode.test.ts +22 -0
  267. package/tests/util/isHandleConnected.test.ts +37 -0
  268. package/tests/util/mergeSockets.test.ts +43 -0
  269. package/tests/visual/README.md +64 -0
  270. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-alignment-chromium-win32.png +0 -0
  271. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  272. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  273. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  274. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  275. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  276. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  277. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  278. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  279. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  280. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  281. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  282. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  283. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-traces-chromium-win32.png +0 -0
  284. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  285. package/tests/visual/panels.visual.test.tsx +76 -0
  286. package/tsconfig.base.json +39 -0
  287. package/tsconfig.json +18 -59
  288. package/tsconfig.prod.json +23 -0
  289. package/tsdown.config.ts +15 -3
  290. package/typedoc.json +7 -7
  291. package/vite.config.js +7 -0
  292. package/vitest.config.ts +5 -2
  293. package/vitest.visual.config.ts +48 -0
  294. package/src/components/AutoSizeInput.tsx +0 -65
  295. package/src/components/Controls.tsx +0 -87
  296. package/src/components/InputSocket.tsx +0 -142
  297. package/src/components/Node.tsx +0 -68
  298. package/src/components/NodeContainer.tsx +0 -46
  299. package/src/components/NodePicker.tsx +0 -77
  300. package/src/components/OutputSocket.tsx +0 -58
  301. package/src/components/modals/ClearModal.tsx +0 -40
  302. package/src/components/modals/HelpModal.tsx +0 -36
  303. package/src/components/modals/LoadModal.tsx +0 -96
  304. package/src/components/modals/Modal.tsx +0 -64
  305. package/src/components/modals/SaveModal.tsx +0 -60
  306. package/src/hooks/useCustomNodeTypes.tsx +0 -31
  307. package/src/hooks/useGraphRunner.ts +0 -104
  308. package/src/hooks/useMergeMap.ts +0 -14
  309. package/src/hooks/useNodeSpecJson.ts +0 -20
  310. package/src/hooks/useQueriableDefinitions.ts +0 -22
  311. package/src/styles.css +0 -8
  312. package/tailwind.config.ts +0 -19
  313. package/tests/tsconfig.json +0 -10
  314. /package/src/{types.d.ts → types-declarations.d.ts} +0 -0
@@ -0,0 +1,10 @@
1
+ import type { localGraphRunnerStoreFactory } from './store';
2
+
3
+ /**
4
+ * Extend the System interface to include the local graph runner store
5
+ */
6
+ declare module '@/system/system' {
7
+ interface System {
8
+ localGraphRunnerStore: ReturnType<typeof localGraphRunnerStoreFactory>;
9
+ }
10
+ }
@@ -0,0 +1,633 @@
1
+ import { Engine, type IRegistry } from '@kiberon-labs/behave-graph';
2
+ import type {
3
+ GraphRunnerMessage,
4
+ ServerGraphRunnerMessage,
5
+ ServerVariable,
6
+ ServerEvent
7
+ } from '../graphrunner/types.js';
8
+ import type { SessionFactory, Session } from '../graphrunner/session.js';
9
+ import {
10
+ type ActiveRun,
11
+ type MessageContext,
12
+ generateId,
13
+ handleHello,
14
+ handleCreateSession,
15
+ handleGetCapabilities,
16
+ createForwardingLogger,
17
+ prepareRegistryWithDependencies,
18
+ parseAndValidateGraph,
19
+ setupTracing,
20
+ setupVariableChangeTracking,
21
+ executeGraphLifecycle,
22
+ handleGetServerVariables,
23
+ handleGetServerEvents,
24
+ handleGetSocketConstraints,
25
+ handleGetNodeTypes
26
+ } from '../graphrunner-local/execution-utils.js';
27
+
28
+ /**
29
+ * Session context provided to lifecycle hooks
30
+ */
31
+ export interface SessionContext {
32
+ sessionId: string;
33
+ metadata?: Record<string, unknown>;
34
+ createdAt: number;
35
+ }
36
+
37
+ /**
38
+ * Run context provided to lifecycle hooks
39
+ */
40
+ export interface RunContext {
41
+ runId: string;
42
+ graphId: string;
43
+ sessionId: string;
44
+ inputs?: unknown;
45
+ options?: { trace?: boolean };
46
+ }
47
+
48
+ /**
49
+ * Lifecycle hooks for customizing graph worker behavior
50
+ */
51
+ export interface GraphWorkerHooks {
52
+ /**
53
+ * Called when a new session is created
54
+ * Can return metadata to associate with the session
55
+ */
56
+ onSessionCreated?: (
57
+ sessionId: string,
58
+ metadata?: Record<string, unknown>
59
+ ) =>
60
+ | void
61
+ | Promise<void>
62
+ | Record<string, unknown>
63
+ | Promise<Record<string, unknown>>;
64
+
65
+ /**
66
+ * Called when a session is closed
67
+ */
68
+ onSessionClosed?: (context: SessionContext) => void | Promise<void>;
69
+
70
+ /**
71
+ * Called before a graph run starts
72
+ * Can return false to prevent the run
73
+ */
74
+ onRunStart?: (
75
+ context: RunContext
76
+ ) => boolean | Promise<boolean> | void | Promise<void>;
77
+
78
+ /**
79
+ * Called when a graph run completes successfully
80
+ */
81
+ onRunComplete?: (context: RunContext, run: ActiveRun) => void | Promise<void>;
82
+
83
+ /**
84
+ * Called when a graph run encounters an error
85
+ */
86
+ onRunError?: (context: RunContext, error: Error) => void | Promise<void>;
87
+
88
+ /**
89
+ * Called when a graph run is stopped
90
+ */
91
+ onRunStopped?: (context: RunContext, reason: string) => void | Promise<void>;
92
+
93
+ /**
94
+ * Called on any incoming message, before processing
95
+ * Can return false to prevent default handling
96
+ */
97
+ onMessage?: (message: GraphRunnerMessage) => boolean | void;
98
+ }
99
+
100
+ /**
101
+ * Options for initializing the graph worker
102
+ */
103
+ export interface GraphWorkerOptions {
104
+ /**
105
+ * The registry containing node definitions
106
+ */
107
+ registry: IRegistry;
108
+
109
+ /**
110
+ * Server variables to expose to graphs
111
+ */
112
+ variables?: ServerVariable[];
113
+
114
+ /**
115
+ * Server events to expose to graphs
116
+ */
117
+ serverEvents?: ServerEvent[];
118
+
119
+ /**
120
+ * Lifecycle hooks for customizing behavior
121
+ */
122
+ hooks?: GraphWorkerHooks;
123
+
124
+ /**
125
+ * Custom message handlers for extending the protocol
126
+ */
127
+ customMessageHandlers?: Record<
128
+ string,
129
+ (message: unknown, ctx: MessageContext) => void
130
+ >;
131
+
132
+ /**
133
+ * Factory function for creating custom session objects
134
+ * Uses the existing SessionFactory interface from session.ts
135
+ */
136
+ sessionFactory?: SessionFactory;
137
+ }
138
+
139
+ /**
140
+ * Initialize the graph worker
141
+ * @param options - Configuration options including registry and customizations
142
+ */
143
+ export function initializeGraphWorker(options: GraphWorkerOptions): void {
144
+ const registry = options.registry;
145
+ const variables = options.variables ?? [];
146
+ const events = options.serverEvents ?? [];
147
+ const hooks = options.hooks ?? {};
148
+ const customHandlers = options.customMessageHandlers ?? {};
149
+ const sessionFactory = options.sessionFactory;
150
+
151
+ // Worker state
152
+ const activeRuns = new Map<string, ActiveRun>();
153
+ let sessionId: string | null = null;
154
+ let session: Session | null = null;
155
+
156
+ /**
157
+ * Send a message to the main thread
158
+ */
159
+ function sendMessage(message: ServerGraphRunnerMessage): void {
160
+ self.postMessage({
161
+ type: 'message',
162
+ data: message
163
+ });
164
+ }
165
+
166
+ /**
167
+ * Send an error to the main thread
168
+ */
169
+ function sendError(
170
+ code: string,
171
+ message: string,
172
+ details?: Record<string, unknown>
173
+ ): void {
174
+ sendMessage({
175
+ type: 'error',
176
+ code: code as any,
177
+ message,
178
+ ...details
179
+ });
180
+ }
181
+
182
+ const ctx: MessageContext = { sendMessage, sendError };
183
+
184
+ /**
185
+ * Handle incoming messages from main thread
186
+ */
187
+ async function handleMessage(message: GraphRunnerMessage): Promise<void> {
188
+ // Call onMessage hook if provided
189
+ if (hooks.onMessage) {
190
+ const shouldContinue = hooks.onMessage(message);
191
+ if (shouldContinue === false) {
192
+ return;
193
+ }
194
+ }
195
+
196
+ // Check for custom handlers
197
+ const customHandler = customHandlers[message.type];
198
+ if (customHandler) {
199
+ customHandler(message, ctx);
200
+ return;
201
+ }
202
+
203
+ switch (message.type) {
204
+ case 'hello':
205
+ handleHello(message, 'webworker-runner', ctx);
206
+ break;
207
+ case 'createSession':
208
+ await handleCreateSessionWithHooks(message);
209
+ break;
210
+ case 'getCapabilities':
211
+ handleGetCapabilities(ctx);
212
+ break;
213
+ case 'getServerVariables':
214
+ handleGetServerVariables(variables, ctx);
215
+ break;
216
+ case 'getServerEvents':
217
+ handleGetServerEvents(events, ctx);
218
+ break;
219
+ case 'getSocketConstraints':
220
+ handleGetSocketConstraints(
221
+ { nodeType: message.nodeType, socketName: message.socketName },
222
+ registry,
223
+ ctx
224
+ );
225
+ break;
226
+ case 'getNodeTypes':
227
+ handleGetNodeTypes(registry, ctx);
228
+ break;
229
+ case 'runGraph':
230
+ await handleRunGraphWithHooks(message);
231
+ break;
232
+ case 'stopGraph':
233
+ await handleStopGraphWithHooks(message);
234
+ break;
235
+ case 'getStatus':
236
+ handleGetStatus(message);
237
+ break;
238
+ case 'closeSession':
239
+ await handleCloseSessionWithHooks(message);
240
+ break;
241
+
242
+ default:
243
+ sendError(
244
+ 'PROTOCOL_VIOLATION',
245
+ `Unsupported message type: ${(message as any).type}`
246
+ );
247
+ }
248
+ }
249
+
250
+ /**
251
+ * Handle createSession with lifecycle hooks
252
+ */
253
+ async function handleCreateSessionWithHooks(message: {
254
+ type: 'createSession';
255
+ metadata?: Record<string, unknown>;
256
+ }): Promise<void> {
257
+ sessionId = handleCreateSession(message, ctx);
258
+
259
+ let sessionMetadata = message.metadata ?? {};
260
+
261
+ // Call onSessionCreated hook if provided
262
+ if (hooks.onSessionCreated) {
263
+ try {
264
+ const hookResult = await hooks.onSessionCreated(
265
+ sessionId,
266
+ message.metadata
267
+ );
268
+ if (hookResult && typeof hookResult === 'object') {
269
+ sessionMetadata = { ...sessionMetadata, ...hookResult };
270
+ }
271
+ } catch (error) {
272
+ console.error('Error in onSessionCreated hook:', error);
273
+ }
274
+ }
275
+
276
+ // Use custom session factory if provided, otherwise create default session
277
+ if (sessionFactory) {
278
+ try {
279
+ session = sessionFactory.createSession(sessionId, {
280
+ metadata: sessionMetadata
281
+ });
282
+ } catch (error) {
283
+ console.error('Error in sessionFactory:', error);
284
+ // Fallback to default session
285
+ session = {
286
+ sessionId,
287
+ metadata: sessionMetadata,
288
+ createdAt: Date.now(),
289
+ expiresAt: Date.now() + 24 * 60 * 60 * 1000,
290
+ config: { metadata: sessionMetadata },
291
+ activeRuns: new Set(),
292
+ state: {}
293
+ };
294
+ }
295
+ } else {
296
+ session = {
297
+ sessionId,
298
+ metadata: sessionMetadata,
299
+ createdAt: Date.now(),
300
+ expiresAt: Date.now() + 24 * 60 * 60 * 1000,
301
+ config: { metadata: sessionMetadata },
302
+ activeRuns: new Set(),
303
+ state: {}
304
+ };
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Handle closeSession with lifecycle hooks
310
+ */
311
+ async function handleCloseSessionWithHooks(message: {
312
+ type: 'closeSession';
313
+ sessionId: string;
314
+ }): Promise<void> {
315
+ // Call onSessionClosed hook if provided
316
+ if (hooks.onSessionClosed && session) {
317
+ try {
318
+ await hooks.onSessionClosed({
319
+ sessionId: session.sessionId,
320
+ metadata: session.metadata,
321
+ createdAt: session.createdAt
322
+ });
323
+ } catch (error) {
324
+ console.error('Error in onSessionClosed hook:', error);
325
+ }
326
+ }
327
+
328
+ for (const run of activeRuns.values()) {
329
+ run.engine.dispose();
330
+ }
331
+ activeRuns.clear();
332
+
333
+ sendMessage({
334
+ type: 'sessionClosed',
335
+ sessionId: message.sessionId
336
+ });
337
+
338
+ sessionId = null;
339
+ session = null;
340
+ }
341
+
342
+ /**
343
+ * Handle runGraph with lifecycle hooks
344
+ */
345
+ async function handleRunGraphWithHooks(message: {
346
+ type: 'runGraph';
347
+ sessionId: string;
348
+ graphId: string;
349
+ graph?: unknown;
350
+ inputs?: unknown;
351
+ options?: { trace?: boolean };
352
+ }): Promise<void> {
353
+ const runContext: RunContext = {
354
+ runId: '', // Will be set below
355
+ graphId: message.graphId,
356
+ sessionId: message.sessionId,
357
+ inputs: message.inputs,
358
+ options: message.options
359
+ };
360
+
361
+ // Call onRunStart hook if provided
362
+ if (hooks.onRunStart) {
363
+ try {
364
+ const shouldContinue = await hooks.onRunStart(runContext);
365
+ if (shouldContinue === false) {
366
+ sendMessage({
367
+ type: 'stopped',
368
+ runId: runContext.runId,
369
+ graphId: message.graphId,
370
+ reason: 'Cancelled by onRunStart hook'
371
+ });
372
+ return;
373
+ }
374
+ } catch (error) {
375
+ console.error('Error in onRunStart hook:', error);
376
+ }
377
+ }
378
+
379
+ await handleRunGraph(message, runContext);
380
+ }
381
+
382
+ /**
383
+ * Handle stopGraph with lifecycle hooks
384
+ */
385
+ async function handleStopGraphWithHooks(message: {
386
+ type: 'stopGraph';
387
+ sessionId: string;
388
+ runId: string;
389
+ }): Promise<void> {
390
+ const run = activeRuns.get(message.runId);
391
+ if (!run) {
392
+ sendError('RUN_NOT_FOUND', 'Run not found', { runId: message.runId });
393
+ return;
394
+ }
395
+
396
+ const runContext: RunContext = {
397
+ runId: message.runId,
398
+ graphId: run.graphId,
399
+ sessionId: message.sessionId
400
+ };
401
+
402
+ const reason = 'User requested stop';
403
+
404
+ // Call onRunStopped hook if provided
405
+ if (hooks.onRunStopped) {
406
+ try {
407
+ await hooks.onRunStopped(runContext, reason);
408
+ } catch (error) {
409
+ console.error('Error in onRunStopped hook:', error);
410
+ }
411
+ }
412
+
413
+ run.status = 'stopped';
414
+ run.engine.dispose();
415
+ activeRuns.delete(message.runId);
416
+
417
+ sendMessage({
418
+ type: 'stopped',
419
+ runId: message.runId,
420
+ graphId: run.graphId,
421
+ reason
422
+ });
423
+ }
424
+
425
+ async function handleRunGraph(
426
+ message: {
427
+ type: 'runGraph';
428
+ sessionId: string;
429
+ graphId: string;
430
+ graph?: unknown;
431
+ inputs?: unknown;
432
+ options?: { trace?: boolean };
433
+ },
434
+ runContext: RunContext
435
+ ): Promise<void> {
436
+ const runId = generateId('run');
437
+ runContext.runId = runId;
438
+
439
+ try {
440
+ if (!message.graph) {
441
+ sendError('INVALID_GRAPH', 'Graph not provided', {
442
+ runId,
443
+ graphId: message.graphId
444
+ });
445
+ return;
446
+ }
447
+
448
+ // Create logger
449
+ const logger = createForwardingLogger(
450
+ runId,
451
+ message.graphId,
452
+ sendMessage
453
+ );
454
+
455
+ // Prepare registry with dependencies
456
+ const registryWithDeps = prepareRegistryWithDependencies(
457
+ registry,
458
+ logger
459
+ );
460
+
461
+ // Parse and validate graph
462
+ const { graphInstance, errors } = parseAndValidateGraph(
463
+ message.graph,
464
+ registryWithDeps
465
+ );
466
+
467
+ if (errors.length > 0) {
468
+ sendError('VALIDATION_FAILED', errors.join('; '), {
469
+ runId,
470
+ graphId: message.graphId
471
+ });
472
+ return;
473
+ }
474
+
475
+ // Create engine
476
+ const engine = new Engine(graphInstance, registryWithDeps);
477
+
478
+ // Create run record
479
+ const run: ActiveRun = {
480
+ runId,
481
+ graphId: message.graphId,
482
+ engine,
483
+ graphInstance,
484
+ registry: registryWithDeps,
485
+ status: 'running',
486
+ startedAt: Date.now(),
487
+ performance: {
488
+ nodesExecuted: 0,
489
+ eventsEmitted: 0,
490
+ variableChanges: 0
491
+ },
492
+ isPaused: false,
493
+ executionPhase: 'start',
494
+ currentTick: 0
495
+ };
496
+
497
+ activeRuns.set(runId, run);
498
+
499
+ // Send run started
500
+ sendMessage({
501
+ type: 'runStarted',
502
+ runId,
503
+ graphId: message.graphId,
504
+ startedAt: run.startedAt
505
+ });
506
+
507
+ // Set up variable change tracking
508
+ setupVariableChangeTracking(run, message.graphId, ctx);
509
+
510
+ // Set up tracing if requested
511
+ if (message.options?.trace) {
512
+ setupTracing(run, message.graphId, ctx);
513
+ }
514
+
515
+ // Execute graph
516
+ executeGraphLifecycle(run, message.graphId, ctx)
517
+ .then(async () => {
518
+ // Call onRunComplete hook if provided
519
+ if (hooks.onRunComplete) {
520
+ try {
521
+ await hooks.onRunComplete(runContext, run);
522
+ } catch (error) {
523
+ console.error('Error in onRunComplete hook:', error);
524
+ }
525
+ }
526
+ })
527
+ .catch(async (error) => {
528
+ console.error('Graph execution error:', error);
529
+
530
+ // Call onRunError hook if provided
531
+ if (hooks.onRunError) {
532
+ try {
533
+ await hooks.onRunError(runContext, error);
534
+ } catch (hookError) {
535
+ console.error('Error in onRunError hook:', hookError);
536
+ }
537
+ }
538
+ })
539
+ .finally(() => {
540
+ activeRuns.delete(runId);
541
+ });
542
+ } catch (error) {
543
+ const errorMessage =
544
+ error instanceof Error ? error.message : String(error);
545
+ sendError('NODE_EXECUTION_ERROR', errorMessage, {
546
+ runId,
547
+ graphId: message.graphId
548
+ });
549
+
550
+ // Call onRunError hook if provided
551
+ if (hooks.onRunError) {
552
+ try {
553
+ await hooks.onRunError(runContext, error as Error);
554
+ } catch (hookError) {
555
+ console.error('Error in onRunError hook:', hookError);
556
+ }
557
+ }
558
+ }
559
+ }
560
+
561
+ function handleStopGraph(message: {
562
+ type: 'stopGraph';
563
+ sessionId: string;
564
+ runId: string;
565
+ }): void {
566
+ const run = activeRuns.get(message.runId);
567
+ if (!run) {
568
+ sendError('RUN_NOT_FOUND', 'Run not found', { runId: message.runId });
569
+ return;
570
+ }
571
+
572
+ run.status = 'stopped';
573
+ run.engine.dispose();
574
+ activeRuns.delete(message.runId);
575
+
576
+ sendMessage({
577
+ type: 'stopped',
578
+ runId: message.runId,
579
+ graphId: run.graphId,
580
+ reason: 'User requested stop'
581
+ });
582
+ }
583
+
584
+ function handleGetStatus(message: {
585
+ type: 'getStatus';
586
+ sessionId: string;
587
+ runId: string;
588
+ }): void {
589
+ const run = activeRuns.get(message.runId);
590
+ if (!run) {
591
+ sendError('RUN_NOT_FOUND', 'Run not found', { runId: message.runId });
592
+ return;
593
+ }
594
+
595
+ const elapsedMs = Date.now() - run.startedAt;
596
+
597
+ sendMessage({
598
+ type: 'status',
599
+ runId: run.runId,
600
+ graphId: run.graphId,
601
+ status: run.status,
602
+ startedAt: run.startedAt,
603
+ elapsedMs,
604
+ performance: run.performance,
605
+ startedGraphs: []
606
+ });
607
+ }
608
+
609
+ function handleCloseSession(message: {
610
+ type: 'closeSession';
611
+ sessionId: string;
612
+ }): void {
613
+ for (const run of activeRuns.values()) {
614
+ run.engine.dispose();
615
+ }
616
+ activeRuns.clear();
617
+
618
+ sendMessage({
619
+ type: 'sessionClosed',
620
+ sessionId: message.sessionId
621
+ });
622
+
623
+ sessionId = null;
624
+ }
625
+
626
+ /**
627
+ * Main message handler
628
+ */
629
+ self.onmessage = (event: MessageEvent) => {
630
+ const message = event.data.message;
631
+ void handleMessage(message);
632
+ };
633
+ }