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
@@ -1,10 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var fs = require('fs');
4
- var crypto = require('crypto');
5
3
  var child_process = require('child_process');
4
+ var jsonata2 = require('jsonata');
6
5
  require('ajv-formats');
7
6
 
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var jsonata2__default = /*#__PURE__*/_interopDefault(jsonata2);
10
+
8
11
  // src/event-graph/constants.ts
9
12
  var TASK_STATUS = {
10
13
  NOT_STARTED: "not-started",
@@ -247,43 +250,51 @@ function applyEvent(live, event) {
247
250
  if ("executionId" in event && event.executionId && event.executionId !== state.executionId) {
248
251
  return live;
249
252
  }
250
- let newState;
251
253
  switch (event.type) {
254
+ // --- Execution state transitions ---
252
255
  case "task-started":
253
- newState = applyTaskStart(state, event.taskName);
254
- break;
256
+ return { config, state: applyTaskStart(state, event.taskName) };
255
257
  case "task-completed":
256
- newState = applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data);
257
- break;
258
+ return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };
258
259
  case "task-failed":
259
- newState = applyTaskFailure(state, config, event.taskName, event.error);
260
- break;
260
+ return { config, state: applyTaskFailure(state, config, event.taskName, event.error) };
261
261
  case "task-progress":
262
- newState = applyTaskProgress(state, event.taskName, event.message, event.progress);
263
- break;
262
+ return { config, state: applyTaskProgress(state, event.taskName, event.message, event.progress) };
264
263
  case "task-restart":
265
- newState = applyTaskRestart(state, event.taskName);
266
- break;
264
+ return { config, state: applyTaskRestart(state, event.taskName) };
267
265
  case "inject-tokens":
268
- newState = {
269
- ...state,
270
- availableOutputs: [.../* @__PURE__ */ new Set([...state.availableOutputs, ...event.tokens])],
271
- lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
266
+ return {
267
+ config,
268
+ state: {
269
+ ...state,
270
+ availableOutputs: [.../* @__PURE__ */ new Set([...state.availableOutputs, ...event.tokens])],
271
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
272
+ }
272
273
  };
273
- break;
274
274
  case "agent-action":
275
- newState = applyAgentAction(state, event.action);
276
- break;
275
+ return { config, state: applyAgentAction(state, event.action) };
276
+ // --- Structural mutations ---
277
+ case "task-upsert":
278
+ return addNode(live, event.taskName, event.taskConfig);
279
+ case "task-removal":
280
+ return removeNode(live, event.taskName);
281
+ case "node-requires-add":
282
+ return addRequires(live, event.nodeName, event.tokens);
283
+ case "node-requires-remove":
284
+ return removeRequires(live, event.nodeName, event.tokens);
285
+ case "node-provides-add":
286
+ return addProvides(live, event.nodeName, event.tokens);
287
+ case "node-provides-remove":
288
+ return removeProvides(live, event.nodeName, event.tokens);
277
289
  default:
278
290
  return live;
279
291
  }
280
- return { config, state: newState };
281
292
  }
282
293
  function applyEvents(live, events) {
283
294
  return events.reduce((current, event) => applyEvent(current, event), live);
284
295
  }
285
296
  function addNode(live, name, taskConfig) {
286
- if (live.config.tasks[name]) return live;
297
+ const exists = !!live.config.tasks[name];
287
298
  return {
288
299
  config: {
289
300
  ...live.config,
@@ -291,7 +302,10 @@ function addNode(live, name, taskConfig) {
291
302
  },
292
303
  state: {
293
304
  ...live.state,
294
- tasks: { ...live.state.tasks, [name]: createDefaultGraphEngineStore2() },
305
+ tasks: {
306
+ ...live.state.tasks,
307
+ [name]: exists ? live.state.tasks[name] : createDefaultGraphEngineStore2()
308
+ },
295
309
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
296
310
  }
297
311
  };
@@ -998,6 +1012,8 @@ function getDownstream(live, nodeName) {
998
1012
  }));
999
1013
  return { nodeName, nodes, tokens: [...tokenSet] };
1000
1014
  }
