yaml-flow 3.1.1 → 5.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 (194) hide show
  1. package/README.md +81 -20
  2. package/board-live-cards-cli.js +37 -0
  3. package/browser/board-livegraph-runtime.js +1453 -0
  4. package/browser/board-livegraph-runtime.js.map +1 -0
  5. package/browser/card-compute.js +153 -433
  6. package/browser/live-cards.js +868 -115
  7. package/browser/live-cards.schema.json +90 -83
  8. package/dist/board-livegraph-runtime/index.cjs +1448 -0
  9. package/dist/board-livegraph-runtime/index.cjs.map +1 -0
  10. package/dist/board-livegraph-runtime/index.d.cts +101 -0
  11. package/dist/board-livegraph-runtime/index.d.ts +101 -0
  12. package/dist/board-livegraph-runtime/index.js +1441 -0
  13. package/dist/board-livegraph-runtime/index.js.map +1 -0
  14. package/dist/card-compute/index.cjs +266 -431
  15. package/dist/card-compute/index.cjs.map +1 -1
  16. package/dist/card-compute/index.d.cts +77 -49
  17. package/dist/card-compute/index.d.ts +77 -49
  18. package/dist/card-compute/index.js +263 -432
  19. package/dist/card-compute/index.js.map +1 -1
  20. package/dist/cli/board-live-cards-cli.cjs +2750 -0
  21. package/dist/cli/board-live-cards-cli.cjs.map +1 -0
  22. package/dist/cli/board-live-cards-cli.d.cts +205 -0
  23. package/dist/cli/board-live-cards-cli.d.ts +205 -0
  24. package/dist/cli/board-live-cards-cli.js +2702 -0
  25. package/dist/cli/board-live-cards-cli.js.map +1 -0
  26. package/dist/{constants-B2zqu10b.d.ts → constants-DuzE5n03.d.ts} +2 -2
  27. package/dist/{constants-DJZU1pwJ.d.cts → constants-ozjf1Ejw.d.cts} +2 -2
  28. package/dist/continuous-event-graph/index.cjs +258 -464
  29. package/dist/continuous-event-graph/index.cjs.map +1 -1
  30. package/dist/continuous-event-graph/index.d.cts +18 -358
  31. package/dist/continuous-event-graph/index.d.ts +18 -358
  32. package/dist/continuous-event-graph/index.js +255 -464
  33. package/dist/continuous-event-graph/index.js.map +1 -1
  34. package/dist/event-graph/index.cjs +4 -4
  35. package/dist/event-graph/index.cjs.map +1 -1
  36. package/dist/event-graph/index.d.cts +5 -5
  37. package/dist/event-graph/index.d.ts +5 -5
  38. package/dist/event-graph/index.js +4 -4
  39. package/dist/event-graph/index.js.map +1 -1
  40. package/dist/index.cjs +1684 -555
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +26 -7
  43. package/dist/index.d.ts +26 -7
  44. package/dist/index.js +1678 -555
  45. package/dist/index.js.map +1 -1
  46. package/dist/inference/index.cjs +138 -19
  47. package/dist/inference/index.cjs.map +1 -1
  48. package/dist/inference/index.d.cts +2 -2
  49. package/dist/inference/index.d.ts +2 -2
  50. package/dist/inference/index.js +138 -19
  51. package/dist/inference/index.js.map +1 -1
  52. package/dist/journal-DRfJiheM.d.cts +28 -0
  53. package/dist/journal-NLYuqege.d.ts +28 -0
  54. package/dist/live-cards-bridge-Or7fdEJV.d.ts +316 -0
  55. package/dist/live-cards-bridge-vGJ6tMzN.d.cts +316 -0
  56. package/dist/schedule-CMcZe5Ny.d.ts +21 -0
  57. package/dist/schedule-CiucyCan.d.cts +21 -0
  58. package/dist/step-machine/index.cjs +18 -1
  59. package/dist/step-machine/index.cjs.map +1 -1
  60. package/dist/step-machine/index.d.cts +2 -2
  61. package/dist/step-machine/index.d.ts +2 -2
  62. package/dist/step-machine/index.js +18 -1
  63. package/dist/step-machine/index.js.map +1 -1
  64. package/dist/stores/file.d.cts +1 -1
  65. package/dist/stores/file.d.ts +1 -1
  66. package/dist/stores/index.d.cts +1 -1
  67. package/dist/stores/index.d.ts +1 -1
  68. package/dist/stores/localStorage.d.cts +1 -1
  69. package/dist/stores/localStorage.d.ts +1 -1
  70. package/dist/stores/memory.d.cts +1 -1
  71. package/dist/stores/memory.d.ts +1 -1
  72. package/dist/{types-BwvgvlOO.d.cts → types-BzLD8bjb.d.cts} +1 -1
  73. package/dist/{types-ClRA8hzC.d.ts → types-C2eJ7DAV.d.ts} +1 -1
  74. package/dist/{types-DEj7OakX.d.cts → types-CMFSIjpc.d.cts} +39 -4
  75. package/dist/{types-DEj7OakX.d.ts → types-CMFSIjpc.d.ts} +39 -4
  76. package/dist/{types-FZ_eyErS.d.cts → types-ycun84cq.d.cts} +1 -0
  77. package/dist/{types-FZ_eyErS.d.ts → types-ycun84cq.d.ts} +1 -0
  78. package/dist/{validate-DEZ2Ymdb.d.ts → validate-DJQTQ6bP.d.ts} +1 -1
  79. package/dist/{validate-DqKTZg_o.d.cts → validate-ke92Cleg.d.cts} +1 -1
  80. package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +22 -0
  81. package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +16 -0
  82. package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +15 -0
  83. package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +15 -0
  84. package/examples/browser/boards/portfolio-tracker/fetch-prices.js +43 -0
  85. package/examples/browser/boards/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
  86. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +7 -0
  87. package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +217 -0
  88. package/examples/browser/livecards-browser/index.html +41 -0
  89. package/examples/browser/{index.html → step-machine-browser/index.html} +53 -53
  90. package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
  91. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
  92. package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
  93. package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
  94. package/examples/cli/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
  95. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
  96. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
  97. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
  98. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
  99. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
  100. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
  101. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
  102. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
  103. package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
  104. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
  105. package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
  106. package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
  107. package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +36 -0
  108. package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +30 -0
  109. package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +19 -0
  110. package/examples/cli/step-machine-demo/step-cli-echo-y.js +15 -0
  111. package/examples/cli/step-machine-demo/step2-double-cli.js +39 -0
  112. package/examples/cli/step-machine-demo/two-step-math-handlers.js +32 -0
  113. package/examples/cli/step-machine-demo/two-step-math.flow.yaml +31 -0
  114. package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +24 -0
  115. package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +35 -0
  116. package/examples/example-board/board.yaml +23 -0
  117. package/examples/example-board/bootstrap_payload.json +1 -0
  118. package/examples/example-board/cards/card-chain-region-alert.json +39 -0
  119. package/examples/example-board/cards/card-chain-region-totals.json +26 -0
  120. package/examples/example-board/cards/card-chain-top-region.json +24 -0
  121. package/examples/example-board/cards/card-ex-actions.json +32 -0
  122. package/examples/example-board/cards/card-ex-chart.json +30 -0
  123. package/examples/example-board/cards/card-ex-filter.json +36 -0
  124. package/examples/example-board/cards/card-ex-filtered-by-preference.json +59 -0
  125. package/examples/example-board/cards/card-ex-form.json +91 -0
  126. package/examples/example-board/cards/card-ex-list.json +22 -0
  127. package/examples/example-board/cards/card-ex-markdown.json +17 -0
  128. package/examples/example-board/cards/card-ex-metric.json +19 -0
  129. package/examples/example-board/cards/card-ex-narrative.json +36 -0
  130. package/examples/example-board/cards/card-ex-source-http.json +28 -0
  131. package/examples/example-board/cards/card-ex-source.json +21 -0
  132. package/examples/example-board/cards/card-ex-status.json +35 -0
  133. package/examples/example-board/cards/card-ex-table.json +30 -0
  134. package/examples/example-board/cards/card-ex-todo.json +29 -0
  135. package/examples/example-board/demo-chat-handler.js +69 -0
  136. package/examples/example-board/demo-server.js +87 -0
  137. package/examples/example-board/demo-shell-browser.html +806 -0
  138. package/examples/example-board/demo-shell-with-server.html +280 -0
  139. package/examples/example-board/demo-shell.html +62 -0
  140. package/examples/example-board/demo-task-executor.js +255 -0
  141. package/examples/example-board/mock.db +15 -0
  142. package/examples/example-board/reusable-board-runtime-client.js +265 -0
  143. package/examples/example-board/reusable-runtime-artifacts-adapter.js +233 -0
  144. package/examples/example-board/reusable-server-runtime.js +1284 -0
  145. package/examples/index.html +799 -0
  146. package/examples/{batch → npm-libs/batch}/batch-step-machine.ts +1 -1
  147. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-cards-board.ts +18 -18
  148. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-portfolio-dashboard.ts +24 -24
  149. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/portfolio-tracker.ts +1 -1
  150. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-monitoring.ts +1 -1
  151. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-pipeline.ts +1 -1
  152. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/soc-incident-board.ts +1 -1
  153. package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/stock-dashboard.ts +1 -1
  154. package/examples/{event-graph → npm-libs/event-graph}/ci-cd-pipeline.ts +1 -1
  155. package/examples/{event-graph → npm-libs/event-graph}/executor-diamond.ts +1 -1
  156. package/examples/{event-graph → npm-libs/event-graph}/executor-pipeline.ts +1 -1
  157. package/examples/{event-graph → npm-libs/event-graph}/research-pipeline.ts +1 -1
  158. package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/multi-stage-etl.ts +1 -1
  159. package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/url-processing-pipeline.ts +1 -1
  160. package/examples/{inference → npm-libs/inference}/azure-deployment.ts +1 -1
  161. package/examples/{inference → npm-libs/inference}/copilot-cli.ts +1 -1
  162. package/examples/{inference → npm-libs/inference}/data-pipeline.ts +1 -1
  163. package/examples/{inference → npm-libs/inference}/pluggable-adapters.ts +1 -1
  164. package/examples/{node → npm-libs/node}/ai-conversation.ts +1 -1
  165. package/examples/{node → npm-libs/node}/simple-greeting.ts +2 -2
  166. package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
  167. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
  168. package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
  169. package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
  170. package/examples/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
  171. package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
  172. package/examples/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
  173. package/examples/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
  174. package/examples/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
  175. package/examples/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
  176. package/examples/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
  177. package/examples/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
  178. package/examples/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
  179. package/examples/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
  180. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker-task-executor.cjs +96 -0
  181. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
  182. package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
  183. package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
  184. package/package.json +27 -2
  185. package/schema/board-status.schema.json +118 -0
  186. package/schema/card-runtime.schema.json +25 -0
  187. package/schema/flow.schema.json +5 -0
  188. package/schema/live-cards.schema.json +90 -83
  189. package/step-machine-cli.js +674 -0
  190. package/browser/ingest-board.js +0 -296
  191. package/examples/ingest.js +0 -733
  192. /package/examples/{flows → npm-libs/flows}/ai-conversation.yaml +0 -0
  193. /package/examples/{flows → npm-libs/flows}/order-processing.yaml +0 -0
  194. /package/examples/{flows → npm-libs/flows}/simple-greeting.yaml +0 -0
