yaml-flow 3.1.0 → 4.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.
- package/README.md +81 -20
- package/board-live-cards-cli.js +37 -0
- package/browser/card-compute.js +132 -431
- package/browser/live-cards.js +41 -27
- package/browser/live-cards.schema.json +59 -77
- package/dist/card-compute/index.cjs +135 -415
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.d.cts +52 -49
- package/dist/card-compute/index.d.ts +52 -49
- package/dist/card-compute/index.js +134 -415
- package/dist/card-compute/index.js.map +1 -1
- package/dist/cli/board-live-cards-cli.cjs +2379 -0
- package/dist/cli/board-live-cards-cli.cjs.map +1 -0
- package/dist/cli/board-live-cards-cli.d.cts +213 -0
- package/dist/cli/board-live-cards-cli.d.ts +213 -0
- package/dist/cli/board-live-cards-cli.js +2332 -0
- package/dist/cli/board-live-cards-cli.js.map +1 -0
- package/dist/{constants-B2zqu10b.d.ts → constants-DuzE5n03.d.ts} +2 -2
- package/dist/{constants-DJZU1pwJ.d.cts → constants-ozjf1Ejw.d.cts} +2 -2
- package/dist/continuous-event-graph/index.cjs +201 -448
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.d.cts +16 -340
- package/dist/continuous-event-graph/index.d.ts +16 -340
- package/dist/continuous-event-graph/index.js +198 -448
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/event-graph/index.cjs +4 -4
- package/dist/event-graph/index.cjs.map +1 -1
- package/dist/event-graph/index.d.cts +5 -5
- package/dist/event-graph/index.d.ts +5 -5
- package/dist/event-graph/index.js +4 -4
- package/dist/event-graph/index.js.map +1 -1
- package/dist/index.cjs +278 -533
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +278 -533
- package/dist/index.js.map +1 -1
- package/dist/inference/index.cjs +138 -19
- package/dist/inference/index.cjs.map +1 -1
- package/dist/inference/index.d.cts +2 -2
- package/dist/inference/index.d.ts +2 -2
- package/dist/inference/index.js +138 -19
- package/dist/inference/index.js.map +1 -1
- package/dist/journal-BJDjWb5Q.d.cts +343 -0
- package/dist/journal-B_2JnBMF.d.ts +343 -0
- package/dist/step-machine/index.cjs +18 -1
- package/dist/step-machine/index.cjs.map +1 -1
- package/dist/step-machine/index.d.cts +2 -2
- package/dist/step-machine/index.d.ts +2 -2
- package/dist/step-machine/index.js +18 -1
- package/dist/step-machine/index.js.map +1 -1
- package/dist/stores/file.d.cts +1 -1
- package/dist/stores/file.d.ts +1 -1
- package/dist/stores/index.d.cts +1 -1
- package/dist/stores/index.d.ts +1 -1
- package/dist/stores/localStorage.d.cts +1 -1
- package/dist/stores/localStorage.d.ts +1 -1
- package/dist/stores/memory.d.cts +1 -1
- package/dist/stores/memory.d.ts +1 -1
- package/dist/{types-BwvgvlOO.d.cts → types-BzLD8bjb.d.cts} +1 -1
- package/dist/{types-ClRA8hzC.d.ts → types-C2eJ7DAV.d.ts} +1 -1
- package/dist/{types-DEj7OakX.d.cts → types-CMFSIjpc.d.cts} +39 -4
- package/dist/{types-DEj7OakX.d.ts → types-CMFSIjpc.d.ts} +39 -4
- package/dist/{types-FZ_eyErS.d.cts → types-ycun84cq.d.cts} +1 -0
- package/dist/{types-FZ_eyErS.d.ts → types-ycun84cq.d.ts} +1 -0
- package/dist/{validate-DEZ2Ymdb.d.ts → validate-DJQTQ6bP.d.ts} +1 -1
- package/dist/{validate-DqKTZg_o.d.cts → validate-ke92Cleg.d.cts} +1 -1
- package/examples/browser/boards/portfolio-tracker/cards/holdings-table.json +22 -0
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-form.json +16 -0
- package/examples/browser/boards/portfolio-tracker/cards/portfolio-value.json +15 -0
- package/examples/browser/boards/portfolio-tracker/cards/price-fetch.json +15 -0
- package/examples/browser/boards/portfolio-tracker/fetch-prices.js +43 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +7 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +189 -0
- package/examples/browser/livecards-browser/index.html +688 -0
- package/examples/browser/step-machine-browser/index.html +367 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
- package/examples/cli/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
- package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +36 -0
- package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +30 -0
- package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +19 -0
- package/examples/cli/step-machine-demo/step-cli-echo-y.js +15 -0
- package/examples/cli/step-machine-demo/step2-double-cli.js +39 -0
- package/examples/cli/step-machine-demo/two-step-math-handlers.js +32 -0
- package/examples/cli/step-machine-demo/two-step-math.flow.yaml +31 -0
- package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +24 -0
- package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +35 -0
- package/examples/index.html +792 -0
- package/examples/ingest.js +733 -0
- package/examples/npm-libs/batch/batch-step-machine.ts +121 -0
- package/examples/npm-libs/continuous-event-graph/live-cards-board.ts +215 -0
- package/examples/npm-libs/continuous-event-graph/live-portfolio-dashboard.ts +555 -0
- package/examples/npm-libs/continuous-event-graph/portfolio-tracker.ts +287 -0
- package/examples/npm-libs/continuous-event-graph/reactive-monitoring.ts +265 -0
- package/examples/npm-libs/continuous-event-graph/reactive-pipeline.ts +168 -0
- package/examples/npm-libs/continuous-event-graph/soc-incident-board.ts +287 -0
- package/examples/npm-libs/continuous-event-graph/stock-dashboard.ts +229 -0
- package/examples/npm-libs/event-graph/ci-cd-pipeline.ts +243 -0
- package/examples/npm-libs/event-graph/executor-diamond.ts +165 -0
- package/examples/npm-libs/event-graph/executor-pipeline.ts +161 -0
- package/examples/npm-libs/event-graph/research-pipeline.ts +137 -0
- package/examples/npm-libs/flows/ai-conversation.yaml +116 -0
- package/examples/npm-libs/flows/order-processing.yaml +143 -0
- package/examples/npm-libs/flows/simple-greeting.yaml +54 -0
- package/examples/npm-libs/graph-of-graphs/multi-stage-etl.ts +307 -0
- package/examples/npm-libs/graph-of-graphs/url-processing-pipeline.ts +254 -0
- package/examples/npm-libs/inference/azure-deployment.ts +149 -0
- package/examples/npm-libs/inference/copilot-cli.ts +138 -0
- package/examples/npm-libs/inference/data-pipeline.ts +145 -0
- package/examples/npm-libs/inference/pluggable-adapters.ts +254 -0
- package/examples/npm-libs/node/ai-conversation.ts +195 -0
- package/examples/npm-libs/node/simple-greeting.ts +101 -0
- package/examples/step-machine-cli/portfolio-tracker/cards/holdings-table.json +22 -0
- package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-form.json +43 -0
- package/examples/step-machine-cli/portfolio-tracker/cards/portfolio-value.json +15 -0
- package/examples/step-machine-cli/portfolio-tracker/cards/price-fetch.json +15 -0
- package/examples/step-machine-cli/portfolio-tracker/fetch-prices.js +48 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +58 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +27 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +25 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +29 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +27 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/status-cli.js +25 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +37 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +53 -0
- package/examples/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +35 -0
- package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +227 -0
- package/examples/step-machine-cli/portfolio-tracker/portfolio-tracker.input.json +38 -0
- package/examples/step-machine-cli/portfolio-tracker/run-portfolio-tracker.bat +29 -0
- package/package.json +14 -2
- package/schema/board-status.schema.json +118 -0
- package/schema/flow.schema.json +5 -0
- package/schema/live-cards.schema.json +59 -77
- package/step-machine-cli.js +674 -0
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fs = require('fs');
|
|
4
3
|
var crypto = require('crypto');
|
|
5
4
|
var child_process = require('child_process');
|
|
5
|
+
var jsonata = require('jsonata');
|
|
6
6
|
require('ajv-formats');
|
|
7
7
|
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var jsonata__default = /*#__PURE__*/_interopDefault(jsonata);
|
|
11
|
+
|
|
8
12
|
// src/event-graph/constants.ts
|
|
9
13
|
var TASK_STATUS = {
|
|
10
14
|
NOT_STARTED: "not-started",
|
|
@@ -247,43 +251,51 @@ function applyEvent(live, event) {
|
|
|
247
251
|
if ("executionId" in event && event.executionId && event.executionId !== state.executionId) {
|
|
248
252
|
return live;
|
|
249
253
|
}
|
|
250
|
-
let newState;
|
|
251
254
|
switch (event.type) {
|
|
255
|
+
// --- Execution state transitions ---
|
|
252
256
|
case "task-started":
|
|
253
|
-
|
|
254
|
-
break;
|
|
257
|
+
return { config, state: applyTaskStart(state, event.taskName) };
|
|
255
258
|
case "task-completed":
|
|
256
|
-
|
|
257
|
-
break;
|
|
259
|
+
return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };
|
|
258
260
|
case "task-failed":
|
|
259
|
-
|
|
260
|
-
break;
|
|
261
|
+
return { config, state: applyTaskFailure(state, config, event.taskName, event.error) };
|
|
261
262
|
case "task-progress":
|
|
262
|
-
|
|
263
|
-
break;
|
|
263
|
+
return { config, state: applyTaskProgress(state, event.taskName, event.message, event.progress) };
|
|
264
264
|
case "task-restart":
|
|
265
|
-
|
|
266
|
-
break;
|
|
265
|
+
return { config, state: applyTaskRestart(state, event.taskName) };
|
|
267
266
|
case "inject-tokens":
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
267
|
+
return {
|
|
268
|
+
config,
|
|
269
|
+
state: {
|
|
270
|
+
...state,
|
|
271
|
+
availableOutputs: [.../* @__PURE__ */ new Set([...state.availableOutputs, ...event.tokens])],
|
|
272
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
273
|
+
}
|
|
272
274
|
};
|
|
273
|
-
break;
|
|
274
275
|
case "agent-action":
|
|
275
|
-
|
|
276
|
-
|
|
276
|
+
return { config, state: applyAgentAction(state, event.action) };
|
|
277
|
+
// --- Structural mutations ---
|
|
278
|
+
case "task-upsert":
|
|
279
|
+
return addNode(live, event.taskName, event.taskConfig);
|
|
280
|
+
case "task-removal":
|
|
281
|
+
return removeNode(live, event.taskName);
|
|
282
|
+
case "node-requires-add":
|
|
283
|
+
return addRequires(live, event.nodeName, event.tokens);
|
|
284
|
+
case "node-requires-remove":
|
|
285
|
+
return removeRequires(live, event.nodeName, event.tokens);
|
|
286
|
+
case "node-provides-add":
|
|
287
|
+
return addProvides(live, event.nodeName, event.tokens);
|
|
288
|
+
case "node-provides-remove":
|
|
289
|
+
return removeProvides(live, event.nodeName, event.tokens);
|
|
277
290
|
default:
|
|
278
291
|
return live;
|
|
279
292
|
}
|
|
280
|
-
return { config, state: newState };
|
|
281
293
|
}
|
|
282
294
|
function applyEvents(live, events) {
|
|
283
295
|
return events.reduce((current, event) => applyEvent(current, event), live);
|
|
284
296
|
}
|
|
285
297
|
function addNode(live, name, taskConfig) {
|
|
286
|
-
|
|
298
|
+
const exists = !!live.config.tasks[name];
|
|
287
299
|
return {
|
|
288
300
|
config: {
|
|
289
301
|
...live.config,
|
|
@@ -291,7 +303,10 @@ function addNode(live, name, taskConfig) {
|
|
|
291
303
|
},
|
|
292
304
|
state: {
|
|
293
305
|
...live.state,
|
|
294
|
-
tasks: {
|
|
306
|
+
tasks: {
|
|
307
|
+
...live.state.tasks,
|
|
308
|
+
[name]: exists ? live.state.tasks[name] : createDefaultGraphEngineStore2()
|
|
309
|
+
},
|
|
295
310
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
296
311
|
}
|
|
297
312
|
};
|
|
@@ -998,6 +1013,8 @@ function getDownstream(live, nodeName) {
|
|
|
998
1013
|
}));
|
|
999
1014
|
return { nodeName, nodes, tokens: [...tokenSet] };
|
|
1000
1015
|
}
|
|
1016
|
+
|
|
1017
|
+
// src/continuous-event-graph/journal.ts
|
|
1001
1018
|
var MemoryJournal = class {
|
|
1002
1019
|
buffer = [];
|
|
1003
1020
|
append(event) {
|
|
@@ -1012,36 +1029,6 @@ var MemoryJournal = class {
|
|
|
1012
1029
|
return this.buffer.length;
|
|
1013
1030
|
}
|
|
1014
1031
|
};
|
|
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
|
-
};
|
|
1045
1032
|
function computeDataHash(data) {
|
|
1046
1033
|
const json = stableStringify(data);
|
|
1047
1034
|
return crypto.createHash("sha256").update(json).digest("hex").slice(0, 16);
|
|
@@ -1070,15 +1057,16 @@ function decodeCallbackToken(token) {
|
|
|
1070
1057
|
return null;
|
|
1071
1058
|
}
|
|
1072
1059
|
}
|
|
1073
|
-
function createReactiveGraph(
|
|
1060
|
+
function createReactiveGraph(configOrLive, options, executionId) {
|
|
1074
1061
|
const {
|
|
1075
1062
|
handlers: initialHandlers,
|
|
1076
|
-
journal = new MemoryJournal(),
|
|
1077
1063
|
onDrain
|
|
1078
1064
|
} = options;
|
|
1079
|
-
|
|
1065
|
+
const inputQueue = new MemoryJournal();
|
|
1066
|
+
let live = "state" in configOrLive && "config" in configOrLive ? configOrLive : createLiveGraph(configOrLive, executionId);
|
|
1080
1067
|
let disposed = false;
|
|
1081
1068
|
const handlers = new Map(Object.entries(initialHandlers));
|
|
1069
|
+
const internalJournal = new MemoryJournal();
|
|
1082
1070
|
let draining = false;
|
|
1083
1071
|
let drainQueued = false;
|
|
1084
1072
|
function drain() {
|
|
@@ -1098,7 +1086,9 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1098
1086
|
}
|
|
1099
1087
|
}
|
|
1100
1088
|
function drainOnce() {
|
|
1101
|
-
const
|
|
1089
|
+
const internalEvents = internalJournal.drain();
|
|
1090
|
+
const inputEvents = inputQueue.drain();
|
|
1091
|
+
const events = [...internalEvents, ...inputEvents];
|
|
1102
1092
|
if (events.length > 0) {
|
|
1103
1093
|
live = applyEvents(live, events);
|
|
1104
1094
|
}
|
|
@@ -1109,6 +1099,26 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1109
1099
|
for (const taskName of result.eligible) {
|
|
1110
1100
|
dispatchTask(taskName);
|
|
1111
1101
|
}
|
|
1102
|
+
for (const event of events) {
|
|
1103
|
+
if (event.type === "task-progress") {
|
|
1104
|
+
const { taskName, update } = event;
|
|
1105
|
+
const taskConfig = live.config.tasks[taskName];
|
|
1106
|
+
if (!taskConfig) continue;
|
|
1107
|
+
const taskState = live.state.tasks[taskName];
|
|
1108
|
+
if (!taskState || taskState.status !== "running") continue;
|
|
1109
|
+
const callbackToken = encodeCallbackToken(taskName);
|
|
1110
|
+
runPipeline(taskName, callbackToken, update).catch((error) => {
|
|
1111
|
+
if (disposed) return;
|
|
1112
|
+
internalJournal.append({
|
|
1113
|
+
type: "task-failed",
|
|
1114
|
+
taskName,
|
|
1115
|
+
error: error.message ?? String(error),
|
|
1116
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1117
|
+
});
|
|
1118
|
+
drain();
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1112
1122
|
}
|
|
1113
1123
|
function resolveUpstreamState(taskName) {
|
|
1114
1124
|
const taskConfig = live.config.tasks[taskName];
|
|
@@ -1130,7 +1140,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1130
1140
|
}
|
|
1131
1141
|
return state;
|
|
1132
1142
|
}
|
|
1133
|
-
async function runPipeline(taskName, callbackToken) {
|
|
1143
|
+
async function runPipeline(taskName, callbackToken, update) {
|
|
1134
1144
|
const taskConfig = live.config.tasks[taskName];
|
|
1135
1145
|
const handlerNames = taskConfig.taskHandlers ?? [];
|
|
1136
1146
|
const upstreamState = resolveUpstreamState(taskName);
|
|
@@ -1144,7 +1154,8 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1144
1154
|
state: upstreamState,
|
|
1145
1155
|
taskState: live.state.tasks[taskName],
|
|
1146
1156
|
config: taskConfig,
|
|
1147
|
-
callbackToken
|
|
1157
|
+
callbackToken,
|
|
1158
|
+
update
|
|
1148
1159
|
};
|
|
1149
1160
|
const status = await handler(input);
|
|
1150
1161
|
if (status === "task-initiate-failure") {
|
|
@@ -1158,15 +1169,16 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1158
1169
|
if (!handlerNames || handlerNames.length === 0) {
|
|
1159
1170
|
return;
|
|
1160
1171
|
}
|
|
1161
|
-
|
|
1172
|
+
internalJournal.append({
|
|
1162
1173
|
type: "task-started",
|
|
1163
1174
|
taskName,
|
|
1164
1175
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1165
1176
|
});
|
|
1177
|
+
drain();
|
|
1166
1178
|
const callbackToken = encodeCallbackToken(taskName);
|
|
1167
1179
|
runPipeline(taskName, callbackToken).catch((error) => {
|
|
1168
1180
|
if (disposed) return;
|
|
1169
|
-
|
|
1181
|
+
internalJournal.append({
|
|
1170
1182
|
type: "task-failed",
|
|
1171
1183
|
taskName,
|
|
1172
1184
|
error: error.message ?? String(error),
|
|
@@ -1181,16 +1193,16 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1181
1193
|
if (event.type === "task-completed" && event.data && !event.dataHash) {
|
|
1182
1194
|
event = { ...event, dataHash: computeDataHash(event.data) };
|
|
1183
1195
|
}
|
|
1184
|
-
|
|
1196
|
+
inputQueue.append(event);
|
|
1185
1197
|
drain();
|
|
1186
1198
|
},
|
|
1187
1199
|
pushAll(events) {
|
|
1188
1200
|
if (disposed) return;
|
|
1189
1201
|
for (const event of events) {
|
|
1190
1202
|
if (event.type === "task-completed" && event.data && !event.dataHash) {
|
|
1191
|
-
|
|
1203
|
+
inputQueue.append({ ...event, dataHash: computeDataHash(event.data) });
|
|
1192
1204
|
} else {
|
|
1193
|
-
|
|
1205
|
+
inputQueue.append(event);
|
|
1194
1206
|
}
|
|
1195
1207
|
}
|
|
1196
1208
|
drain();
|
|
@@ -1202,7 +1214,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1202
1214
|
const { taskName } = decoded;
|
|
1203
1215
|
if (!live.config.tasks[taskName]) return;
|
|
1204
1216
|
if (errors && errors.length > 0) {
|
|
1205
|
-
|
|
1217
|
+
inputQueue.append({
|
|
1206
1218
|
type: "task-failed",
|
|
1207
1219
|
taskName,
|
|
1208
1220
|
error: errors.join("; "),
|
|
@@ -1210,7 +1222,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1210
1222
|
});
|
|
1211
1223
|
} else {
|
|
1212
1224
|
const dataHash = data && Object.keys(data).length > 0 ? computeDataHash(data) : void 0;
|
|
1213
|
-
|
|
1225
|
+
inputQueue.append({
|
|
1214
1226
|
type: "task-completed",
|
|
1215
1227
|
taskName,
|
|
1216
1228
|
data,
|
|
@@ -1222,31 +1234,33 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1222
1234
|
},
|
|
1223
1235
|
addNode(name, taskConfig) {
|
|
1224
1236
|
if (disposed) return;
|
|
1225
|
-
|
|
1237
|
+
inputQueue.append({ type: "task-upsert", taskName: name, taskConfig, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1226
1238
|
drain();
|
|
1227
1239
|
},
|
|
1228
1240
|
removeNode(name) {
|
|
1229
1241
|
if (disposed) return;
|
|
1230
|
-
|
|
1242
|
+
inputQueue.append({ type: "task-removal", taskName: name, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1243
|
+
drain();
|
|
1231
1244
|
},
|
|
1232
1245
|
addRequires(nodeName, tokens) {
|
|
1233
1246
|
if (disposed) return;
|
|
1234
|
-
|
|
1247
|
+
inputQueue.append({ type: "node-requires-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1235
1248
|
drain();
|
|
1236
1249
|
},
|
|
1237
1250
|
removeRequires(nodeName, tokens) {
|
|
1238
1251
|
if (disposed) return;
|
|
1239
|
-
|
|
1252
|
+
inputQueue.append({ type: "node-requires-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1240
1253
|
drain();
|
|
1241
1254
|
},
|
|
1242
1255
|
addProvides(nodeName, tokens) {
|
|
1243
1256
|
if (disposed) return;
|
|
1244
|
-
|
|
1257
|
+
inputQueue.append({ type: "node-provides-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1245
1258
|
drain();
|
|
1246
1259
|
},
|
|
1247
1260
|
removeProvides(nodeName, tokens) {
|
|
1248
1261
|
if (disposed) return;
|
|
1249
|
-
|
|
1262
|
+
inputQueue.append({ type: "node-provides-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1263
|
+
drain();
|
|
1250
1264
|
},
|
|
1251
1265
|
registerHandler(name, fn) {
|
|
1252
1266
|
handlers.set(name, fn);
|
|
@@ -1257,7 +1271,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1257
1271
|
retrigger(taskName) {
|
|
1258
1272
|
if (disposed) return;
|
|
1259
1273
|
if (!live.config.tasks[taskName]) return;
|
|
1260
|
-
|
|
1274
|
+
inputQueue.append({
|
|
1261
1275
|
type: "task-restart",
|
|
1262
1276
|
taskName,
|
|
1263
1277
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -1268,7 +1282,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1268
1282
|
if (disposed) return;
|
|
1269
1283
|
for (const name of taskNames) {
|
|
1270
1284
|
if (!live.config.tasks[name]) continue;
|
|
1271
|
-
|
|
1285
|
+
inputQueue.append({
|
|
1272
1286
|
type: "task-restart",
|
|
1273
1287
|
taskName: name,
|
|
1274
1288
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -1276,6 +1290,9 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
1276
1290
|
}
|
|
1277
1291
|
drain();
|
|
1278
1292
|
},
|
|
1293
|
+
snapshot() {
|
|
1294
|
+
return snapshot(live);
|
|
1295
|
+
},
|
|
1279
1296
|
getState() {
|
|
1280
1297
|
return live;
|
|
1281
1298
|
},
|
|
@@ -1659,288 +1676,43 @@ function deepSet(obj, path, value) {
|
|
|
1659
1676
|
}
|
|
1660
1677
|
cur[parts[parts.length - 1]] = value;
|
|
1661
1678
|
}
|
|
1662
|
-
|
|
1663
|
-
|
|
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;
|
|
1679
|
+
async function run(node, options) {
|
|
1680
|
+
if (!node?.compute?.length) return node;
|
|
1927
1681
|
if (!node.state) node.state = {};
|
|
1928
|
-
|
|
1682
|
+
node.computed_values = {};
|
|
1683
|
+
node._sourcesData = options?.sourcesData ?? {};
|
|
1684
|
+
const ctx = {
|
|
1685
|
+
state: node.state,
|
|
1686
|
+
requires: node.requires ?? {},
|
|
1687
|
+
sources: node._sourcesData,
|
|
1688
|
+
computed_values: node.computed_values
|
|
1689
|
+
};
|
|
1690
|
+
for (const step of node.compute) {
|
|
1929
1691
|
try {
|
|
1930
|
-
const val =
|
|
1931
|
-
deepSet(node.
|
|
1692
|
+
const val = await jsonata__default.default(step.expr).evaluate(ctx);
|
|
1693
|
+
deepSet(node.computed_values, step.bindTo, val);
|
|
1694
|
+
ctx.computed_values = node.computed_values;
|
|
1932
1695
|
} catch (err) {
|
|
1933
|
-
console.error(`CardCompute.run error on "${node.id
|
|
1696
|
+
console.error(`CardCompute.run error on "${node.id ?? "?"}.${step.bindTo}":`, err);
|
|
1934
1697
|
}
|
|
1935
1698
|
}
|
|
1936
1699
|
return node;
|
|
1937
1700
|
}
|
|
1701
|
+
async function evalExpr(expr, node) {
|
|
1702
|
+
const ctx = {
|
|
1703
|
+
state: node.state ?? {},
|
|
1704
|
+
requires: node.requires ?? {},
|
|
1705
|
+
sources: node._sourcesData ?? {},
|
|
1706
|
+
computed_values: node.computed_values ?? {}
|
|
1707
|
+
};
|
|
1708
|
+
return jsonata__default.default(expr).evaluate(ctx);
|
|
1709
|
+
}
|
|
1938
1710
|
function resolve(node, path) {
|
|
1711
|
+
if (path.startsWith("sources.")) {
|
|
1712
|
+
return deepGet(node._sourcesData ?? {}, path.slice("sources.".length));
|
|
1713
|
+
}
|
|
1939
1714
|
return deepGet(node, path);
|
|
1940
1715
|
}
|
|
1941
|
-
function registerFunction(name, fn) {
|
|
1942
|
-
_customFns[name] = fn;
|
|
1943
|
-
}
|
|
1944
1716
|
var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
1945
1717
|
"metric",
|
|
1946
1718
|
"table",
|
|
@@ -1957,26 +1729,17 @@ var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
|
1957
1729
|
"markdown",
|
|
1958
1730
|
"custom"
|
|
1959
1731
|
]);
|
|
1960
|
-
var VALID_SOURCE_KINDS = /* @__PURE__ */ new Set(["api", "websocket", "static", "llm"]);
|
|
1961
1732
|
var VALID_STATUSES = /* @__PURE__ */ new Set(["fresh", "stale", "loading", "error"]);
|
|
1962
|
-
var
|
|
1963
|
-
var SOURCE_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "source", "state", "compute"]);
|
|
1733
|
+
var ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "meta", "requires", "provides", "view", "state", "compute", "sources"]);
|
|
1964
1734
|
function validateNode(node) {
|
|
1965
1735
|
const errors = [];
|
|
1966
1736
|
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
1967
1737
|
return { ok: false, errors: ["Node must be a non-null object"] };
|
|
1968
1738
|
}
|
|
1969
1739
|
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;
|
|
1740
|
+
if (typeof n.id !== "string" || !n.id) errors.push("id: required, must be a non-empty string");
|
|
1978
1741
|
for (const key of Object.keys(n)) {
|
|
1979
|
-
if (!
|
|
1742
|
+
if (!ALLOWED_KEYS.has(key)) errors.push(`Unknown top-level key: "${key}"`);
|
|
1980
1743
|
}
|
|
1981
1744
|
if (n.state == null || typeof n.state !== "object" || Array.isArray(n.state)) {
|
|
1982
1745
|
errors.push("state: required, must be an object");
|
|
@@ -1995,37 +1758,58 @@ function validateNode(node) {
|
|
|
1995
1758
|
if (meta.tags != null && !Array.isArray(meta.tags)) errors.push("meta.tags: must be an array");
|
|
1996
1759
|
}
|
|
1997
1760
|
}
|
|
1998
|
-
if (n.
|
|
1999
|
-
|
|
2000
|
-
|
|
1761
|
+
if (n.requires != null && !Array.isArray(n.requires)) errors.push("requires: must be an array of strings");
|
|
1762
|
+
if (n.provides != null) {
|
|
1763
|
+
if (!Array.isArray(n.provides)) {
|
|
1764
|
+
errors.push("provides: must be an array of { bindTo, src } bindings");
|
|
2001
1765
|
} else {
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
1766
|
+
n.provides.forEach((p, i) => {
|
|
1767
|
+
if (!p || typeof p !== "object" || Array.isArray(p)) {
|
|
1768
|
+
errors.push(`provides[${i}]: must be an object with bindTo and src`);
|
|
1769
|
+
} else {
|
|
1770
|
+
const b = p;
|
|
1771
|
+
if (typeof b.bindTo !== "string" || !b.bindTo) errors.push(`provides[${i}]: missing required "bindTo" string`);
|
|
1772
|
+
if (typeof b.src !== "string" || !b.src) errors.push(`provides[${i}]: missing required "src" string`);
|
|
1773
|
+
}
|
|
1774
|
+
});
|
|
2005
1775
|
}
|
|
2006
1776
|
}
|
|
2007
1777
|
if (n.compute != null) {
|
|
2008
|
-
if (
|
|
2009
|
-
errors.push("compute: must be an
|
|
1778
|
+
if (!Array.isArray(n.compute)) {
|
|
1779
|
+
errors.push("compute: must be an array of compute steps");
|
|
2010
1780
|
} else {
|
|
2011
|
-
|
|
2012
|
-
if (!
|
|
2013
|
-
errors.push(`compute
|
|
2014
|
-
} else if (!expr.fn) {
|
|
2015
|
-
errors.push(`compute.${key}: missing required "fn" property`);
|
|
1781
|
+
n.compute.forEach((step, i) => {
|
|
1782
|
+
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
1783
|
+
errors.push(`compute[${i}]: must be a compute step object`);
|
|
2016
1784
|
} else {
|
|
2017
|
-
const
|
|
2018
|
-
if (!
|
|
2019
|
-
|
|
1785
|
+
const s = step;
|
|
1786
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`compute[${i}]: missing required "bindTo" property`);
|
|
1787
|
+
if (typeof s.expr !== "string" || !s.expr) errors.push(`compute[${i}]: missing required "expr" string (JSONata expression)`);
|
|
1788
|
+
}
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
if (n.sources != null) {
|
|
1793
|
+
if (!Array.isArray(n.sources)) {
|
|
1794
|
+
errors.push("sources: must be an array");
|
|
1795
|
+
} else {
|
|
1796
|
+
n.sources.forEach((src, i) => {
|
|
1797
|
+
if (!src || typeof src !== "object" || Array.isArray(src)) {
|
|
1798
|
+
errors.push(`sources[${i}]: must be an object`);
|
|
1799
|
+
} else {
|
|
1800
|
+
const s = src;
|
|
1801
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`sources[${i}]: missing required "bindTo" property`);
|
|
1802
|
+
if (s.outputFile != null && typeof s.outputFile !== "string") errors.push(`sources[${i}]: outputFile must be a string`);
|
|
1803
|
+
if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
|
|
1804
|
+
errors.push(`sources[${i}]: optionalForCompletionGating must be a boolean`);
|
|
2020
1805
|
}
|
|
2021
1806
|
}
|
|
2022
|
-
}
|
|
1807
|
+
});
|
|
2023
1808
|
}
|
|
2024
1809
|
}
|
|
2025
|
-
if (n.
|
|
2026
|
-
if (n.
|
|
2027
|
-
|
|
2028
|
-
errors.push("view: required for card nodes, must be an object");
|
|
1810
|
+
if (n.view != null) {
|
|
1811
|
+
if (typeof n.view !== "object" || Array.isArray(n.view)) {
|
|
1812
|
+
errors.push("view: must be an object");
|
|
2029
1813
|
} else {
|
|
2030
1814
|
const view = n.view;
|
|
2031
1815
|
if (!Array.isArray(view.elements) || view.elements.length === 0) {
|
|
@@ -2046,28 +1830,8 @@ function validateNode(node) {
|
|
|
2046
1830
|
}
|
|
2047
1831
|
});
|
|
2048
1832
|
}
|
|
2049
|
-
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout)))
|
|
2050
|
-
|
|
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
|
-
}
|
|
1833
|
+
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout))) errors.push("view.layout: must be an object");
|
|
1834
|
+
if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) errors.push("view.features: must be an object");
|
|
2071
1835
|
}
|
|
2072
1836
|
}
|
|
2073
1837
|
return { ok: errors.length === 0, errors };
|
|
@@ -2076,14 +1840,7 @@ var CardCompute = {
|
|
|
2076
1840
|
run,
|
|
2077
1841
|
eval: evalExpr,
|
|
2078
1842
|
resolve,
|
|
2079
|
-
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
|
-
}
|
|
1843
|
+
validate: validateNode
|
|
2087
1844
|
};
|
|
2088
1845
|
|
|
2089
1846
|
// src/continuous-event-graph/live-cards-bridge.ts
|
|
@@ -2116,19 +1873,26 @@ function liveCardsToReactiveGraph(input, options = {}) {
|
|
|
2116
1873
|
}
|
|
2117
1874
|
const sharedState = options.sharedState ?? /* @__PURE__ */ new Map();
|
|
2118
1875
|
const tasks = {};
|
|
1876
|
+
const allTokens = /* @__PURE__ */ new Set();
|
|
1877
|
+
const tokenToCardId = /* @__PURE__ */ new Map();
|
|
1878
|
+
for (const card of cards) {
|
|
1879
|
+
for (const binding of card.provides ?? [{ bindTo: card.id, src: `state.${card.id}` }]) {
|
|
1880
|
+
allTokens.add(binding.bindTo);
|
|
1881
|
+
tokenToCardId.set(binding.bindTo, card.id);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
2119
1884
|
for (const card of cards) {
|
|
2120
|
-
const requires = card.
|
|
1885
|
+
const requires = card.requires ?? [];
|
|
2121
1886
|
for (const req of requires) {
|
|
2122
|
-
if (!
|
|
2123
|
-
throw new Error(`Card "${card.id}" requires "${req}" but no card
|
|
1887
|
+
if (!allTokens.has(req)) {
|
|
1888
|
+
throw new Error(`Card "${card.id}" requires "${req}" but no card provides that token`);
|
|
2124
1889
|
}
|
|
2125
1890
|
}
|
|
2126
1891
|
tasks[card.id] = {
|
|
2127
1892
|
requires: requires.length > 0 ? requires : void 0,
|
|
2128
|
-
provides: [card.id],
|
|
1893
|
+
provides: (card.provides ?? [{ bindTo: card.id, src: `state.${card.id}` }]).map((p) => p.bindTo),
|
|
2129
1894
|
taskHandlers: [card.id],
|
|
2130
|
-
|
|
2131
|
-
description: card.meta?.title ?? `${card.type}: ${card.id}`
|
|
1895
|
+
description: card.meta?.title ?? card.id
|
|
2132
1896
|
};
|
|
2133
1897
|
}
|
|
2134
1898
|
const config = {
|
|
@@ -2147,10 +1911,10 @@ function liveCardsToReactiveGraph(input, options = {}) {
|
|
|
2147
1911
|
graphRef.resolveCallback(token, data, errors);
|
|
2148
1912
|
};
|
|
2149
1913
|
for (const card of cards) {
|
|
2150
|
-
if (card.
|
|
1914
|
+
if (card.sources && card.sources.length > 0) {
|
|
2151
1915
|
handlers[card.id] = buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedState, getResolve);
|
|
2152
1916
|
} else {
|
|
2153
|
-
handlers[card.id] = buildCardHandler(card, cardHandlers, sharedState, cardMap, getResolve);
|
|
1917
|
+
handlers[card.id] = buildCardHandler(card, cardHandlers, sharedState, cardMap, tokenToCardId, getResolve);
|
|
2154
1918
|
}
|
|
2155
1919
|
}
|
|
2156
1920
|
const graph = createReactiveGraph(
|
|
@@ -2184,7 +1948,7 @@ function buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedSt
|
|
|
2184
1948
|
return "task-initiated";
|
|
2185
1949
|
};
|
|
2186
1950
|
}
|
|
2187
|
-
function buildCardHandler(card, cardHandlers, sharedState,
|
|
1951
|
+
function buildCardHandler(card, cardHandlers, sharedState, _cardMap, tokenToCardId, getResolve) {
|
|
2188
1952
|
if (cardHandlers[card.id]) {
|
|
2189
1953
|
const userHandler = cardHandlers[card.id];
|
|
2190
1954
|
return async (input) => {
|
|
@@ -2192,49 +1956,38 @@ function buildCardHandler(card, cardHandlers, sharedState, cardMap, getResolve)
|
|
|
2192
1956
|
};
|
|
2193
1957
|
}
|
|
2194
1958
|
return async (input) => {
|
|
1959
|
+
const requiresData = {};
|
|
1960
|
+
const requires = card.requires ?? [];
|
|
1961
|
+
for (const token of requires) {
|
|
1962
|
+
const producerId = tokenToCardId.get(token) ?? token;
|
|
1963
|
+
const upstreamState = sharedState.get(producerId);
|
|
1964
|
+
if (upstreamState) {
|
|
1965
|
+
requiresData[token] = upstreamState[token] ?? upstreamState;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
2195
1968
|
const computeNode = {
|
|
2196
1969
|
id: card.id,
|
|
2197
1970
|
state: { ...card.state },
|
|
1971
|
+
requires: requiresData,
|
|
2198
1972
|
compute: card.compute
|
|
2199
1973
|
};
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
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
|
-
}
|
|
1974
|
+
await CardCompute.run(computeNode);
|
|
1975
|
+
let resultData;
|
|
1976
|
+
if (card.provides && card.provides.length > 0) {
|
|
1977
|
+
resultData = {};
|
|
1978
|
+
for (const { bindTo, src } of card.provides) {
|
|
1979
|
+
resultData[bindTo] = CardCompute.resolve(computeNode, src);
|
|
2217
1980
|
}
|
|
1981
|
+
} else {
|
|
1982
|
+
resultData = { ...computeNode.state, ...computeNode.computed_values };
|
|
2218
1983
|
}
|
|
2219
|
-
|
|
2220
|
-
const resultState = { ...computeNode.state };
|
|
1984
|
+
const resultState = { ...computeNode.state, ...computeNode.computed_values };
|
|
2221
1985
|
sharedState.set(card.id, resultState);
|
|
2222
|
-
getResolve()(input.callbackToken,
|
|
1986
|
+
getResolve()(input.callbackToken, resultData);
|
|
2223
1987
|
return "task-initiated";
|
|
2224
1988
|
};
|
|
2225
1989
|
}
|
|
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
1990
|
|
|
2237
|
-
exports.FileJournal = FileJournal;
|
|
2238
1991
|
exports.MemoryJournal = MemoryJournal;
|
|
2239
1992
|
exports.addNode = addNode;
|
|
2240
1993
|
exports.addProvides = addProvides;
|