1015
+
1016
+ // src/continuous-event-graph/journal.ts
1001
1017
  var MemoryJournal = class {
1002
1018
  buffer = [];
1003
1019
  append(event) {
@@ -1012,39 +1028,11 @@ var MemoryJournal = class {
1012
1028
  return this.buffer.length;
1013
1029
  }
1014
1030
  };
1015
- var FileJournal = class {
1016
- constructor(path) {
1017
- this.path = path;
1018
- if (!fs.existsSync(path)) {
1019
- fs.writeFileSync(path, "", "utf-8");
1020
- }
1021
- }
1022
- path;
1023
- pending = 0;
1024
- append(event) {
1025
- fs.appendFileSync(this.path, JSON.stringify(event) + "\n", "utf-8");
1026
- this.pending++;
1027
- }
1028
- drain() {
1029
- const content = fs.readFileSync(this.path, "utf-8").trim();
1030
- fs.writeFileSync(this.path, "", "utf-8");
1031
- this.pending = 0;
1032
- if (!content) return [];
1033
- return content.split("\n").map((line) => JSON.parse(line));
1034
- }
1035
- get size() {
1036
- try {
1037
- const content = fs.readFileSync(this.path, "utf-8").trim();
1038
- if (!content) return 0;
1039
- return content.split("\n").length;
1040
- } catch {
1041
- return this.pending;
1042
- }
1043
- }
1044
- };
1031
+
1032
+ // src/continuous-event-graph/reactive.ts
1045
1033
  function computeDataHash(data) {
1046
1034
  const json = stableStringify(data);
1047
- return crypto.createHash("sha256").update(json).digest("hex").slice(0, 16);
1035
+ return fnv1a64Hex(json);
1048
1036
  }
1049
1037
  function stableStringify(value) {
1050
1038
  if (value === null || value === void 0 || typeof value !== "object") {
@@ -1057,28 +1045,65 @@ function stableStringify(value) {
1057
1045
  const keys = Object.keys(obj).sort();
1058
1046
  return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
1059
1047
  }
1048
+ function fnv1a64Hex(input) {
1049
+ let hash = 0xcbf29ce484222325n;
1050
+ const prime = 0x100000001b3n;
1051
+ const mod = 0xffffffffffffffffn;
1052
+ for (let i = 0; i < input.length; i++) {
1053
+ hash ^= BigInt(input.charCodeAt(i));
1054
+ hash = hash * prime & mod;
1055
+ }
1056
+ return hash.toString(16).padStart(16, "0");
1057
+ }
1058
+ function base64UrlEncode(input) {
1059
+ if (typeof Buffer !== "undefined") {
1060
+ return Buffer.from(input, "utf8").toString("base64url");
1061
+ }
1062
+ if (typeof btoa === "function") {
1063
+ const bytes = new TextEncoder().encode(input);
1064
+ let binary = "";
1065
+ for (const b of bytes) binary += String.fromCharCode(b);
1066
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
1067
+ }
1068
+ throw new Error("No base64 encoder available in this runtime");
1069
+ }
1070
+ function base64UrlDecode(input) {
1071
+ if (typeof Buffer !== "undefined") {
1072
+ return Buffer.from(input, "base64url").toString("utf8");
1073
+ }
1074
+ if (typeof atob === "function") {
1075
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
1076
+ const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
1077
+ const binary = atob(padded);
1078
+ const bytes = new Uint8Array(binary.length);
1079
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
1080
+ return new TextDecoder().decode(bytes);
1081
+ }
1082
+ throw new Error("No base64 decoder available in this runtime");
1083
+ }
1060
1084
  function encodeCallbackToken(taskName) {
1061
1085
  const payload = JSON.stringify({ t: taskName, n: Date.now().toString(36) + Math.random().toString(36).slice(2, 6) });
1062
- return Buffer.from(payload).toString("base64url");
1086
+ return base64UrlEncode(payload);
1063
1087
  }
1064
1088
  function decodeCallbackToken(token) {
1065
1089
  try {
1066
- const payload = JSON.parse(Buffer.from(token, "base64url").toString());
1090
+ const payload = JSON.parse(base64UrlDecode(token));
1067
1091
  if (typeof payload?.t === "string") return { taskName: payload.t };
1068
1092
  return null;
1069
1093
  } catch {
1070
1094
  return null;
1071
1095
  }
1072
1096
  }
1073
- function createReactiveGraph(config, options, executionId) {
1097
+ function createReactiveGraph(configOrLive, options, executionId) {
1074
1098
  const {
1075
1099
  handlers: initialHandlers,
1076
- journal = new MemoryJournal(),
1077
1100
  onDrain
1078
1101
  } = options;
1079
- let live = createLiveGraph(config, executionId);
1102
+ const inputQueue = new MemoryJournal();
1103
+ let live = "state" in configOrLive && "config" in configOrLive ? configOrLive : createLiveGraph(configOrLive, executionId);
1080
1104
  let disposed = false;
1081
1105
  const handlers = new Map(Object.entries(initialHandlers));
1106
+ const internalJournal = new MemoryJournal();
1082
1107
  let draining = false;
1083
1108
  let drainQueued = false;
1084
1109
  function drain() {
@@ -1098,7 +1123,9 @@ function createReactiveGraph(config, options, executionId) {
1098
1123
  }
1099
1124
  }
1100
1125
  function drainOnce() {
1101
- const events = journal.drain();
1126
+ const internalEvents = internalJournal.drain();
1127
+ const inputEvents = inputQueue.drain();
1128
+ const events = [...internalEvents, ...inputEvents];
1102
1129
  if (events.length > 0) {
1103
1130
  live = applyEvents(live, events);
1104
1131
  }
@@ -1109,6 +1136,26 @@ function createReactiveGraph(config, options, executionId) {
1109
1136
  for (const taskName of result.eligible) {
1110
1137
  dispatchTask(taskName);
1111
1138
  }
1139
+ for (const event of events) {
1140
+ if (event.type === "task-progress") {
1141
+ const { taskName, update } = event;
1142
+ const taskConfig = live.config.tasks[taskName];
1143
+ if (!taskConfig) continue;
1144
+ const taskState = live.state.tasks[taskName];
1145
+ if (!taskState || taskState.status !== "running") continue;
1146
+ const callbackToken = encodeCallbackToken(taskName);
1147
+ runPipeline(taskName, callbackToken, update).catch((error) => {
1148
+ if (disposed) return;
1149
+ internalJournal.append({
1150
+ type: "task-failed",
1151
+ taskName,
1152
+ error: error.message ?? String(error),
1153
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1154
+ });
1155
+ drain();
1156
+ });
1157
+ }
1158
+ }
1112
1159
  }
1113
1160
  function resolveUpstreamState(taskName) {
1114
1161
  const taskConfig = live.config.tasks[taskName];
@@ -1130,7 +1177,7 @@ function createReactiveGraph(config, options, executionId) {
1130
1177
  }
1131
1178
  return state;
1132
1179
  }
1133
- async function runPipeline(taskName, callbackToken) {
1180
+ async function runPipeline(taskName, callbackToken, update) {
1134
1181
  const taskConfig = live.config.tasks[taskName];
1135
1182
  const handlerNames = taskConfig.taskHandlers ?? [];
1136
1183
  const upstreamState = resolveUpstreamState(taskName);
@@ -1144,7 +1191,8 @@ function createReactiveGraph(config, options, executionId) {
1144
1191
  state: upstreamState,
1145
1192
  taskState: live.state.tasks[taskName],
1146
1193
  config: taskConfig,
1147
- callbackToken
1194
+ callbackToken,
1195
+ update
1148
1196
  };
1149
1197
  const status = await handler(input);
1150
1198
  if (status === "task-initiate-failure") {
@@ -1158,15 +1206,16 @@ function createReactiveGraph(config, options, executionId) {
1158
1206
  if (!handlerNames || handlerNames.length === 0) {
1159
1207
  return;
1160
1208
  }
1161
- journal.append({
1209
+ internalJournal.append({
1162
1210
  type: "task-started",
1163
1211
  taskName,
1164
1212
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
1165
1213
  });
1214
+ drain();
1166
1215
  const callbackToken = encodeCallbackToken(taskName);
1167
1216
  runPipeline(taskName, callbackToken).catch((error) => {
1168
1217
  if (disposed) return;
1169
- journal.append({
1218
+ internalJournal.append({
1170
1219
  type: "task-failed",
1171
1220
  taskName,
1172
1221
  error: error.message ?? String(error),
@@ -1181,16 +1230,16 @@ function createReactiveGraph(config, options, executionId) {
1181
1230
  if (event.type === "task-completed" && event.data && !event.dataHash) {
1182
1231
  event = { ...event, dataHash: computeDataHash(event.data) };
1183
1232
  }
1184
- journal.append(event);
1233
+ inputQueue.append(event);
1185
1234
  drain();
1186
1235
  },
1187
1236
  pushAll(events) {
1188
1237
  if (disposed) return;
1189
1238
  for (const event of events) {
1190
1239
  if (event.type === "task-completed" && event.data && !event.dataHash) {
1191
- journal.append({ ...event, dataHash: computeDataHash(event.data) });
1240
+ inputQueue.append({ ...event, dataHash: computeDataHash(event.data) });
1192
1241
  } else {
1193
- journal.append(event);
1242
+ inputQueue.append(event);
1194
1243
  }
1195
1244
  }
1196
1245
  drain();
@@ -1202,7 +1251,7 @@ function createReactiveGraph(config, options, executionId) {
1202
1251
  const { taskName } = decoded;
1203
1252
  if (!live.config.tasks[taskName]) return;
1204
1253
  if (errors && errors.length > 0) {
1205
- journal.append({
1254
+ inputQueue.append({
1206
1255
  type: "task-failed",
1207
1256
  taskName,
1208
1257
  error: errors.join("; "),
@@ -1210,7 +1259,7 @@ function createReactiveGraph(config, options, executionId) {
1210
1259
  });
1211
1260
  } else {
1212
1261
  const dataHash = data && Object.keys(data).length > 0 ? computeDataHash(data) : void 0;
1213
- journal.append({
1262
+ inputQueue.append({
1214
1263
  type: "task-completed",
1215
1264
  taskName,
1216
1265
  data,
@@ -1222,31 +1271,33 @@ function createReactiveGraph(config, options, executionId) {
1222
1271
  },
1223
1272
  addNode(name, taskConfig) {
1224
1273
  if (disposed) return;
1225
- live = addNode(live, name, taskConfig);
1274
+ inputQueue.append({ type: "task-upsert", taskName: name, taskConfig, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1226
1275
  drain();
1227
1276
  },
1228
1277
  removeNode(name) {
1229
1278
  if (disposed) return;
1230
- live = removeNode(live, name);
1279
+ inputQueue.append({ type: "task-removal", taskName: name, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1280
+ drain();
1231
1281
  },
1232
1282
  addRequires(nodeName, tokens) {
1233
1283
  if (disposed) return;
1234
- live = addRequires(live, nodeName, tokens);
1284
+ inputQueue.append({ type: "node-requires-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1235
1285
  drain();
1236
1286
  },
1237
1287
  removeRequires(nodeName, tokens) {
1238
1288
  if (disposed) return;
1239
- live = removeRequires(live, nodeName, tokens);
1289
+ inputQueue.append({ type: "node-requires-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1240
1290
  drain();
1241
1291
  },
1242
1292
  addProvides(nodeName, tokens) {
1243
1293
  if (disposed) return;
1244
- live = addProvides(live, nodeName, tokens);
1294
+ inputQueue.append({ type: "node-provides-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1245
1295
  drain();
1246
1296
  },
1247
1297
  removeProvides(nodeName, tokens) {
1248
1298
  if (disposed) return;
1249
- live = removeProvides(live, nodeName, tokens);
1299
+ inputQueue.append({ type: "node-provides-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
1300
+ drain();
1250
1301
  },
1251
1302
  registerHandler(name, fn) {
1252
1303
  handlers.set(name, fn);
@@ -1257,7 +1308,7 @@ function createReactiveGraph(config, options, executionId) {
1257
1308
  retrigger(taskName) {
1258
1309
  if (disposed) return;
1259
1310
  if (!live.config.tasks[taskName]) return;
1260
- journal.append({
1311
+ inputQueue.append({
1261
1312
  type: "task-restart",
1262
1313
  taskName,
1263
1314
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -1268,7 +1319,7 @@ function createReactiveGraph(config, options, executionId) {
1268
1319
  if (disposed) return;
1269
1320
  for (const name of taskNames) {
1270
1321
  if (!live.config.tasks[name]) continue;
1271
- journal.append({
1322
+ inputQueue.append({
1272
1323
  type: "task-restart",
1273
1324
  taskName: name,
1274
1325
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -1276,6 +1327,9 @@ function createReactiveGraph(config, options, executionId) {
1276
1327
  }
1277
1328
  drain();
1278
1329
  },
1330
+ snapshot() {
1331
+ return snapshot(live);
1332
+ },
1279
1333
  getState() {
1280
1334
  return live;
1281
1335
  },
@@ -1659,288 +1713,43 @@ function deepSet(obj, path, value) {
1659
1713
  }
1660
1714
  cur[parts[parts.length - 1]] = value;
1661
1715
  }
1662
- var _fns = {};
1663
- _fns.sum = (input, _e, opts) => {
1664
- const a = Array.isArray(input) ? input : [];
1665
- return opts.field ? a.reduce((s, r) => s + (Number(r[opts.field]) || 0), 0) : a.reduce((s, v) => s + (Number(v) || 0), 0);
1666
- };
1667
- _fns.avg = (input, _e, opts) => {
1668
- const s = _fns.sum(input, _e, opts);
1669
- const n = Array.isArray(input) ? input.length : 1;
1670
- return n ? s / n : 0;
1671
- };
1672
- _fns.min = (input, _e, opts) => {
1673
- const a = Array.isArray(input) ? input : [];
1674
- const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
1675
- return vals.length ? Math.min(...vals) : 0;
1676
- };
1677
- _fns.max = (input, _e, opts) => {
1678
- const a = Array.isArray(input) ? input : [];
1679
- const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
1680
- return vals.length ? Math.max(...vals) : 0;
1681
- };
1682
- _fns.count = (input) => Array.isArray(input) ? input.length : input != null ? 1 : 0;
1683
- _fns.first = (input) => Array.isArray(input) ? input[0] : input;
1684
- _fns.last = (input) => Array.isArray(input) ? input[input.length - 1] : input;
1685
- _fns.add = (input) => {
1686
- const a = Array.isArray(input) ? input : [];
1687
- return a.reduce((s, v) => s + Number(v), 0);
1688
- };
1689
- _fns.sub = (input) => {
1690
- const a = Array.isArray(input) ? input : [];
1691
- return a.length >= 2 ? Number(a[0]) - Number(a[1]) : 0;
1692
- };
1693
- _fns.mul = (input) => {
1694
- const a = Array.isArray(input) ? input : [];
1695
- return a.reduce((s, v) => s * Number(v), 1);
1696
- };
1697
- _fns.div = (input) => {
1698
- const a = Array.isArray(input) ? input : [];
1699
- return a.length >= 2 && Number(a[1]) !== 0 ? Number(a[0]) / Number(a[1]) : 0;
1700
- };
1701
- _fns.round = (input, _e, opts) => {
1702
- const decimals = opts.decimals != null ? opts.decimals : 0;
1703
- const factor = Math.pow(10, decimals);
1704
- return Math.round(Number(input) * factor) / factor;
1705
- };
1706
- _fns.abs = (input) => Math.abs(Number(input));
1707
- _fns.mod = (input) => {
1708
- const a = Array.isArray(input) ? input : [];
1709
- return a.length >= 2 ? Number(a[0]) % Number(a[1]) : 0;
1710
- };
1711
- _fns.gt = (input) => {
1712
- const a = Array.isArray(input) ? input : [];
1713
- return a.length >= 2 && Number(a[0]) > Number(a[1]);
1714
- };
1715
- _fns.gte = (input) => {
1716
- const a = Array.isArray(input) ? input : [];
1717
- return a.length >= 2 && Number(a[0]) >= Number(a[1]);
1718
- };
1719
- _fns.lt = (input) => {
1720
- const a = Array.isArray(input) ? input : [];
1721
- return a.length >= 2 && Number(a[0]) < Number(a[1]);
1722
- };
1723
- _fns.lte = (input) => {
1724
- const a = Array.isArray(input) ? input : [];
1725
- return a.length >= 2 && Number(a[0]) <= Number(a[1]);
1726
- };
1727
- _fns.eq = (input) => {
1728
- const a = Array.isArray(input) ? input : [];
1729
- return a.length >= 2 && a[0] === a[1];
1730
- };
1731
- _fns.neq = (input) => {
1732
- const a = Array.isArray(input) ? input : [];
1733
- return a.length >= 2 && a[0] !== a[1];
1734
- };
1735
- _fns.and = (input) => {
1736
- const a = Array.isArray(input) ? input : [];
1737
- return a.every(Boolean);
1738
- };
1739
- _fns.or = (input) => {
1740
- const a = Array.isArray(input) ? input : [];
1741
- return a.some(Boolean);
1742
- };
1743
- _fns.not = (input) => !input;
1744
- _fns.concat = (input) => {
1745
- const a = Array.isArray(input) ? input : [];
1746
- return a.map((v) => v != null ? String(v) : "").join("");
1747
- };
1748
- _fns.upper = (input) => String(input || "").toUpperCase();
1749
- _fns.lower = (input) => String(input || "").toLowerCase();
1750
- _fns.template = (input, _e, opts) => {
1751
- let t = String(opts.format || "");
1752
- if (input && typeof input === "object" && !Array.isArray(input)) {
1753
- for (const k of Object.keys(input)) {
1754
- const v = input[k];
1755
- t = t.split("{{" + k + "}}").join(v != null ? String(v) : "");
1756
- }
1757
- }
1758
- return t;
1759
- };
1760
- _fns.join = (input, _e, opts) => {
1761
- const a = Array.isArray(input) ? input : [];
1762
- const sep = opts.separator != null ? String(opts.separator) : ", ";
1763
- return a.map((v) => v != null ? String(v) : "").join(sep);
1764
- };
1765
- _fns.split = (input, _e, opts) => {
1766
- const sep = opts.separator != null ? String(opts.separator) : ",";
1767
- return String(input || "").split(sep).map((s) => s.trim());
1768
- };
1769
- _fns.trim = (input) => String(input || "").trim();
1770
- _fns.pluck = (input, _e, opts) => Array.isArray(input) ? input.map((r) => r[opts.field]) : [];
1771
- _fns.filter = (input, _e, opts) => {
1772
- if (!Array.isArray(input)) return [];
1773
- if (opts.field) return input.filter((r) => !!r[opts.field]);
1774
- return input.filter(Boolean);
1775
- };
1776
- _fns.map = (input) => Array.isArray(input) ? input.slice() : [];
1777
- _fns.sort = (input, _e, opts) => {
1778
- const a = Array.isArray(input) ? input.slice() : [];
1779
- const f = opts.field;
1780
- const dir = opts.direction === "desc" ? -1 : 1;
1781
- if (f) return a.sort((x, y) => x[f] > y[f] ? dir : x[f] < y[f] ? -dir : 0);
1782
- return a.sort((x, y) => x > y ? dir : x < y ? -dir : 0);
1783
- };
1784
- _fns.slice = (input, _e, opts) => Array.isArray(input) ? input.slice(opts.start || 0, opts.end) : input;
1785
- _fns.flat = (input, _e, opts) => {
1786
- const depth = opts.depth != null ? opts.depth : 1;
1787
- return Array.isArray(input) ? input.flat(depth) : [input];
1788
- };
1789
- _fns.unique = (input) => {
1790
- if (!Array.isArray(input)) return [input];
1791
- const seen = /* @__PURE__ */ new Set();
1792
- return input.filter((v) => {
1793
- const key = typeof v === "object" ? JSON.stringify(v) : v;
1794
- if (seen.has(key)) return false;
1795
- seen.add(key);
1796
- return true;
1797
- });
1798
- };
1799
- _fns.group = (input, _e, opts) => {
1800
- const a = Array.isArray(input) ? input : [];
1801
- const g = {};
1802
- a.forEach((r) => {
1803
- const k = String(r[opts.field] || "");
1804
- if (!g[k]) g[k] = [];
1805
- g[k].push(r);
1806
- });
1807
- return g;
1808
- };
1809
- _fns.flatten_keys = (input) => {
1810
- if (!input || typeof input !== "object" || Array.isArray(input)) return [];
1811
- const result = [];
1812
- for (const k of Object.keys(input)) {
1813
- const vals = Array.isArray(input[k]) ? input[k] : [input[k]];
1814
- vals.forEach((v) => result.push({ key: k, value: v }));
1815
- }
1816
- return result;
1817
- };
1818
- _fns.entries = (input) => {
1819
- if (!input || typeof input !== "object" || Array.isArray(input)) return [];
1820
- return Object.keys(input).map((k) => ({ key: k, value: input[k] }));
1821
- };
1822
- _fns.from_entries = (input) => {
1823
- if (!Array.isArray(input)) return {};
1824
- const obj = {};
1825
- input.forEach((item) => {
1826
- if (item.key != null) obj[item.key] = item.value;
1827
- });
1828
- return obj;
1829
- };
1830
- _fns.length = (input) => {
1831
- if (Array.isArray(input)) return input.length;
1832
- if (typeof input === "string") return input.length;
1833
- if (input && typeof input === "object") return Object.keys(input).length;
1834
- return 0;
1835
- };
1836
- _fns.get = (input, _e, opts) => deepGet(input, opts.field || opts.path || "");
1837
- _fns.default = (input, _e, opts) => input != null ? input : opts.value;
1838
- _fns.coalesce = (input) => {
1839
- const a = Array.isArray(input) ? input : [];
1840
- for (let i = 0; i < a.length; i++) {
1841
- if (a[i] != null) return a[i];
1842
- }
1843
- return null;
1844
- };
1845
- _fns.now = () => (/* @__PURE__ */ new Date()).toISOString();
1846
- _fns.diff_days = (input) => {
1847
- const a = Array.isArray(input) ? input : [];
1848
- return a.length >= 2 ? Math.floor((new Date(a[0]).getTime() - new Date(a[1]).getTime()) / 864e5) : 0;
1849
- };
1850
- _fns.format_date = (input, _e, opts) => {
1851
- try {
1852
- const d = new Date(input);
1853
- if (opts.format === "iso") return d.toISOString();
1854
- if (opts.format === "date") return d.toLocaleDateString();
1855
- if (opts.format === "time") return d.toLocaleTimeString();
1856
- return d.toLocaleDateString();
1857
- } catch {
1858
- return String(input);
1859
- }
1860
- };
1861
- _fns.parse_date = (input) => {
1862
- try {
1863
- return new Date(input).toISOString();
1864
- } catch {
1865
- return null;
1866
- }
1867
- };
1868
- _fns.to_number = (input) => Number(input) || 0;
1869
- _fns.to_string = (input) => input != null ? String(input) : "";
1870
- _fns.to_bool = (input) => !!input;
1871
- _fns.type_of = (input) => Array.isArray(input) ? "array" : typeof input;
1872
- _fns.is_null = (input) => input == null;
1873
- _fns.is_empty = (input) => {
1874
- if (input == null) return true;
1875
- if (Array.isArray(input)) return input.length === 0;
1876
- if (typeof input === "string") return input.length === 0;
1877
- if (typeof input === "object") return Object.keys(input).length === 0;
1878
- return false;
1879
- };
1880
- var _customFns = {};
1881
- function evalExpr(expr, node) {
1882
- if (expr == null) return expr;
1883
- if (typeof expr !== "object" || Array.isArray(expr)) return expr;
1884
- const e = expr;
1885
- if (!e.fn) return expr;
1886
- let input = e.input;
1887
- if (typeof input === "string" && input.startsWith("state.")) {
1888
- input = deepGet(node, input);
1889
- } else if (Array.isArray(input)) {
1890
- input = input.map((v) => {
1891
- if (typeof v === "string" && v.startsWith("state.")) return deepGet(node, v);
1892
- if (v && typeof v === "object" && v.fn) return evalExpr(v, node);
1893
- return v;
1894
- });
1895
- } else if (input && typeof input === "object" && input.fn) {
1896
- input = evalExpr(input, node);
1897
- }
1898
- if (e.fn === "if") {
1899
- const cond = evalExpr(e.cond, node);
1900
- if (cond) {
1901
- return e.then && typeof e.then === "object" && e.then.fn ? evalExpr(e.then, node) : e.then;
1902
- } else {
1903
- return e.else && typeof e.else === "object" && e.else.fn ? evalExpr(e.else, node) : e.else;
1904
- }
1905
- }
1906
- if (e.fn === "filter" && Array.isArray(input) && e.where) {
1907
- return input.filter((item) => {
1908
- const tmp = { state: { ...node.state, $: item } };
1909
- return evalExpr(e.where, tmp);
1910
- });
1911
- }
1912
- if (e.fn === "map" && Array.isArray(input) && e.apply) {
1913
- return input.map((item) => {
1914
- const tmp = { state: { ...node.state, $: item } };
1915
- return evalExpr(e.apply, tmp);
1916
- });
1917
- }
1918
- const fn = _customFns[e.fn] || _fns[e.fn];
1919
- if (!fn) {
1920
- console.warn('CardCompute: unknown function "' + e.fn + '"');
1921
- return void 0;
1922
- }
1923
- return fn(input, evalExpr, e);
1924
- }
1925
- function run(node) {
1926
- if (!node || !node.compute) return node;
1927
- if (!node.state) node.state = {};
1928
- for (const key of Object.keys(node.compute)) {
1716
+ async function run(node, options) {
1717
+ if (!node?.compute?.length) return node;
1718
+ if (!node.card_data) node.card_data = {};
1719
+ node.computed_values = {};
1720
+ node._sourcesData = options?.sourcesData ?? {};
1721
+ const ctx = {
1722
+ card_data: node.card_data,
1723
+ requires: node.requires ?? {},
1724
+ fetched_sources: node._sourcesData,
1725
+ computed_values: node.computed_values
1726
+ };
1727
+ for (const step of node.compute) {
1929
1728
  try {
1930
- const val = evalExpr(node.compute[key], node);
1931
- deepSet(node.state, key, val);
1729
+ const val = await jsonata2__default.default(step.expr).evaluate(ctx);
1730
+ deepSet(node.computed_values, step.bindTo, val);
1731
+ ctx.computed_values = node.computed_values;
1932
1732
  } catch (err) {
1933
- console.error(`CardCompute.run error on "${node.id || "?"}.${key}":`, err);
1733
+ console.error(`CardCompute.run error on "${node.id ?? "?"}.${step.bindTo}":`, err);
1934
1734
  }
1935
1735
  }
1936
1736
  return node;
1937
1737
  }
1738
+ async function evalExpr(expr, node) {
1739
+ const ctx = {
1740
+ card_data: node.card_data ?? {},
1741
+ requires: node.requires ?? {},
1742
+ fetched_sources: node._sourcesData ?? {},
1743
+ computed_values: node.computed_values ?? {}
1744
+ };
1745
+ return jsonata2__default.default(expr).evaluate(ctx);
1746
+ }
1938
1747
  function resolve(node, path) {
1748
+ if (path.startsWith("fetched_sources.")) {
1749
+ return deepGet(node._sourcesData ?? {}, path.slice("fetched_sources.".length));
1750
+ }
1939
1751
  return deepGet(node, path);
1940
1752
  }
1941
- function registerFunction(name, fn) {
1942
- _customFns[name] = fn;
1943
- }
1944
1753
  var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
1945
1754
  "metric",
1946
1755
  "table",
@@ -1957,34 +1766,19 @@ var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
1957
1766
  "markdown",
1958
1767
  "custom"
1959
1768
  ]);
1960
- var VALID_SOURCE_KINDS = /* @__PURE__ */ new Set(["api", "websocket", "static", "llm"]);
1961
- var VALID_STATUSES = /* @__PURE__ */ new Set(["fresh", "stale", "loading", "error"]);
1962
- var CARD_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "view", "state", "compute"]);
1963
- var SOURCE_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "source", "state", "compute"]);
1769
+ var ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "meta", "requires", "provides", "view", "card_data", "compute", "sources"]);
1964
1770
  function validateNode(node) {
1965
1771
  const errors = [];
1966
1772
  if (!node || typeof node !== "object" || Array.isArray(node)) {
1967
1773
  return { ok: false, errors: ["Node must be a non-null object"] };
1968
1774
  }
1969
1775
  const n = node;
1970
- if (typeof n.id !== "string" || !n.id) {
1971
- errors.push("id: required, must be a non-empty string");
1972
- }
1973
- if (n.type !== "card" && n.type !== "source") {
1974
- errors.push('type: must be "card" or "source"');
1975
- return { ok: false, errors };
1976
- }
1977
- const allowed = n.type === "card" ? CARD_ALLOWED_KEYS : SOURCE_ALLOWED_KEYS;
1776
+ if (typeof n.id !== "string" || !n.id) errors.push("id: required, must be a non-empty string");
1978
1777
  for (const key of Object.keys(n)) {
1979
- if (!allowed.has(key)) errors.push(`Unknown top-level key: "${key}"`);
1778
+ if (!ALLOWED_KEYS.has(key)) errors.push(`Unknown top-level key: "${key}"`);
1980
1779
  }
1981
- if (n.state == null || typeof n.state !== "object" || Array.isArray(n.state)) {
1982
- errors.push("state: required, must be an object");
1983
- } else {
1984
- const state = n.state;
1985
- if (state.status != null && !VALID_STATUSES.has(state.status)) {
1986
- errors.push(`state.status: must be one of: ${[...VALID_STATUSES].join(", ")}`);
1987
- }
1780
+ if (n.card_data == null || typeof n.card_data !== "object" || Array.isArray(n.card_data)) {
1781
+ errors.push("card_data: required, must be an object");
1988
1782
  }
1989
1783
  if (n.meta != null) {
1990
1784
  if (typeof n.meta !== "object" || Array.isArray(n.meta)) {
@@ -1995,37 +1789,58 @@ function validateNode(node) {
1995
1789
  if (meta.tags != null && !Array.isArray(meta.tags)) errors.push("meta.tags: must be an array");
1996
1790
  }
1997
1791
  }
1998
- if (n.data != null) {
1999
- if (typeof n.data !== "object" || Array.isArray(n.data)) {
2000
- errors.push("data: must be an object");
1792
+ if (n.requires != null && !Array.isArray(n.requires)) errors.push("requires: must be an array of strings");
1793
+ if (n.provides != null) {
1794
+ if (!Array.isArray(n.provides)) {
1795
+ errors.push("provides: must be an array of { bindTo, src } bindings");
2001
1796
  } else {
2002
- const data = n.data;
2003
- if (data.requires != null && !Array.isArray(data.requires)) errors.push("data.requires: must be an array of strings");
2004
- if (data.provides != null && (typeof data.provides !== "object" || Array.isArray(data.provides))) errors.push("data.provides: must be an object");
1797
+ n.provides.forEach((p, i) => {
1798
+ if (!p || typeof p !== "object" || Array.isArray(p)) {
1799
+ errors.push(`provides[${i}]: must be an object with bindTo and src`);
1800
+ } else {
1801
+ const b = p;
1802
+ if (typeof b.bindTo !== "string" || !b.bindTo) errors.push(`provides[${i}]: missing required "bindTo" string`);
1803
+ if (typeof b.src !== "string" || !b.src) errors.push(`provides[${i}]: missing required "src" string`);
1804
+ }
1805
+ });
2005
1806
  }
2006
1807
  }
2007
1808
  if (n.compute != null) {
2008
- if (typeof n.compute !== "object" || Array.isArray(n.compute)) {
2009
- errors.push("compute: must be an object");
1809
+ if (!Array.isArray(n.compute)) {
1810
+ errors.push("compute: must be an array of compute steps");
1811
+ } else {
1812
+ n.compute.forEach((step, i) => {
1813
+ if (!step || typeof step !== "object" || Array.isArray(step)) {
1814
+ errors.push(`compute[${i}]: must be a compute step object`);
1815
+ } else {
1816
+ const s = step;
1817
+ if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`compute[${i}]: missing required "bindTo" property`);
1818
+ if (typeof s.expr !== "string" || !s.expr) errors.push(`compute[${i}]: missing required "expr" string (JSONata expression)`);
1819
+ }
1820
+ });
1821
+ }
1822
+ }
1823
+ if (n.sources != null) {
1824
+ if (!Array.isArray(n.sources)) {
1825
+ errors.push("sources: must be an array");
2010
1826
  } else {
2011
- for (const [key, expr] of Object.entries(n.compute)) {
2012
- if (!expr || typeof expr !== "object" || Array.isArray(expr)) {
2013
- errors.push(`compute.${key}: must be a compute expression object`);
2014
- } else if (!expr.fn) {
2015
- errors.push(`compute.${key}: missing required "fn" property`);
1827
+ n.sources.forEach((src, i) => {
1828
+ if (!src || typeof src !== "object" || Array.isArray(src)) {
1829
+ errors.push(`sources[${i}]: must be an object`);
2016
1830
  } else {
2017
- const fn = expr.fn;
2018
- if (!_fns[fn] && !_customFns[fn]) {
2019
- errors.push(`compute.${key}: unknown function "${fn}"`);
1831
+ const s = src;
1832
+ if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`sources[${i}]: missing required "bindTo" property`);
1833
+ if (s.outputFile != null && typeof s.outputFile !== "string") errors.push(`sources[${i}]: outputFile must be a string`);
1834
+ if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
1835
+ errors.push(`sources[${i}]: optionalForCompletionGating must be a boolean`);
2020
1836
  }
2021
1837
  }
2022
- }
1838
+ });
2023
1839
  }
2024
1840
  }
2025
- if (n.type === "card") {
2026
- if (n.source != null) errors.push('Card nodes must not have "source" \u2014 use type "source" instead');
2027
- if (n.view == null || typeof n.view !== "object" || Array.isArray(n.view)) {
2028
- errors.push("view: required for card nodes, must be an object");
1841
+ if (n.view != null) {
1842
+ if (typeof n.view !== "object" || Array.isArray(n.view)) {
1843
+ errors.push("view: must be an object");
2029
1844
  } else {
2030
1845
  const view = n.view;
2031
1846
  if (!Array.isArray(view.elements) || view.elements.length === 0) {
@@ -2046,44 +1861,27 @@ function validateNode(node) {
2046
1861
  }
2047
1862
  });
2048
1863
  }
2049
- if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout))) {
2050
- errors.push("view.layout: must be an object");
2051
- }
2052
- if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) {
2053
- errors.push("view.features: must be an object");
2054
- }
2055
- }
2056
- }
2057
- if (n.type === "source") {
2058
- if (n.view != null) errors.push('Source nodes must not have "view" \u2014 use type "card" instead');
2059
- if (n.source == null || typeof n.source !== "object" || Array.isArray(n.source)) {
2060
- errors.push("source: required for source nodes, must be an object");
2061
- } else {
2062
- const src = n.source;
2063
- if (!src.kind || !VALID_SOURCE_KINDS.has(src.kind)) {
2064
- errors.push(`source.kind: required, must be one of: ${[...VALID_SOURCE_KINDS].join(", ")}`);
2065
- }
2066
- if (typeof src.bindTo !== "string" || !src.bindTo) {
2067
- errors.push("source.bindTo: required, must be a state path string");
2068
- } else if (!src.bindTo.startsWith("state.")) {
2069
- errors.push('source.bindTo: must start with "state."');
2070
- }
1864
+ if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout))) errors.push("view.layout: must be an object");
1865
+ if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) errors.push("view.features: must be an object");
2071
1866
  }
2072
1867
  }
2073
1868
  return { ok: errors.length === 0, errors };
2074
1869
  }
1870
+ function enrichSources(sources, context) {
1871
+ if (!sources || sources.length === 0) return [];
1872
+ return sources.map((src) => ({
1873
+ ...src,
1874
+ _requires: context.requires ?? {},
1875
+ _sourcesData: context.sourcesData ?? {},
1876
+ _computed_values: context.computed_values ?? {}
1877
+ }));
1878
+ }
2075
1879
  var CardCompute = {
2076
1880
  run,
2077
1881
  eval: evalExpr,
2078
1882
  resolve,
2079
1883
  validate: validateNode,
2080
- registerFunction,
2081
- get functions() {
2082
- const all = {};
2083
- for (const k of Object.keys(_fns)) all[k] = _fns[k];
2084
- for (const k of Object.keys(_customFns)) all[k] = _customFns[k];
2085
- return all;
2086
- }
1884
+ enrichSources
2087
1885
  };
2088
1886
 
2089
1887
  // src/continuous-event-graph/live-cards-bridge.ts
@@ -2116,19 +1914,26 @@ function liveCardsToReactiveGraph(input, options = {}) {
2116
1914
  }
2117
1915
  const sharedState = options.sharedState ?? /* @__PURE__ */ new Map();
2118
1916
  const tasks = {};
1917
+ const allTokens = /* @__PURE__ */ new Set();
1918
+ const tokenToCardId = /* @__PURE__ */ new Map();
1919
+ for (const card of cards) {
1920
+ for (const binding of card.provides ?? [{ bindTo: card.id, src: "card_data" }]) {
1921
+ allTokens.add(binding.bindTo);
1922
+ tokenToCardId.set(binding.bindTo, card.id);
1923
+ }
1924
+ }
2119
1925
  for (const card of cards) {
2120
- const requires = card.data?.requires ?? [];
1926
+ const requires = card.requires ?? [];
2121
1927
  for (const req of requires) {
2122
- if (!cardMap.has(req)) {
2123
- throw new Error(`Card "${card.id}" requires "${req}" but no card with that ID exists`);
1928
+ if (!allTokens.has(req)) {
1929
+ throw new Error(`Card "${card.id}" requires "${req}" but no card provides that token`);
2124
1930
  }
2125
1931
  }
2126
1932
  tasks[card.id] = {
2127
1933
  requires: requires.length > 0 ? requires : void 0,
2128
- provides: [card.id],
1934
+ provides: (card.provides ?? [{ bindTo: card.id, src: "card_data" }]).map((p) => p.bindTo),
2129
1935
  taskHandlers: [card.id],
2130
- // each card has a named handler matching its ID
2131
- description: card.meta?.title ?? `${card.type}: ${card.id}`
1936
+ description: card.meta?.title ?? card.id
2132
1937
  };
2133
1938
  }
2134
1939
  const config = {
@@ -2147,10 +1952,10 @@ function liveCardsToReactiveGraph(input, options = {}) {
2147
1952
  graphRef.resolveCallback(token, data, errors);
2148
1953
  };
2149
1954
  for (const card of cards) {
2150
- if (card.type === "source") {
1955
+ if (card.sources && card.sources.length > 0) {
2151
1956
  handlers[card.id] = buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedState, getResolve);
2152
1957
  } else {
2153
- handlers[card.id] = buildCardHandler(card, cardHandlers, sharedState, cardMap, getResolve);
1958
+ handlers[card.id] = buildCardHandler(card, cardHandlers, sharedState, cardMap, tokenToCardId, getResolve);
2154
1959
  }
2155
1960
  }
2156
1961
  const graph = createReactiveGraph(
@@ -2178,13 +1983,13 @@ function buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedSt
2178
1983
  };
2179
1984
  }
2180
1985
  return async (input) => {
2181
- const state = { ...card.state };
2182
- sharedState.set(card.id, state);
2183
- getResolve()(input.callbackToken, state);
1986
+ const data = { ...card.card_data };
1987
+ sharedState.set(card.id, data);
1988
+ getResolve()(input.callbackToken, data);
2184
1989
  return "task-initiated";
2185
1990
  };
2186
1991
  }
2187
- function buildCardHandler(card, cardHandlers, sharedState, cardMap, getResolve) {
1992
+ function buildCardHandler(card, cardHandlers, sharedState, _cardMap, tokenToCardId, getResolve) {
2188
1993
  if (cardHandlers[card.id]) {
2189
1994
  const userHandler = cardHandlers[card.id];
2190
1995
  return async (input) => {
@@ -2192,49 +1997,38 @@ function buildCardHandler(card, cardHandlers, sharedState, cardMap, getResolve)
2192
1997
  };
2193
1998
  }
2194
1999
  return async (input) => {
2000
+ const requiresData = {};
2001
+ const requires = card.requires ?? [];
2002
+ for (const token of requires) {
2003
+ const producerId = tokenToCardId.get(token) ?? token;
2004
+ const upstreamState = sharedState.get(producerId);
2005
+ if (upstreamState) {
2006
+ requiresData[token] = upstreamState[token] ?? upstreamState;
2007
+ }
2008
+ }
2195
2009
  const computeNode = {
2196
2010
  id: card.id,
2197
- state: { ...card.state },
2011
+ card_data: { ...card.card_data },
2012
+ requires: requiresData,
2198
2013
  compute: card.compute
2199
2014
  };
2200
- const requires = card.data?.requires ?? [];
2201
- for (const upstreamId of requires) {
2202
- const upstreamState = sharedState.get(upstreamId);
2203
- if (upstreamState) {
2204
- computeNode.state[upstreamId] = upstreamState;
2205
- }
2206
- const upstreamCard = cardMap.get(upstreamId);
2207
- if (upstreamCard?.data?.provides && upstreamState) {
2208
- for (const [key, bindRef] of Object.entries(upstreamCard.data.provides)) {
2209
- if (typeof bindRef === "string" && bindRef.startsWith("state.")) {
2210
- const path = bindRef.slice(6);
2211
- const value = deepGet2(upstreamState, path);
2212
- if (value !== void 0) {
2213
- computeNode.state[key] = value;
2214
- }
2215
- }
2216
- }
2015
+ await CardCompute.run(computeNode);
2016
+ let resultData;
2017
+ if (card.provides && card.provides.length > 0) {
2018
+ resultData = {};
2019
+ for (const { bindTo, src } of card.provides) {
2020
+ resultData[bindTo] = CardCompute.resolve(computeNode, src);
2217
2021
  }
2022
+ } else {
2023
+ resultData = { ...computeNode.card_data, ...computeNode.computed_values };
2218
2024
  }
2219
- CardCompute.run(computeNode);
2220
- const resultState = { ...computeNode.state };
2025
+ const resultState = { ...computeNode.card_data, ...computeNode.computed_values };
2221
2026
  sharedState.set(card.id, resultState);
2222
- getResolve()(input.callbackToken, resultState);
2027
+ getResolve()(input.callbackToken, resultData);
2223
2028
  return "task-initiated";
2224
2029
  };
2225
2030
  }
2226
- function deepGet2(obj, path) {
2227
- if (!path || !obj) return void 0;
2228
- const parts = path.split(".");
2229
- let cur = obj;
2230
- for (const part of parts) {
2231
- if (cur == null) return void 0;
2232
- cur = cur[part];
2233
- }
2234
- return cur;
2235
- }
2236
2031
 
2237
- exports.FileJournal = FileJournal;
2238
2032
  exports.MemoryJournal = MemoryJournal;
2239
2033
  exports.addNode = addNode;
2240
2034
  exports.addProvides = addProvides;