@@ -0,0 +1,265 @@
1
+ (function () {
2
+ function clone(x) {
3
+ return JSON.parse(JSON.stringify(x));
4
+ }
5
+
6
+ function replaceNodeInPlace(target, source) {
7
+ Object.keys(target).forEach((k) => delete target[k]);
8
+ Object.assign(target, clone(source));
9
+ }
10
+
11
+ function stableNodeString(node) {
12
+ return JSON.stringify(node);
13
+ }
14
+
15
+ function createBoardRuntimeClient(options) {
16
+ if (!options || typeof options !== 'object') {
17
+ throw new Error('options are required');
18
+ }
19
+
20
+ const fetchServer = options.fetchServer;
21
+ const boardPaths = options.boardPaths;
22
+ const buildLiveCardModelsFromArtifacts = options.buildLiveCardModelsFromArtifacts;
23
+ const getServerOrigin = options.getServerOrigin;
24
+
25
+ if (typeof fetchServer !== 'function') throw new Error('options.fetchServer is required');
26
+ if (typeof boardPaths !== 'function') throw new Error('options.boardPaths is required');
27
+ if (typeof buildLiveCardModelsFromArtifacts !== 'function') {
28
+ throw new Error('options.buildLiveCardModelsFromArtifacts is required');
29
+ }
30
+ if (typeof getServerOrigin !== 'function') throw new Error('options.getServerOrigin is required');
31
+
32
+ let nodesById = {};
33
+ let board = null;
34
+ let sse = null;
35
+ let currentMode = String(options.initialMode || 'board');
36
+ const canvas = options.canvas && typeof options.canvas === 'object'
37
+ ? options.canvas
38
+ : { height: '72vh', overflow: 'auto' };
39
+
40
+ function syncBoardNodes(nextNodes) {
41
+ const existingIds = new Set(board ? board.nodes.map((n) => n.id) : []);
42
+ const nextById = Object.fromEntries(nextNodes.map((n) => [n.id, n]));
43
+ let changed = false;
44
+
45
+ if (board) {
46
+ for (const id of existingIds) {
47
+ if (!nextById[id]) {
48
+ board.remove(id);
49
+ changed = true;
50
+ }
51
+ }
52
+ }
53
+
54
+ for (const nextNode of nextNodes) {
55
+ const existing = nodesById[nextNode.id];
56
+ if (existing) {
57
+ const prevStr = stableNodeString(existing);
58
+ const nextStr = stableNodeString(nextNode);
59
+ if (prevStr !== nextStr) {
60
+ replaceNodeInPlace(existing, nextNode);
61
+ changed = true;
62
+ }
63
+ } else {
64
+ nodesById[nextNode.id] = clone(nextNode);
65
+ if (board) board.add(nodesById[nextNode.id]);
66
+ changed = true;
67
+ }
68
+ }
69
+
70
+ if (board && changed) board.refresh();
71
+ }
72
+
73
+ async function uploadCardFile(boardId, cardId, file, opts) {
74
+ if (!file) return null;
75
+ const optionsObj = opts && typeof opts === 'object' ? opts : {};
76
+ const inChat = optionsObj.inChat === true;
77
+ const fileName = typeof file.name === 'string' ? file.name : 'upload.bin';
78
+ const contentType = file.type || 'application/octet-stream';
79
+ const paths = boardPaths(boardId);
80
+ const uploadPath = inChat
81
+ ? `${paths.cardFile(cardId)}?inChat=true`
82
+ : paths.cardFile(cardId);
83
+
84
+ const upload = await fetchServer(uploadPath, {
85
+ method: 'POST',
86
+ headers: {
87
+ 'content-type': contentType,
88
+ 'x-file-name': encodeURIComponent(fileName),
89
+ },
90
+ body: file,
91
+ });
92
+
93
+ if (!upload.ok) {
94
+ const errText = await upload.text();
95
+ throw new Error(`Upload failed (${upload.status}): ${errText || 'unknown error'}`);
96
+ }
97
+
98
+ const payload = await upload.json();
99
+ return payload && payload.file ? payload.file : null;
100
+ }
101
+
102
+ async function uploadActionFiles(boardId, cardId, actionType, payload) {
103
+ if (actionType !== 'chat-send' && actionType !== 'file-upload') return payload || {};
104
+ const nextPayload = { ...(payload || {}) };
105
+ const rawFiles = Array.isArray(nextPayload.files) ? nextPayload.files : [];
106
+ if (!rawFiles.length) {
107
+ nextPayload.files = [];
108
+ return nextPayload;
109
+ }
110
+
111
+ const uploaded = [];
112
+ for (const file of rawFiles) {
113
+ const fileMeta = await uploadCardFile(boardId, cardId, file, { inChat: actionType === 'chat-send' });
114
+ if (fileMeta) uploaded.push(fileMeta);
115
+ }
116
+
117
+ // For chat uploads, server-side file API already records file metadata and emits system chat logs.
118
+ nextPayload.files = actionType === 'chat-send' ? [] : uploaded;
119
+ return nextPayload;
120
+ }
121
+
122
+ async function bootstrapBoard(params) {
123
+ const p = params && typeof params === 'object' ? params : {};
124
+ const boardId = String(p.boardId || 'default');
125
+ const taskExecutorPath = typeof p.taskExecutorPath === 'string' ? p.taskExecutorPath.trim() : '';
126
+ const runDemoSetup = p.runDemoSetup !== false;
127
+ const mode = String(p.mode || currentMode || 'board');
128
+ const rootEl = p.rootElement;
129
+ if (!rootEl) throw new Error('bootstrapBoard requires params.rootElement');
130
+
131
+ const paths = boardPaths(boardId);
132
+
133
+ if (runDemoSetup) {
134
+ const setup = await fetchServer(paths.demoSetup);
135
+ if (!setup.ok) throw new Error(`Server demo-setup failed (${setup.status}).`);
136
+ }
137
+
138
+ const initBoardPath = taskExecutorPath
139
+ ? `${paths.initBoard}?taskExecutorPath=${encodeURIComponent(taskExecutorPath)}`
140
+ : paths.initBoard;
141
+ const initBoardRes = await fetchServer(initBoardPath);
142
+ if (!initBoardRes.ok) throw new Error(`Server init-board failed (${initBoardRes.status}).`);
143
+
144
+ const bootstrapCardsRes = await fetchServer(paths.bootstrapCards);
145
+ if (!bootstrapCardsRes.ok) {
146
+ throw new Error(`Server bootstrap-cards failed (${bootstrapCardsRes.status}).`);
147
+ }
148
+
149
+ const payload = await bootstrapCardsRes.json();
150
+ const cards = buildLiveCardModelsFromArtifacts(payload);
151
+ if (!Array.isArray(cards)) throw new Error('Server payload missing published runtime artifacts');
152
+
153
+ nodesById = {};
154
+ for (const n of cards) nodesById[n.id] = clone(n);
155
+
156
+ const engine = LiveCard.init({
157
+ resolve: (id) => nodesById[id],
158
+ onPatchState: async (id, patch) => {
159
+ await fetchServer(paths.patchCard(id), {
160
+ method: 'PATCH',
161
+ headers: { 'content-type': 'application/json' },
162
+ body: JSON.stringify(patch || {}),
163
+ });
164
+ },
165
+ onRefresh: async (id) => {
166
+ await fetchServer(paths.patchCard(id), {
167
+ method: 'PATCH',
168
+ headers: { 'content-type': 'application/json' },
169
+ body: JSON.stringify({}),
170
+ });
171
+ },
172
+ onAction: async (id, actionType, actionPayload) => {
173
+ const uploadedPayload = await uploadActionFiles(boardId, id, actionType, actionPayload);
174
+ await fetchServer(paths.cardAction(id), {
175
+ method: 'POST',
176
+ headers: { 'content-type': 'application/json' },
177
+ body: JSON.stringify({ actionType, payload: uploadedPayload || {} }),
178
+ });
179
+ },
180
+ getChatMessages: async (id) => {
181
+ const res = await fetchServer(paths.cardChats(id));
182
+ if (!res.ok) return [];
183
+ const chatPayload = await res.json();
184
+ const items = Array.isArray(chatPayload && chatPayload.messages) ? chatPayload.messages : [];
185
+ return items.map((m) => ({
186
+ role: m && typeof m.role === 'string' ? m.role : 'system',
187
+ text: m && typeof m.text === 'string' ? m.text : '',
188
+ files: [],
189
+ }));
190
+ },
191
+ });
192
+
193
+ rootEl.innerHTML = '';
194
+ board = LiveCard.Board(engine, rootEl, {
195
+ nodes: Object.values(nodesById),
196
+ mode,
197
+ canvas,
198
+ });
199
+ currentMode = mode;
200
+
201
+ const origin = getServerOrigin();
202
+ if (!origin) {
203
+ throw new Error('Server origin not resolved before SSE start');
204
+ }
205
+ sse = new EventSource(`${origin}${paths.stream}`);
206
+ sse.onmessage = function (evt) {
207
+ try {
208
+ const update = JSON.parse(evt.data || '{}');
209
+ syncBoardNodes(buildLiveCardModelsFromArtifacts(update));
210
+ if (board && board.engine && typeof board.engine.onServerSseEvent === 'function') {
211
+ board.engine.onServerSseEvent();
212
+ } else if (board && board.engine && typeof board.engine.refreshOpenChatModal === 'function') {
213
+ board.engine.refreshOpenChatModal();
214
+ }
215
+ } catch (err) {
216
+ console.warn('Bad SSE payload', err);
217
+ }
218
+ };
219
+
220
+ return board;
221
+ }
222
+
223
+ function dispose() {
224
+ if (sse) {
225
+ sse.close();
226
+ sse = null;
227
+ }
228
+ board = null;
229
+ nodesById = {};
230
+ }
231
+
232
+ function setMode(mode) {
233
+ currentMode = String(mode || 'board');
234
+ if (board) board.setMode(currentMode);
235
+ }
236
+
237
+ function autoLayout() {
238
+ if (!board) return;
239
+ board.setMode('canvas');
240
+ currentMode = 'canvas';
241
+ board.autoLayout();
242
+ }
243
+
244
+ function setDevMode(enabled) {
245
+ if (board) board.setDevMode(Boolean(enabled));
246
+ }
247
+
248
+ function getCurrentMode() {
249
+ return currentMode;
250
+ }
251
+
252
+ return {
253
+ bootstrapBoard,
254
+ dispose,
255
+ setMode,
256
+ autoLayout,
257
+ setDevMode,
258
+ getCurrentMode,
259
+ };
260
+ }
261
+
262
+ window.ReusableBoardRuntimeClient = {
263
+ createBoardRuntimeClient,
264
+ };
265
+ })();
@@ -0,0 +1,233 @@
1
+ function clone(value) {
2
+ return JSON.parse(JSON.stringify(value));
3
+ }
4
+
5
+ function taskStatusToCardStatus(taskStatus) {
6
+ if (taskStatus === 'running' || taskStatus === 'in-progress') return 'loading';
7
+ if (taskStatus === 'failed') return 'error';
8
+ if (taskStatus === 'completed') return 'fresh';
9
+ return 'fresh';
10
+ }
11
+
12
+ function cardStatusToTaskStatus(cardStatus) {
13
+ if (cardStatus === 'loading') return 'in-progress';
14
+ if (cardStatus === 'error') return 'failed';
15
+ if (cardStatus === 'stale') return 'pending';
16
+ if (cardStatus === 'fresh') return 'completed';
17
+ return 'pending';
18
+ }
19
+
20
+ function ensureObject(value, name) {
21
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
22
+ throw new Error(`${name} must be an object`);
23
+ }
24
+ return value;
25
+ }
26
+
27
+ function normalizeCardRuntimeArtifact(cardId, artifact) {
28
+ const safeArtifact = artifact && typeof artifact === 'object' && !Array.isArray(artifact)
29
+ ? artifact
30
+ : {};
31
+
32
+ const cardData = safeArtifact.card_data && typeof safeArtifact.card_data === 'object' && !Array.isArray(safeArtifact.card_data)
33
+ ? clone(safeArtifact.card_data)
34
+ : {};
35
+
36
+ const computedValues = safeArtifact.computed_values && typeof safeArtifact.computed_values === 'object' && !Array.isArray(safeArtifact.computed_values)
37
+ ? clone(safeArtifact.computed_values)
38
+ : {};
39
+
40
+ const fetchedSources = safeArtifact.fetched_sources && typeof safeArtifact.fetched_sources === 'object' && !Array.isArray(safeArtifact.fetched_sources)
41
+ ? clone(safeArtifact.fetched_sources)
42
+ : {};
43
+
44
+ const requiresData = safeArtifact.requires && typeof safeArtifact.requires === 'object' && !Array.isArray(safeArtifact.requires)
45
+ ? clone(safeArtifact.requires)
46
+ : {};
47
+
48
+ return {
49
+ schema_version: safeArtifact.schema_version || 'v1',
50
+ card_id: typeof safeArtifact.card_id === 'string' ? safeArtifact.card_id : cardId,
51
+ card_data: cardData,
52
+ computed_values: computedValues,
53
+ fetched_sources: fetchedSources,
54
+ requires: requiresData,
55
+ };
56
+ }
57
+
58
+ function resolveRequiresData(cardDefinition, dataObjectsByToken) {
59
+ const resolved = {};
60
+ const tokens = Array.isArray(cardDefinition && cardDefinition.requires) ? cardDefinition.requires : [];
61
+ const safeObjects = dataObjectsByToken && typeof dataObjectsByToken === 'object' && !Array.isArray(dataObjectsByToken)
62
+ ? dataObjectsByToken
63
+ : {};
64
+
65
+ for (const token of tokens) {
66
+ if (!Object.prototype.hasOwnProperty.call(safeObjects, token)) continue;
67
+ resolved[token] = clone(safeObjects[token]);
68
+ }
69
+
70
+ return resolved;
71
+ }
72
+
73
+ function buildLiveCardModelsFromArtifacts(payload) {
74
+ const safePayload = ensureObject(payload, 'payload');
75
+ const cardDefinitions = Array.isArray(safePayload.cardDefinitions) ? safePayload.cardDefinitions : [];
76
+ const statusSnapshot = safePayload.statusSnapshot && typeof safePayload.statusSnapshot === 'object' ? safePayload.statusSnapshot : {};
77
+ const cardRuntimeById = safePayload.cardRuntimeById && typeof safePayload.cardRuntimeById === 'object' ? safePayload.cardRuntimeById : {};
78
+ const dataObjectsByToken = safePayload.dataObjectsByToken && typeof safePayload.dataObjectsByToken === 'object' ? safePayload.dataObjectsByToken : {};
79
+ const statusCards = Array.isArray(statusSnapshot.cards) ? statusSnapshot.cards : [];
80
+ const statusById = new Map(statusCards.map((card) => [card.name, card]));
81
+
82
+ return cardDefinitions.map((cardDefinition) => {
83
+ const card = clone(cardDefinition);
84
+ const cardId = card && card.id;
85
+ if (!cardId) throw new Error('cardDefinitions entry missing id');
86
+
87
+ const statusCard = statusById.get(cardId);
88
+ const runtimeArtifact = normalizeCardRuntimeArtifact(cardId, cardRuntimeById[cardId]);
89
+
90
+ const cardData = {
91
+ ...((card.card_data && typeof card.card_data === 'object' && !Array.isArray(card.card_data)) ? card.card_data : {}),
92
+ ...(runtimeArtifact.card_data || {}),
93
+ status: taskStatusToCardStatus(statusCard && statusCard.status),
94
+ lastRun: (statusCard && statusCard.runtime && statusCard.runtime.last_transition_at) || null,
95
+ };
96
+
97
+ if (statusCard && statusCard.error && statusCard.error.message) {
98
+ cardData.error = statusCard.error.message;
99
+ }
100
+
101
+ const runtimeState = statusCard
102
+ ? {
103
+ task_status: statusCard.status || null,
104
+ card_status: taskStatusToCardStatus(statusCard.status),
105
+ runtime: clone(statusCard.runtime || {}),
106
+ error: statusCard.error ? clone(statusCard.error) : null,
107
+ blocked_by: Array.isArray(statusCard.blocked_by) ? clone(statusCard.blocked_by) : [],
108
+ requires_missing: Array.isArray(statusCard.requires_missing) ? clone(statusCard.requires_missing) : [],
109
+ }
110
+ : {
111
+ task_status: null,
112
+ card_status: cardData.status || 'fresh',
113
+ runtime: { last_transition_at: cardData.lastRun || null },
114
+ error: cardData.error ? { message: cardData.error } : null,
115
+ blocked_by: [],
116
+ requires_missing: [],
117
+ };
118
+
119
+ return {
120
+ id: cardId,
121
+ card,
122
+ card_data: cardData,
123
+ fetched_sources: runtimeArtifact.fetched_sources || {},
124
+ requires: resolveRequiresData(card, dataObjectsByToken),
125
+ computed_values: runtimeArtifact.computed_values || {},
126
+ runtime_state: runtimeState,
127
+ data_objects: clone(dataObjectsByToken),
128
+ };
129
+ });
130
+ }
131
+
132
+ function buildBrowserArtifactsFromRuntime({ boardPath, cardDefinitions, runtimeModels, graphState }) {
133
+ const safeCardDefinitions = Array.isArray(cardDefinitions) ? cardDefinitions : [];
134
+ const safeRuntimeModels = Array.isArray(runtimeModels) ? runtimeModels : [];
135
+ const runtimeModelById = new Map(safeRuntimeModels.map((model) => [model.id, model]));
136
+ const taskStates = graphState && graphState.state && graphState.state.tasks ? graphState.state.tasks : {};
137
+
138
+ const cardRuntimeById = {};
139
+ for (const model of safeRuntimeModels) {
140
+ if (!model || !model.id) continue;
141
+ cardRuntimeById[model.id] = {
142
+ schema_version: 'v1',
143
+ card_id: model.id,
144
+ card_data: clone(model.card_data || {}),
145
+ computed_values: clone(model.computed_values || {}),
146
+ fetched_sources: clone(model.fetched_sources || {}),
147
+ requires: clone(model.requires || {}),
148
+ };
149
+ }
150
+
151
+ const dataObjectsByToken = {};
152
+ for (const taskName of Object.keys(taskStates)) {
153
+ const taskState = taskStates[taskName] || {};
154
+ const taskData = taskState.data && typeof taskState.data === 'object' ? taskState.data : {};
155
+ const providesData = taskData.provides_data && typeof taskData.provides_data === 'object'
156
+ ? taskData.provides_data
157
+ : {};
158
+
159
+ for (const token of Object.keys(providesData)) {
160
+ dataObjectsByToken[token] = clone(providesData[token]);
161
+ }
162
+ }
163
+
164
+ const statusCards = safeCardDefinitions.map((cardDefinition) => {
165
+ const runtimeModel = runtimeModelById.get(cardDefinition.id) || {};
166
+ const taskState = taskStates[cardDefinition.id] || {};
167
+ const taskStatus = typeof taskState.status === 'string'
168
+ ? taskState.status
169
+ : cardStatusToTaskStatus(runtimeModel.card_data && runtimeModel.card_data.status);
170
+
171
+ const errorMessage = typeof taskState.error === 'string'
172
+ ? taskState.error
173
+ : runtimeModel.card_data && typeof runtimeModel.card_data.error === 'string'
174
+ ? runtimeModel.card_data.error
175
+ : null;
176
+
177
+ return {
178
+ name: cardDefinition.id,
179
+ status: taskStatus,
180
+ error: errorMessage ? {
181
+ message: errorMessage,
182
+ code: 'TASK_FAILED',
183
+ at: taskState.failedAt || null,
184
+ source: 'browser-runtime',
185
+ } : undefined,
186
+ requires: Array.isArray(cardDefinition.requires) ? cardDefinition.requires : [],
187
+ requires_satisfied: [],
188
+ requires_missing: [],
189
+ provides_declared: Array.isArray(cardDefinition.provides)
190
+ ? cardDefinition.provides.map((entry) => entry.bindTo)
191
+ : [cardDefinition.id],
192
+ provides_runtime: Object.keys((taskState.data && taskState.data.provides_data) || {}).sort(),
193
+ blocked_by: [],
194
+ unblocks: [],
195
+ runtime: {
196
+ attempt_count: taskState.executionCount || 0,
197
+ restart_count: taskState.retryCount || 0,
198
+ in_progress_since: taskStatus === 'in-progress' ? (taskState.startedAt || null) : null,
199
+ last_transition_at: taskState.lastUpdated || (runtimeModel.card_data && runtimeModel.card_data.lastRun) || null,
200
+ last_completed_at: taskState.completedAt || null,
201
+ last_restarted_at: taskState.startedAt || null,
202
+ status_age_ms: null,
203
+ },
204
+ };
205
+ });
206
+
207
+ return {
208
+ cardDefinitions: clone(safeCardDefinitions),
209
+ cardRuntimeById,
210
+ dataObjectsByToken,
211
+ statusSnapshot: {
212
+ schema_version: 'v1',
213
+ meta: { board: { path: boardPath || 'browser-runtime' } },
214
+ summary: {
215
+ card_count: statusCards.length,
216
+ completed: statusCards.filter((card) => card.status === 'completed').length,
217
+ eligible: 0,
218
+ pending: statusCards.filter((card) => card.status === 'pending').length,
219
+ blocked: 0,
220
+ unresolved: 0,
221
+ failed: statusCards.filter((card) => card.status === 'failed').length,
222
+ in_progress: statusCards.filter((card) => card.status === 'in-progress').length,
223
+ orphan_cards: 0,
224
+ topology: {
225
+ edge_count: 0,
226
+ max_fan_out_card: null,
227
+ max_fan_out: 0,
228
+ },
229
+ },
230
+ cards: statusCards,
231
+ },
232
+ };
233
+ }