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
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var addFormats = require('ajv-formats');
|
|
4
|
-
var fs = require('fs');
|
|
5
4
|
var crypto$1 = require('crypto');
|
|
6
5
|
var child_process = require('child_process');
|
|
6
|
+
var jsonata = require('jsonata');
|
|
7
7
|
|
|
8
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
9
|
|
|
10
10
|
var addFormats__default = /*#__PURE__*/_interopDefault(addFormats);
|
|
11
|
+
var jsonata__default = /*#__PURE__*/_interopDefault(jsonata);
|
|
11
12
|
|
|
12
13
|
var __create = Object.create;
|
|
13
14
|
var __defProp = Object.defineProperty;
|
|
@@ -6445,7 +6446,7 @@ function applyStepResult(flow, state, stepName, stepResult) {
|
|
|
6445
6446
|
};
|
|
6446
6447
|
}
|
|
6447
6448
|
}
|
|
6448
|
-
const nextStep = stepConfig.transitions[stepResult.result];
|
|
6449
|
+
const nextStep = stepConfig.failure_transitions?.[stepResult.result] ?? stepConfig.transitions[stepResult.result];
|
|
6449
6450
|
if (!nextStep) {
|
|
6450
6451
|
throw new Error(
|
|
6451
6452
|
`No transition defined for result "${stepResult.result}" in step "${stepName}"`
|
|
@@ -6650,6 +6651,15 @@ var StepMachine = class {
|
|
|
6650
6651
|
);
|
|
6651
6652
|
}
|
|
6652
6653
|
}
|
|
6654
|
+
if (stepConfig.failure_transitions) {
|
|
6655
|
+
for (const [result, target] of Object.entries(stepConfig.failure_transitions)) {
|
|
6656
|
+
if (!steps[target] && !terminal_states[target]) {
|
|
6657
|
+
throw new Error(
|
|
6658
|
+
`Step "${stepName}" failure_transition "${result}" points to unknown step "${target}"`
|
|
6659
|
+
);
|
|
6660
|
+
}
|
|
6661
|
+
}
|
|
6662
|
+
}
|
|
6653
6663
|
}
|
|
6654
6664
|
}
|
|
6655
6665
|
on(eventType, listener) {
|
|
@@ -6879,6 +6889,9 @@ function validateStepFlowConfig(flow) {
|
|
|
6879
6889
|
if (!step.transitions || typeof step.transitions !== "object") {
|
|
6880
6890
|
errors.push(`Step "${stepName}" must have a "transitions" object`);
|
|
6881
6891
|
}
|
|
6892
|
+
if (step.failure_transitions !== void 0 && typeof step.failure_transitions !== "object") {
|
|
6893
|
+
errors.push(`Step "${stepName}" failure_transitions must be an object when provided`);
|
|
6894
|
+
}
|
|
6882
6895
|
}
|
|
6883
6896
|
}
|
|
6884
6897
|
if (!f.terminal_states || typeof f.terminal_states !== "object") {
|
|
@@ -6999,6 +7012,11 @@ var flow_schema_default = {
|
|
|
6999
7012
|
additionalProperties: { type: "string" },
|
|
7000
7013
|
minProperties: 1
|
|
7001
7014
|
},
|
|
7015
|
+
failure_transitions: {
|
|
7016
|
+
type: "object",
|
|
7017
|
+
description: "Mapping of failure-like results (e.g. failure, timeout) -> next step name",
|
|
7018
|
+
additionalProperties: { type: "string" }
|
|
7019
|
+
},
|
|
7002
7020
|
retry: {
|
|
7003
7021
|
$ref: "#/definitions/retry_config"
|
|
7004
7022
|
},
|
|
@@ -7937,8 +7955,8 @@ function apply(state, event, graph) {
|
|
|
7937
7955
|
return applyInjectTokens(state, event.tokens);
|
|
7938
7956
|
case "agent-action":
|
|
7939
7957
|
return applyAgentAction(state, event.action, graph, event.config);
|
|
7940
|
-
case "task-
|
|
7941
|
-
return
|
|
7958
|
+
case "task-upsert":
|
|
7959
|
+
return applyTaskUpsert(state, event.taskName, event.taskConfig);
|
|
7942
7960
|
default:
|
|
7943
7961
|
return state;
|
|
7944
7962
|
}
|
|
@@ -7995,7 +8013,7 @@ function applyAgentAction(state, action, graph, config) {
|
|
|
7995
8013
|
return state;
|
|
7996
8014
|
}
|
|
7997
8015
|
}
|
|
7998
|
-
function
|
|
8016
|
+
function applyTaskUpsert(state, taskName, taskConfig) {
|
|
7999
8017
|
if (!taskName || !taskConfig || !Array.isArray(taskConfig.provides)) {
|
|
8000
8018
|
return state;
|
|
8001
8019
|
}
|
|
@@ -8003,7 +8021,7 @@ function applyTaskCreation(state, taskName, taskConfig) {
|
|
|
8003
8021
|
...state,
|
|
8004
8022
|
tasks: {
|
|
8005
8023
|
...state.tasks,
|
|
8006
|
-
[taskName]: createDefaultGraphEngineStore()
|
|
8024
|
+
[taskName]: state.tasks[taskName] ?? createDefaultGraphEngineStore()
|
|
8007
8025
|
},
|
|
8008
8026
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
8009
8027
|
};
|
|
@@ -9275,43 +9293,51 @@ function applyEvent(live, event) {
|
|
|
9275
9293
|
if ("executionId" in event && event.executionId && event.executionId !== state.executionId) {
|
|
9276
9294
|
return live;
|
|
9277
9295
|
}
|
|
9278
|
-
let newState;
|
|
9279
9296
|
switch (event.type) {
|
|
9297
|
+
// --- Execution state transitions ---
|
|
9280
9298
|
case "task-started":
|
|
9281
|
-
|
|
9282
|
-
break;
|
|
9299
|
+
return { config, state: applyTaskStart(state, event.taskName) };
|
|
9283
9300
|
case "task-completed":
|
|
9284
|
-
|
|
9285
|
-
break;
|
|
9301
|
+
return { config, state: applyTaskCompletion(state, config, event.taskName, event.result, event.dataHash, event.data) };
|
|
9286
9302
|
case "task-failed":
|
|
9287
|
-
|
|
9288
|
-
break;
|
|
9303
|
+
return { config, state: applyTaskFailure(state, config, event.taskName, event.error) };
|
|
9289
9304
|
case "task-progress":
|
|
9290
|
-
|
|
9291
|
-
break;
|
|
9305
|
+
return { config, state: applyTaskProgress(state, event.taskName, event.message, event.progress) };
|
|
9292
9306
|
case "task-restart":
|
|
9293
|
-
|
|
9294
|
-
break;
|
|
9307
|
+
return { config, state: applyTaskRestart(state, event.taskName) };
|
|
9295
9308
|
case "inject-tokens":
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9309
|
+
return {
|
|
9310
|
+
config,
|
|
9311
|
+
state: {
|
|
9312
|
+
...state,
|
|
9313
|
+
availableOutputs: [.../* @__PURE__ */ new Set([...state.availableOutputs, ...event.tokens])],
|
|
9314
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
9315
|
+
}
|
|
9300
9316
|
};
|
|
9301
|
-
break;
|
|
9302
9317
|
case "agent-action":
|
|
9303
|
-
|
|
9304
|
-
|
|
9318
|
+
return { config, state: applyAgentAction2(state, event.action) };
|
|
9319
|
+
// --- Structural mutations ---
|
|
9320
|
+
case "task-upsert":
|
|
9321
|
+
return addNode(live, event.taskName, event.taskConfig);
|
|
9322
|
+
case "task-removal":
|
|
9323
|
+
return removeNode(live, event.taskName);
|
|
9324
|
+
case "node-requires-add":
|
|
9325
|
+
return addRequires(live, event.nodeName, event.tokens);
|
|
9326
|
+
case "node-requires-remove":
|
|
9327
|
+
return removeRequires(live, event.nodeName, event.tokens);
|
|
9328
|
+
case "node-provides-add":
|
|
9329
|
+
return addProvides(live, event.nodeName, event.tokens);
|
|
9330
|
+
case "node-provides-remove":
|
|
9331
|
+
return removeProvides(live, event.nodeName, event.tokens);
|
|
9305
9332
|
default:
|
|
9306
9333
|
return live;
|
|
9307
9334
|
}
|
|
9308
|
-
return { config, state: newState };
|
|
9309
9335
|
}
|
|
9310
9336
|
function applyEvents(live, events) {
|
|
9311
9337
|
return events.reduce((current, event) => applyEvent(current, event), live);
|
|
9312
9338
|
}
|
|
9313
9339
|
function addNode(live, name, taskConfig) {
|
|
9314
|
-
|
|
9340
|
+
const exists = !!live.config.tasks[name];
|
|
9315
9341
|
return {
|
|
9316
9342
|
config: {
|
|
9317
9343
|
...live.config,
|
|
@@ -9319,7 +9345,10 @@ function addNode(live, name, taskConfig) {
|
|
|
9319
9345
|
},
|
|
9320
9346
|
state: {
|
|
9321
9347
|
...live.state,
|
|
9322
|
-
tasks: {
|
|
9348
|
+
tasks: {
|
|
9349
|
+
...live.state.tasks,
|
|
9350
|
+
[name]: exists ? live.state.tasks[name] : createDefaultGraphEngineStore3()
|
|
9351
|
+
},
|
|
9323
9352
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
9324
9353
|
}
|
|
9325
9354
|
};
|
|
@@ -10026,6 +10055,8 @@ function getDownstream(live, nodeName) {
|
|
|
10026
10055
|
}));
|
|
10027
10056
|
return { nodeName, nodes, tokens: [...tokenSet] };
|
|
10028
10057
|
}
|
|
10058
|
+
|
|
10059
|
+
// src/continuous-event-graph/journal.ts
|
|
10029
10060
|
var MemoryJournal = class {
|
|
10030
10061
|
buffer = [];
|
|
10031
10062
|
append(event) {
|
|
@@ -10040,36 +10071,6 @@ var MemoryJournal = class {
|
|
|
10040
10071
|
return this.buffer.length;
|
|
10041
10072
|
}
|
|
10042
10073
|
};
|
|
10043
|
-
var FileJournal = class {
|
|
10044
|
-
constructor(path) {
|
|
10045
|
-
this.path = path;
|
|
10046
|
-
if (!fs.existsSync(path)) {
|
|
10047
|
-
fs.writeFileSync(path, "", "utf-8");
|
|
10048
|
-
}
|
|
10049
|
-
}
|
|
10050
|
-
path;
|
|
10051
|
-
pending = 0;
|
|
10052
|
-
append(event) {
|
|
10053
|
-
fs.appendFileSync(this.path, JSON.stringify(event) + "\n", "utf-8");
|
|
10054
|
-
this.pending++;
|
|
10055
|
-
}
|
|
10056
|
-
drain() {
|
|
10057
|
-
const content = fs.readFileSync(this.path, "utf-8").trim();
|
|
10058
|
-
fs.writeFileSync(this.path, "", "utf-8");
|
|
10059
|
-
this.pending = 0;
|
|
10060
|
-
if (!content) return [];
|
|
10061
|
-
return content.split("\n").map((line) => JSON.parse(line));
|
|
10062
|
-
}
|
|
10063
|
-
get size() {
|
|
10064
|
-
try {
|
|
10065
|
-
const content = fs.readFileSync(this.path, "utf-8").trim();
|
|
10066
|
-
if (!content) return 0;
|
|
10067
|
-
return content.split("\n").length;
|
|
10068
|
-
} catch {
|
|
10069
|
-
return this.pending;
|
|
10070
|
-
}
|
|
10071
|
-
}
|
|
10072
|
-
};
|
|
10073
10074
|
function computeDataHash(data) {
|
|
10074
10075
|
const json = stableStringify(data);
|
|
10075
10076
|
return crypto$1.createHash("sha256").update(json).digest("hex").slice(0, 16);
|
|
@@ -10098,15 +10099,16 @@ function decodeCallbackToken(token) {
|
|
|
10098
10099
|
return null;
|
|
10099
10100
|
}
|
|
10100
10101
|
}
|
|
10101
|
-
function createReactiveGraph(
|
|
10102
|
+
function createReactiveGraph(configOrLive, options, executionId) {
|
|
10102
10103
|
const {
|
|
10103
10104
|
handlers: initialHandlers,
|
|
10104
|
-
journal = new MemoryJournal(),
|
|
10105
10105
|
onDrain
|
|
10106
10106
|
} = options;
|
|
10107
|
-
|
|
10107
|
+
const inputQueue = new MemoryJournal();
|
|
10108
|
+
let live = "state" in configOrLive && "config" in configOrLive ? configOrLive : createLiveGraph(configOrLive, executionId);
|
|
10108
10109
|
let disposed = false;
|
|
10109
10110
|
const handlers = new Map(Object.entries(initialHandlers));
|
|
10111
|
+
const internalJournal = new MemoryJournal();
|
|
10110
10112
|
let draining = false;
|
|
10111
10113
|
let drainQueued = false;
|
|
10112
10114
|
function drain() {
|
|
@@ -10126,7 +10128,9 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10126
10128
|
}
|
|
10127
10129
|
}
|
|
10128
10130
|
function drainOnce() {
|
|
10129
|
-
const
|
|
10131
|
+
const internalEvents = internalJournal.drain();
|
|
10132
|
+
const inputEvents = inputQueue.drain();
|
|
10133
|
+
const events = [...internalEvents, ...inputEvents];
|
|
10130
10134
|
if (events.length > 0) {
|
|
10131
10135
|
live = applyEvents(live, events);
|
|
10132
10136
|
}
|
|
@@ -10137,6 +10141,26 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10137
10141
|
for (const taskName of result.eligible) {
|
|
10138
10142
|
dispatchTask(taskName);
|
|
10139
10143
|
}
|
|
10144
|
+
for (const event of events) {
|
|
10145
|
+
if (event.type === "task-progress") {
|
|
10146
|
+
const { taskName, update } = event;
|
|
10147
|
+
const taskConfig = live.config.tasks[taskName];
|
|
10148
|
+
if (!taskConfig) continue;
|
|
10149
|
+
const taskState = live.state.tasks[taskName];
|
|
10150
|
+
if (!taskState || taskState.status !== "running") continue;
|
|
10151
|
+
const callbackToken = encodeCallbackToken(taskName);
|
|
10152
|
+
runPipeline(taskName, callbackToken, update).catch((error) => {
|
|
10153
|
+
if (disposed) return;
|
|
10154
|
+
internalJournal.append({
|
|
10155
|
+
type: "task-failed",
|
|
10156
|
+
taskName,
|
|
10157
|
+
error: error.message ?? String(error),
|
|
10158
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10159
|
+
});
|
|
10160
|
+
drain();
|
|
10161
|
+
});
|
|
10162
|
+
}
|
|
10163
|
+
}
|
|
10140
10164
|
}
|
|
10141
10165
|
function resolveUpstreamState(taskName) {
|
|
10142
10166
|
const taskConfig = live.config.tasks[taskName];
|
|
@@ -10158,7 +10182,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10158
10182
|
}
|
|
10159
10183
|
return state;
|
|
10160
10184
|
}
|
|
10161
|
-
async function runPipeline(taskName, callbackToken) {
|
|
10185
|
+
async function runPipeline(taskName, callbackToken, update) {
|
|
10162
10186
|
const taskConfig = live.config.tasks[taskName];
|
|
10163
10187
|
const handlerNames = taskConfig.taskHandlers ?? [];
|
|
10164
10188
|
const upstreamState = resolveUpstreamState(taskName);
|
|
@@ -10172,7 +10196,8 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10172
10196
|
state: upstreamState,
|
|
10173
10197
|
taskState: live.state.tasks[taskName],
|
|
10174
10198
|
config: taskConfig,
|
|
10175
|
-
callbackToken
|
|
10199
|
+
callbackToken,
|
|
10200
|
+
update
|
|
10176
10201
|
};
|
|
10177
10202
|
const status = await handler(input);
|
|
10178
10203
|
if (status === "task-initiate-failure") {
|
|
@@ -10186,15 +10211,16 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10186
10211
|
if (!handlerNames || handlerNames.length === 0) {
|
|
10187
10212
|
return;
|
|
10188
10213
|
}
|
|
10189
|
-
|
|
10214
|
+
internalJournal.append({
|
|
10190
10215
|
type: "task-started",
|
|
10191
10216
|
taskName,
|
|
10192
10217
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
10193
10218
|
});
|
|
10219
|
+
drain();
|
|
10194
10220
|
const callbackToken = encodeCallbackToken(taskName);
|
|
10195
10221
|
runPipeline(taskName, callbackToken).catch((error) => {
|
|
10196
10222
|
if (disposed) return;
|
|
10197
|
-
|
|
10223
|
+
internalJournal.append({
|
|
10198
10224
|
type: "task-failed",
|
|
10199
10225
|
taskName,
|
|
10200
10226
|
error: error.message ?? String(error),
|
|
@@ -10209,16 +10235,16 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10209
10235
|
if (event.type === "task-completed" && event.data && !event.dataHash) {
|
|
10210
10236
|
event = { ...event, dataHash: computeDataHash(event.data) };
|
|
10211
10237
|
}
|
|
10212
|
-
|
|
10238
|
+
inputQueue.append(event);
|
|
10213
10239
|
drain();
|
|
10214
10240
|
},
|
|
10215
10241
|
pushAll(events) {
|
|
10216
10242
|
if (disposed) return;
|
|
10217
10243
|
for (const event of events) {
|
|
10218
10244
|
if (event.type === "task-completed" && event.data && !event.dataHash) {
|
|
10219
|
-
|
|
10245
|
+
inputQueue.append({ ...event, dataHash: computeDataHash(event.data) });
|
|
10220
10246
|
} else {
|
|
10221
|
-
|
|
10247
|
+
inputQueue.append(event);
|
|
10222
10248
|
}
|
|
10223
10249
|
}
|
|
10224
10250
|
drain();
|
|
@@ -10230,7 +10256,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10230
10256
|
const { taskName } = decoded;
|
|
10231
10257
|
if (!live.config.tasks[taskName]) return;
|
|
10232
10258
|
if (errors && errors.length > 0) {
|
|
10233
|
-
|
|
10259
|
+
inputQueue.append({
|
|
10234
10260
|
type: "task-failed",
|
|
10235
10261
|
taskName,
|
|
10236
10262
|
error: errors.join("; "),
|
|
@@ -10238,7 +10264,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10238
10264
|
});
|
|
10239
10265
|
} else {
|
|
10240
10266
|
const dataHash = data && Object.keys(data).length > 0 ? computeDataHash(data) : void 0;
|
|
10241
|
-
|
|
10267
|
+
inputQueue.append({
|
|
10242
10268
|
type: "task-completed",
|
|
10243
10269
|
taskName,
|
|
10244
10270
|
data,
|
|
@@ -10250,31 +10276,33 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10250
10276
|
},
|
|
10251
10277
|
addNode(name, taskConfig) {
|
|
10252
10278
|
if (disposed) return;
|
|
10253
|
-
|
|
10279
|
+
inputQueue.append({ type: "task-upsert", taskName: name, taskConfig, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10254
10280
|
drain();
|
|
10255
10281
|
},
|
|
10256
10282
|
removeNode(name) {
|
|
10257
10283
|
if (disposed) return;
|
|
10258
|
-
|
|
10284
|
+
inputQueue.append({ type: "task-removal", taskName: name, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10285
|
+
drain();
|
|
10259
10286
|
},
|
|
10260
10287
|
addRequires(nodeName, tokens) {
|
|
10261
10288
|
if (disposed) return;
|
|
10262
|
-
|
|
10289
|
+
inputQueue.append({ type: "node-requires-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10263
10290
|
drain();
|
|
10264
10291
|
},
|
|
10265
10292
|
removeRequires(nodeName, tokens) {
|
|
10266
10293
|
if (disposed) return;
|
|
10267
|
-
|
|
10294
|
+
inputQueue.append({ type: "node-requires-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10268
10295
|
drain();
|
|
10269
10296
|
},
|
|
10270
10297
|
addProvides(nodeName, tokens) {
|
|
10271
10298
|
if (disposed) return;
|
|
10272
|
-
|
|
10299
|
+
inputQueue.append({ type: "node-provides-add", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10273
10300
|
drain();
|
|
10274
10301
|
},
|
|
10275
10302
|
removeProvides(nodeName, tokens) {
|
|
10276
10303
|
if (disposed) return;
|
|
10277
|
-
|
|
10304
|
+
inputQueue.append({ type: "node-provides-remove", nodeName, tokens, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
10305
|
+
drain();
|
|
10278
10306
|
},
|
|
10279
10307
|
registerHandler(name, fn) {
|
|
10280
10308
|
handlers.set(name, fn);
|
|
@@ -10285,7 +10313,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10285
10313
|
retrigger(taskName) {
|
|
10286
10314
|
if (disposed) return;
|
|
10287
10315
|
if (!live.config.tasks[taskName]) return;
|
|
10288
|
-
|
|
10316
|
+
inputQueue.append({
|
|
10289
10317
|
type: "task-restart",
|
|
10290
10318
|
taskName,
|
|
10291
10319
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -10296,7 +10324,7 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10296
10324
|
if (disposed) return;
|
|
10297
10325
|
for (const name of taskNames) {
|
|
10298
10326
|
if (!live.config.tasks[name]) continue;
|
|
10299
|
-
|
|
10327
|
+
inputQueue.append({
|
|
10300
10328
|
type: "task-restart",
|
|
10301
10329
|
taskName: name,
|
|
10302
10330
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -10304,6 +10332,9 @@ function createReactiveGraph(config, options, executionId) {
|
|
|
10304
10332
|
}
|
|
10305
10333
|
drain();
|
|
10306
10334
|
},
|
|
10335
|
+
snapshot() {
|
|
10336
|
+
return snapshot(live);
|
|
10337
|
+
},
|
|
10307
10338
|
getState() {
|
|
10308
10339
|
return live;
|
|
10309
10340
|
},
|
|
@@ -10675,9 +10706,9 @@ var live_cards_schema_default = {
|
|
|
10675
10706
|
description: "Schema for Card and ExternalSource nodes in the LiveCards Board/Canvas engine",
|
|
10676
10707
|
definitions: {
|
|
10677
10708
|
bind_ref: {
|
|
10678
|
-
description: "A state path reference, e.g. 'state.raw_quotes' or '
|
|
10709
|
+
description: "A state path reference, e.g. 'state.raw_quotes' or 'requires.upstream'",
|
|
10679
10710
|
type: "string",
|
|
10680
|
-
pattern: "^state\\."
|
|
10711
|
+
pattern: "^(state|requires|computed_values)\\."
|
|
10681
10712
|
},
|
|
10682
10713
|
bind_or_literal: {
|
|
10683
10714
|
description: "A literal value or a bind reference object",
|
|
@@ -10770,38 +10801,43 @@ var live_cards_schema_default = {
|
|
|
10770
10801
|
tags: { type: "array", items: { type: "string" } }
|
|
10771
10802
|
}
|
|
10772
10803
|
},
|
|
10773
|
-
|
|
10804
|
+
requires: {
|
|
10805
|
+
type: "array",
|
|
10806
|
+
items: { type: "string" },
|
|
10807
|
+
description: "IDs of upstream nodes this node depends on"
|
|
10808
|
+
},
|
|
10809
|
+
provides: {
|
|
10810
|
+
type: "array",
|
|
10811
|
+
items: {
|
|
10812
|
+
type: "object",
|
|
10813
|
+
required: ["bindTo", "src"],
|
|
10814
|
+
properties: {
|
|
10815
|
+
bindTo: { type: "string", description: "Token name published downstream" },
|
|
10816
|
+
src: { type: "string", description: "Path to read value from (state.*, requires.*, computed_values.*)" }
|
|
10817
|
+
}
|
|
10818
|
+
},
|
|
10819
|
+
description: "Explicit bindings exposing computed/state values downstream as named tokens"
|
|
10820
|
+
},
|
|
10821
|
+
compute_step: {
|
|
10822
|
+
description: "A single ordered compute step: reads state.*/requires.*/computed_values.*, writes to computed_values[bindTo]",
|
|
10774
10823
|
type: "object",
|
|
10824
|
+
required: ["bindTo", "expr"],
|
|
10775
10825
|
properties: {
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
items: { type: "string" },
|
|
10779
|
-
description: "IDs of upstream nodes this node depends on"
|
|
10780
|
-
},
|
|
10781
|
-
provides: {
|
|
10782
|
-
type: "object",
|
|
10783
|
-
description: "Subset of state exposed downstream. Keys are published names, values are bind refs.",
|
|
10784
|
-
additionalProperties: { $ref: "#/definitions/bind_or_literal" }
|
|
10785
|
-
}
|
|
10826
|
+
bindTo: { type: "string", description: "Key in computed_values to write result" },
|
|
10827
|
+
expr: { type: "string", description: "JSONata expression evaluated against { state, requires, sources, computed_values }" }
|
|
10786
10828
|
}
|
|
10787
10829
|
},
|
|
10788
10830
|
source_def: {
|
|
10831
|
+
description: "One source entry. The engine only cares about 'bindTo' (compute namespace key) and 'outputFile' (delivery signal). Every other property is yours \u2014 add whatever your task-executor needs: kind, url, headers, mailbox, channel, model, query, etc. The full object is passed verbatim as the --in JSON to the executor.",
|
|
10789
10832
|
type: "object",
|
|
10790
|
-
required: ["
|
|
10833
|
+
required: ["bindTo"],
|
|
10834
|
+
additionalProperties: true,
|
|
10791
10835
|
properties: {
|
|
10792
|
-
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
10796
|
-
|
|
10797
|
-
body_template: { type: "object", description: "Request body with {{var}} placeholders or bind refs" },
|
|
10798
|
-
template_vars: {
|
|
10799
|
-
type: "object",
|
|
10800
|
-
additionalProperties: { $ref: "#/definitions/bind_or_literal" },
|
|
10801
|
-
description: "Variables for url/body templates \u2014 static values or bind refs"
|
|
10802
|
-
},
|
|
10803
|
-
poll_interval: { type: "integer", minimum: 0, description: "Auto-refresh in seconds (0 = manual)" },
|
|
10804
|
-
transform: { type: "string", description: "Dot-path to extract from response, e.g. 'data.items'" }
|
|
10836
|
+
bindTo: { type: "string", description: "Key under sources.* available in compute expressions" },
|
|
10837
|
+
outputFile: { type: "string", description: "Board-relative path the executor writes its JSON result to. Presence of this file signals delivery." },
|
|
10838
|
+
optionalForCompletionGating: { type: "boolean", default: false, description: "When true this source does not gate card completion. Default false when absent, so sources are completion-gating by default." },
|
|
10839
|
+
timeout: { type: "integer", minimum: 0, default: 12e4, description: "Executor/script timeout in ms. Default: 120 000 (2 min)." },
|
|
10840
|
+
script: { type: "string", description: "Legacy direct-run: shell command executed when no .task-executor is registered. stdout is captured as the result." }
|
|
10805
10841
|
}
|
|
10806
10842
|
},
|
|
10807
10843
|
render_element: {
|
|
@@ -10919,64 +10955,37 @@ var live_cards_schema_default = {
|
|
|
10919
10955
|
}
|
|
10920
10956
|
}
|
|
10921
10957
|
},
|
|
10922
|
-
|
|
10923
|
-
|
|
10924
|
-
|
|
10925
|
-
|
|
10958
|
+
title: "LiveCard",
|
|
10959
|
+
description: "A unified card node. Behavior depends on which sections are present (sources, compute, view, etc.)",
|
|
10960
|
+
type: "object",
|
|
10961
|
+
required: ["id"],
|
|
10962
|
+
additionalProperties: false,
|
|
10963
|
+
properties: {
|
|
10964
|
+
id: { type: "string" },
|
|
10965
|
+
requires: { $ref: "#/definitions/requires" },
|
|
10966
|
+
provides: { $ref: "#/definitions/provides" },
|
|
10967
|
+
meta: { $ref: "#/definitions/meta" },
|
|
10968
|
+
view: { $ref: "#/definitions/view" },
|
|
10969
|
+
state: {
|
|
10926
10970
|
type: "object",
|
|
10927
|
-
|
|
10928
|
-
additionalProperties: false,
|
|
10971
|
+
additionalProperties: true,
|
|
10929
10972
|
properties: {
|
|
10930
|
-
|
|
10931
|
-
|
|
10932
|
-
|
|
10933
|
-
data: { $ref: "#/definitions/data" },
|
|
10934
|
-
view: { $ref: "#/definitions/view" },
|
|
10935
|
-
state: {
|
|
10936
|
-
type: "object",
|
|
10937
|
-
additionalProperties: true,
|
|
10938
|
-
properties: {
|
|
10939
|
-
status: { enum: ["fresh", "stale", "loading", "error"] },
|
|
10940
|
-
lastRun: { type: "string", format: "date-time" },
|
|
10941
|
-
error: { type: "string" }
|
|
10942
|
-
}
|
|
10943
|
-
},
|
|
10944
|
-
compute: {
|
|
10945
|
-
type: "object",
|
|
10946
|
-
description: "Derived state: key = state path to write, value = compute_expr",
|
|
10947
|
-
additionalProperties: { $ref: "#/definitions/compute_expr" }
|
|
10948
|
-
}
|
|
10973
|
+
status: { enum: ["fresh", "stale", "loading", "error"] },
|
|
10974
|
+
lastRun: { type: "string", format: "date-time" },
|
|
10975
|
+
error: { type: "string" }
|
|
10949
10976
|
}
|
|
10950
10977
|
},
|
|
10951
|
-
{
|
|
10952
|
-
|
|
10953
|
-
description: "
|
|
10954
|
-
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
meta: { $ref: "#/definitions/meta" },
|
|
10961
|
-
data: { $ref: "#/definitions/data" },
|
|
10962
|
-
source: { $ref: "#/definitions/source_def" },
|
|
10963
|
-
state: {
|
|
10964
|
-
type: "object",
|
|
10965
|
-
additionalProperties: true,
|
|
10966
|
-
properties: {
|
|
10967
|
-
status: { enum: ["fresh", "stale", "loading", "error"] },
|
|
10968
|
-
lastRun: { type: "string", format: "date-time" },
|
|
10969
|
-
error: { type: "string" }
|
|
10970
|
-
}
|
|
10971
|
-
},
|
|
10972
|
-
compute: {
|
|
10973
|
-
type: "object",
|
|
10974
|
-
description: "Derived state: key = state path to write, value = compute_expr",
|
|
10975
|
-
additionalProperties: { $ref: "#/definitions/compute_expr" }
|
|
10976
|
-
}
|
|
10977
|
-
}
|
|
10978
|
+
sources: {
|
|
10979
|
+
type: "array",
|
|
10980
|
+
description: "Source entries. Each entry is passed verbatim to the board's .task-executor (registered via init --task-executor) as the --in JSON file. The executor fetches/generates the data and writes JSON to --out. If no executor is registered, the built-in executor runs the entry's 'cli' command directly. Sources gate completion by default. Set optionalForCompletionGating: true for enrichment-only sources that should not block task-completed.",
|
|
10981
|
+
items: { $ref: "#/definitions/source_def" }
|
|
10982
|
+
},
|
|
10983
|
+
compute: {
|
|
10984
|
+
type: "array",
|
|
10985
|
+
description: "Ordered array of compute steps. Each reads state.*/requires.*/sources.*/computed_values.* and writes to ephemeral computed_values[bindTo].",
|
|
10986
|
+
items: { $ref: "#/definitions/compute_step" }
|
|
10978
10987
|
}
|
|
10979
|
-
|
|
10988
|
+
}
|
|
10980
10989
|
};
|
|
10981
10990
|
|
|
10982
10991
|
// src/card-compute/schema-validator.ts
|
|
@@ -11020,288 +11029,43 @@ function deepSet(obj, path, value) {
|
|
|
11020
11029
|
}
|
|
11021
11030
|
cur[parts[parts.length - 1]] = value;
|
|
11022
11031
|
}
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
const a = Array.isArray(input) ? input : [];
|
|
11026
|
-
return opts.field ? a.reduce((s, r) => s + (Number(r[opts.field]) || 0), 0) : a.reduce((s, v) => s + (Number(v) || 0), 0);
|
|
11027
|
-
};
|
|
11028
|
-
_fns.avg = (input, _e, opts) => {
|
|
11029
|
-
const s = _fns.sum(input, _e, opts);
|
|
11030
|
-
const n = Array.isArray(input) ? input.length : 1;
|
|
11031
|
-
return n ? s / n : 0;
|
|
11032
|
-
};
|
|
11033
|
-
_fns.min = (input, _e, opts) => {
|
|
11034
|
-
const a = Array.isArray(input) ? input : [];
|
|
11035
|
-
const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
|
|
11036
|
-
return vals.length ? Math.min(...vals) : 0;
|
|
11037
|
-
};
|
|
11038
|
-
_fns.max = (input, _e, opts) => {
|
|
11039
|
-
const a = Array.isArray(input) ? input : [];
|
|
11040
|
-
const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
|
|
11041
|
-
return vals.length ? Math.max(...vals) : 0;
|
|
11042
|
-
};
|
|
11043
|
-
_fns.count = (input) => Array.isArray(input) ? input.length : input != null ? 1 : 0;
|
|
11044
|
-
_fns.first = (input) => Array.isArray(input) ? input[0] : input;
|
|
11045
|
-
_fns.last = (input) => Array.isArray(input) ? input[input.length - 1] : input;
|
|
11046
|
-
_fns.add = (input) => {
|
|
11047
|
-
const a = Array.isArray(input) ? input : [];
|
|
11048
|
-
return a.reduce((s, v) => s + Number(v), 0);
|
|
11049
|
-
};
|
|
11050
|
-
_fns.sub = (input) => {
|
|
11051
|
-
const a = Array.isArray(input) ? input : [];
|
|
11052
|
-
return a.length >= 2 ? Number(a[0]) - Number(a[1]) : 0;
|
|
11053
|
-
};
|
|
11054
|
-
_fns.mul = (input) => {
|
|
11055
|
-
const a = Array.isArray(input) ? input : [];
|
|
11056
|
-
return a.reduce((s, v) => s * Number(v), 1);
|
|
11057
|
-
};
|
|
11058
|
-
_fns.div = (input) => {
|
|
11059
|
-
const a = Array.isArray(input) ? input : [];
|
|
11060
|
-
return a.length >= 2 && Number(a[1]) !== 0 ? Number(a[0]) / Number(a[1]) : 0;
|
|
11061
|
-
};
|
|
11062
|
-
_fns.round = (input, _e, opts) => {
|
|
11063
|
-
const decimals = opts.decimals != null ? opts.decimals : 0;
|
|
11064
|
-
const factor = Math.pow(10, decimals);
|
|
11065
|
-
return Math.round(Number(input) * factor) / factor;
|
|
11066
|
-
};
|
|
11067
|
-
_fns.abs = (input) => Math.abs(Number(input));
|
|
11068
|
-
_fns.mod = (input) => {
|
|
11069
|
-
const a = Array.isArray(input) ? input : [];
|
|
11070
|
-
return a.length >= 2 ? Number(a[0]) % Number(a[1]) : 0;
|
|
11071
|
-
};
|
|
11072
|
-
_fns.gt = (input) => {
|
|
11073
|
-
const a = Array.isArray(input) ? input : [];
|
|
11074
|
-
return a.length >= 2 && Number(a[0]) > Number(a[1]);
|
|
11075
|
-
};
|
|
11076
|
-
_fns.gte = (input) => {
|
|
11077
|
-
const a = Array.isArray(input) ? input : [];
|
|
11078
|
-
return a.length >= 2 && Number(a[0]) >= Number(a[1]);
|
|
11079
|
-
};
|
|
11080
|
-
_fns.lt = (input) => {
|
|
11081
|
-
const a = Array.isArray(input) ? input : [];
|
|
11082
|
-
return a.length >= 2 && Number(a[0]) < Number(a[1]);
|
|
11083
|
-
};
|
|
11084
|
-
_fns.lte = (input) => {
|
|
11085
|
-
const a = Array.isArray(input) ? input : [];
|
|
11086
|
-
return a.length >= 2 && Number(a[0]) <= Number(a[1]);
|
|
11087
|
-
};
|
|
11088
|
-
_fns.eq = (input) => {
|
|
11089
|
-
const a = Array.isArray(input) ? input : [];
|
|
11090
|
-
return a.length >= 2 && a[0] === a[1];
|
|
11091
|
-
};
|
|
11092
|
-
_fns.neq = (input) => {
|
|
11093
|
-
const a = Array.isArray(input) ? input : [];
|
|
11094
|
-
return a.length >= 2 && a[0] !== a[1];
|
|
11095
|
-
};
|
|
11096
|
-
_fns.and = (input) => {
|
|
11097
|
-
const a = Array.isArray(input) ? input : [];
|
|
11098
|
-
return a.every(Boolean);
|
|
11099
|
-
};
|
|
11100
|
-
_fns.or = (input) => {
|
|
11101
|
-
const a = Array.isArray(input) ? input : [];
|
|
11102
|
-
return a.some(Boolean);
|
|
11103
|
-
};
|
|
11104
|
-
_fns.not = (input) => !input;
|
|
11105
|
-
_fns.concat = (input) => {
|
|
11106
|
-
const a = Array.isArray(input) ? input : [];
|
|
11107
|
-
return a.map((v) => v != null ? String(v) : "").join("");
|
|
11108
|
-
};
|
|
11109
|
-
_fns.upper = (input) => String(input || "").toUpperCase();
|
|
11110
|
-
_fns.lower = (input) => String(input || "").toLowerCase();
|
|
11111
|
-
_fns.template = (input, _e, opts) => {
|
|
11112
|
-
let t = String(opts.format || "");
|
|
11113
|
-
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
11114
|
-
for (const k of Object.keys(input)) {
|
|
11115
|
-
const v = input[k];
|
|
11116
|
-
t = t.split("{{" + k + "}}").join(v != null ? String(v) : "");
|
|
11117
|
-
}
|
|
11118
|
-
}
|
|
11119
|
-
return t;
|
|
11120
|
-
};
|
|
11121
|
-
_fns.join = (input, _e, opts) => {
|
|
11122
|
-
const a = Array.isArray(input) ? input : [];
|
|
11123
|
-
const sep = opts.separator != null ? String(opts.separator) : ", ";
|
|
11124
|
-
return a.map((v) => v != null ? String(v) : "").join(sep);
|
|
11125
|
-
};
|
|
11126
|
-
_fns.split = (input, _e, opts) => {
|
|
11127
|
-
const sep = opts.separator != null ? String(opts.separator) : ",";
|
|
11128
|
-
return String(input || "").split(sep).map((s) => s.trim());
|
|
11129
|
-
};
|
|
11130
|
-
_fns.trim = (input) => String(input || "").trim();
|
|
11131
|
-
_fns.pluck = (input, _e, opts) => Array.isArray(input) ? input.map((r) => r[opts.field]) : [];
|
|
11132
|
-
_fns.filter = (input, _e, opts) => {
|
|
11133
|
-
if (!Array.isArray(input)) return [];
|
|
11134
|
-
if (opts.field) return input.filter((r) => !!r[opts.field]);
|
|
11135
|
-
return input.filter(Boolean);
|
|
11136
|
-
};
|
|
11137
|
-
_fns.map = (input) => Array.isArray(input) ? input.slice() : [];
|
|
11138
|
-
_fns.sort = (input, _e, opts) => {
|
|
11139
|
-
const a = Array.isArray(input) ? input.slice() : [];
|
|
11140
|
-
const f = opts.field;
|
|
11141
|
-
const dir = opts.direction === "desc" ? -1 : 1;
|
|
11142
|
-
if (f) return a.sort((x, y) => x[f] > y[f] ? dir : x[f] < y[f] ? -dir : 0);
|
|
11143
|
-
return a.sort((x, y) => x > y ? dir : x < y ? -dir : 0);
|
|
11144
|
-
};
|
|
11145
|
-
_fns.slice = (input, _e, opts) => Array.isArray(input) ? input.slice(opts.start || 0, opts.end) : input;
|
|
11146
|
-
_fns.flat = (input, _e, opts) => {
|
|
11147
|
-
const depth = opts.depth != null ? opts.depth : 1;
|
|
11148
|
-
return Array.isArray(input) ? input.flat(depth) : [input];
|
|
11149
|
-
};
|
|
11150
|
-
_fns.unique = (input) => {
|
|
11151
|
-
if (!Array.isArray(input)) return [input];
|
|
11152
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11153
|
-
return input.filter((v) => {
|
|
11154
|
-
const key = typeof v === "object" ? JSON.stringify(v) : v;
|
|
11155
|
-
if (seen.has(key)) return false;
|
|
11156
|
-
seen.add(key);
|
|
11157
|
-
return true;
|
|
11158
|
-
});
|
|
11159
|
-
};
|
|
11160
|
-
_fns.group = (input, _e, opts) => {
|
|
11161
|
-
const a = Array.isArray(input) ? input : [];
|
|
11162
|
-
const g = {};
|
|
11163
|
-
a.forEach((r) => {
|
|
11164
|
-
const k = String(r[opts.field] || "");
|
|
11165
|
-
if (!g[k]) g[k] = [];
|
|
11166
|
-
g[k].push(r);
|
|
11167
|
-
});
|
|
11168
|
-
return g;
|
|
11169
|
-
};
|
|
11170
|
-
_fns.flatten_keys = (input) => {
|
|
11171
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return [];
|
|
11172
|
-
const result = [];
|
|
11173
|
-
for (const k of Object.keys(input)) {
|
|
11174
|
-
const vals = Array.isArray(input[k]) ? input[k] : [input[k]];
|
|
11175
|
-
vals.forEach((v) => result.push({ key: k, value: v }));
|
|
11176
|
-
}
|
|
11177
|
-
return result;
|
|
11178
|
-
};
|
|
11179
|
-
_fns.entries = (input) => {
|
|
11180
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return [];
|
|
11181
|
-
return Object.keys(input).map((k) => ({ key: k, value: input[k] }));
|
|
11182
|
-
};
|
|
11183
|
-
_fns.from_entries = (input) => {
|
|
11184
|
-
if (!Array.isArray(input)) return {};
|
|
11185
|
-
const obj = {};
|
|
11186
|
-
input.forEach((item) => {
|
|
11187
|
-
if (item.key != null) obj[item.key] = item.value;
|
|
11188
|
-
});
|
|
11189
|
-
return obj;
|
|
11190
|
-
};
|
|
11191
|
-
_fns.length = (input) => {
|
|
11192
|
-
if (Array.isArray(input)) return input.length;
|
|
11193
|
-
if (typeof input === "string") return input.length;
|
|
11194
|
-
if (input && typeof input === "object") return Object.keys(input).length;
|
|
11195
|
-
return 0;
|
|
11196
|
-
};
|
|
11197
|
-
_fns.get = (input, _e, opts) => deepGet(input, opts.field || opts.path || "");
|
|
11198
|
-
_fns.default = (input, _e, opts) => input != null ? input : opts.value;
|
|
11199
|
-
_fns.coalesce = (input) => {
|
|
11200
|
-
const a = Array.isArray(input) ? input : [];
|
|
11201
|
-
for (let i = 0; i < a.length; i++) {
|
|
11202
|
-
if (a[i] != null) return a[i];
|
|
11203
|
-
}
|
|
11204
|
-
return null;
|
|
11205
|
-
};
|
|
11206
|
-
_fns.now = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
11207
|
-
_fns.diff_days = (input) => {
|
|
11208
|
-
const a = Array.isArray(input) ? input : [];
|
|
11209
|
-
return a.length >= 2 ? Math.floor((new Date(a[0]).getTime() - new Date(a[1]).getTime()) / 864e5) : 0;
|
|
11210
|
-
};
|
|
11211
|
-
_fns.format_date = (input, _e, opts) => {
|
|
11212
|
-
try {
|
|
11213
|
-
const d = new Date(input);
|
|
11214
|
-
if (opts.format === "iso") return d.toISOString();
|
|
11215
|
-
if (opts.format === "date") return d.toLocaleDateString();
|
|
11216
|
-
if (opts.format === "time") return d.toLocaleTimeString();
|
|
11217
|
-
return d.toLocaleDateString();
|
|
11218
|
-
} catch {
|
|
11219
|
-
return String(input);
|
|
11220
|
-
}
|
|
11221
|
-
};
|
|
11222
|
-
_fns.parse_date = (input) => {
|
|
11223
|
-
try {
|
|
11224
|
-
return new Date(input).toISOString();
|
|
11225
|
-
} catch {
|
|
11226
|
-
return null;
|
|
11227
|
-
}
|
|
11228
|
-
};
|
|
11229
|
-
_fns.to_number = (input) => Number(input) || 0;
|
|
11230
|
-
_fns.to_string = (input) => input != null ? String(input) : "";
|
|
11231
|
-
_fns.to_bool = (input) => !!input;
|
|
11232
|
-
_fns.type_of = (input) => Array.isArray(input) ? "array" : typeof input;
|
|
11233
|
-
_fns.is_null = (input) => input == null;
|
|
11234
|
-
_fns.is_empty = (input) => {
|
|
11235
|
-
if (input == null) return true;
|
|
11236
|
-
if (Array.isArray(input)) return input.length === 0;
|
|
11237
|
-
if (typeof input === "string") return input.length === 0;
|
|
11238
|
-
if (typeof input === "object") return Object.keys(input).length === 0;
|
|
11239
|
-
return false;
|
|
11240
|
-
};
|
|
11241
|
-
var _customFns = {};
|
|
11242
|
-
function evalExpr(expr, node) {
|
|
11243
|
-
if (expr == null) return expr;
|
|
11244
|
-
if (typeof expr !== "object" || Array.isArray(expr)) return expr;
|
|
11245
|
-
const e = expr;
|
|
11246
|
-
if (!e.fn) return expr;
|
|
11247
|
-
let input = e.input;
|
|
11248
|
-
if (typeof input === "string" && input.startsWith("state.")) {
|
|
11249
|
-
input = deepGet(node, input);
|
|
11250
|
-
} else if (Array.isArray(input)) {
|
|
11251
|
-
input = input.map((v) => {
|
|
11252
|
-
if (typeof v === "string" && v.startsWith("state.")) return deepGet(node, v);
|
|
11253
|
-
if (v && typeof v === "object" && v.fn) return evalExpr(v, node);
|
|
11254
|
-
return v;
|
|
11255
|
-
});
|
|
11256
|
-
} else if (input && typeof input === "object" && input.fn) {
|
|
11257
|
-
input = evalExpr(input, node);
|
|
11258
|
-
}
|
|
11259
|
-
if (e.fn === "if") {
|
|
11260
|
-
const cond = evalExpr(e.cond, node);
|
|
11261
|
-
if (cond) {
|
|
11262
|
-
return e.then && typeof e.then === "object" && e.then.fn ? evalExpr(e.then, node) : e.then;
|
|
11263
|
-
} else {
|
|
11264
|
-
return e.else && typeof e.else === "object" && e.else.fn ? evalExpr(e.else, node) : e.else;
|
|
11265
|
-
}
|
|
11266
|
-
}
|
|
11267
|
-
if (e.fn === "filter" && Array.isArray(input) && e.where) {
|
|
11268
|
-
return input.filter((item) => {
|
|
11269
|
-
const tmp = { state: { ...node.state, $: item } };
|
|
11270
|
-
return evalExpr(e.where, tmp);
|
|
11271
|
-
});
|
|
11272
|
-
}
|
|
11273
|
-
if (e.fn === "map" && Array.isArray(input) && e.apply) {
|
|
11274
|
-
return input.map((item) => {
|
|
11275
|
-
const tmp = { state: { ...node.state, $: item } };
|
|
11276
|
-
return evalExpr(e.apply, tmp);
|
|
11277
|
-
});
|
|
11278
|
-
}
|
|
11279
|
-
const fn = _customFns[e.fn] || _fns[e.fn];
|
|
11280
|
-
if (!fn) {
|
|
11281
|
-
console.warn('CardCompute: unknown function "' + e.fn + '"');
|
|
11282
|
-
return void 0;
|
|
11283
|
-
}
|
|
11284
|
-
return fn(input, evalExpr, e);
|
|
11285
|
-
}
|
|
11286
|
-
function run(node) {
|
|
11287
|
-
if (!node || !node.compute) return node;
|
|
11032
|
+
async function run(node, options) {
|
|
11033
|
+
if (!node?.compute?.length) return node;
|
|
11288
11034
|
if (!node.state) node.state = {};
|
|
11289
|
-
|
|
11035
|
+
node.computed_values = {};
|
|
11036
|
+
node._sourcesData = options?.sourcesData ?? {};
|
|
11037
|
+
const ctx = {
|
|
11038
|
+
state: node.state,
|
|
11039
|
+
requires: node.requires ?? {},
|
|
11040
|
+
sources: node._sourcesData,
|
|
11041
|
+
computed_values: node.computed_values
|
|
11042
|
+
};
|
|
11043
|
+
for (const step of node.compute) {
|
|
11290
11044
|
try {
|
|
11291
|
-
const val =
|
|
11292
|
-
deepSet(node.
|
|
11045
|
+
const val = await jsonata__default.default(step.expr).evaluate(ctx);
|
|
11046
|
+
deepSet(node.computed_values, step.bindTo, val);
|
|
11047
|
+
ctx.computed_values = node.computed_values;
|
|
11293
11048
|
} catch (err) {
|
|
11294
|
-
console.error(`CardCompute.run error on "${node.id
|
|
11049
|
+
console.error(`CardCompute.run error on "${node.id ?? "?"}.${step.bindTo}":`, err);
|
|
11295
11050
|
}
|
|
11296
11051
|
}
|
|
11297
11052
|
return node;
|
|
11298
11053
|
}
|
|
11054
|
+
async function evalExpr(expr, node) {
|
|
11055
|
+
const ctx = {
|
|
11056
|
+
state: node.state ?? {},
|
|
11057
|
+
requires: node.requires ?? {},
|
|
11058
|
+
sources: node._sourcesData ?? {},
|
|
11059
|
+
computed_values: node.computed_values ?? {}
|
|
11060
|
+
};
|
|
11061
|
+
return jsonata__default.default(expr).evaluate(ctx);
|
|
11062
|
+
}
|
|
11299
11063
|
function resolve(node, path) {
|
|
11064
|
+
if (path.startsWith("sources.")) {
|
|
11065
|
+
return deepGet(node._sourcesData ?? {}, path.slice("sources.".length));
|
|
11066
|
+
}
|
|
11300
11067
|
return deepGet(node, path);
|
|
11301
11068
|
}
|
|
11302
|
-
function registerFunction(name, fn) {
|
|
11303
|
-
_customFns[name] = fn;
|
|
11304
|
-
}
|
|
11305
11069
|
var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
11306
11070
|
"metric",
|
|
11307
11071
|
"table",
|
|
@@ -11318,26 +11082,17 @@ var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
|
11318
11082
|
"markdown",
|
|
11319
11083
|
"custom"
|
|
11320
11084
|
]);
|
|
11321
|
-
var VALID_SOURCE_KINDS = /* @__PURE__ */ new Set(["api", "websocket", "static", "llm"]);
|
|
11322
11085
|
var VALID_STATUSES = /* @__PURE__ */ new Set(["fresh", "stale", "loading", "error"]);
|
|
11323
|
-
var
|
|
11324
|
-
var SOURCE_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "source", "state", "compute"]);
|
|
11086
|
+
var ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "meta", "requires", "provides", "view", "state", "compute", "sources"]);
|
|
11325
11087
|
function validateNode(node) {
|
|
11326
11088
|
const errors = [];
|
|
11327
11089
|
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
11328
11090
|
return { ok: false, errors: ["Node must be a non-null object"] };
|
|
11329
11091
|
}
|
|
11330
11092
|
const n = node;
|
|
11331
|
-
if (typeof n.id !== "string" || !n.id)
|
|
11332
|
-
errors.push("id: required, must be a non-empty string");
|
|
11333
|
-
}
|
|
11334
|
-
if (n.type !== "card" && n.type !== "source") {
|
|
11335
|
-
errors.push('type: must be "card" or "source"');
|
|
11336
|
-
return { ok: false, errors };
|
|
11337
|
-
}
|
|
11338
|
-
const allowed = n.type === "card" ? CARD_ALLOWED_KEYS : SOURCE_ALLOWED_KEYS;
|
|
11093
|
+
if (typeof n.id !== "string" || !n.id) errors.push("id: required, must be a non-empty string");
|
|
11339
11094
|
for (const key of Object.keys(n)) {
|
|
11340
|
-
if (!
|
|
11095
|
+
if (!ALLOWED_KEYS.has(key)) errors.push(`Unknown top-level key: "${key}"`);
|
|
11341
11096
|
}
|
|
11342
11097
|
if (n.state == null || typeof n.state !== "object" || Array.isArray(n.state)) {
|
|
11343
11098
|
errors.push("state: required, must be an object");
|
|
@@ -11356,37 +11111,58 @@ function validateNode(node) {
|
|
|
11356
11111
|
if (meta.tags != null && !Array.isArray(meta.tags)) errors.push("meta.tags: must be an array");
|
|
11357
11112
|
}
|
|
11358
11113
|
}
|
|
11359
|
-
if (n.
|
|
11360
|
-
|
|
11361
|
-
|
|
11114
|
+
if (n.requires != null && !Array.isArray(n.requires)) errors.push("requires: must be an array of strings");
|
|
11115
|
+
if (n.provides != null) {
|
|
11116
|
+
if (!Array.isArray(n.provides)) {
|
|
11117
|
+
errors.push("provides: must be an array of { bindTo, src } bindings");
|
|
11362
11118
|
} else {
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11119
|
+
n.provides.forEach((p, i) => {
|
|
11120
|
+
if (!p || typeof p !== "object" || Array.isArray(p)) {
|
|
11121
|
+
errors.push(`provides[${i}]: must be an object with bindTo and src`);
|
|
11122
|
+
} else {
|
|
11123
|
+
const b = p;
|
|
11124
|
+
if (typeof b.bindTo !== "string" || !b.bindTo) errors.push(`provides[${i}]: missing required "bindTo" string`);
|
|
11125
|
+
if (typeof b.src !== "string" || !b.src) errors.push(`provides[${i}]: missing required "src" string`);
|
|
11126
|
+
}
|
|
11127
|
+
});
|
|
11366
11128
|
}
|
|
11367
11129
|
}
|
|
11368
11130
|
if (n.compute != null) {
|
|
11369
|
-
if (
|
|
11370
|
-
errors.push("compute: must be an
|
|
11131
|
+
if (!Array.isArray(n.compute)) {
|
|
11132
|
+
errors.push("compute: must be an array of compute steps");
|
|
11133
|
+
} else {
|
|
11134
|
+
n.compute.forEach((step, i) => {
|
|
11135
|
+
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
11136
|
+
errors.push(`compute[${i}]: must be a compute step object`);
|
|
11137
|
+
} else {
|
|
11138
|
+
const s = step;
|
|
11139
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`compute[${i}]: missing required "bindTo" property`);
|
|
11140
|
+
if (typeof s.expr !== "string" || !s.expr) errors.push(`compute[${i}]: missing required "expr" string (JSONata expression)`);
|
|
11141
|
+
}
|
|
11142
|
+
});
|
|
11143
|
+
}
|
|
11144
|
+
}
|
|
11145
|
+
if (n.sources != null) {
|
|
11146
|
+
if (!Array.isArray(n.sources)) {
|
|
11147
|
+
errors.push("sources: must be an array");
|
|
11371
11148
|
} else {
|
|
11372
|
-
|
|
11373
|
-
if (!
|
|
11374
|
-
errors.push(`
|
|
11375
|
-
} else if (!expr.fn) {
|
|
11376
|
-
errors.push(`compute.${key}: missing required "fn" property`);
|
|
11149
|
+
n.sources.forEach((src, i) => {
|
|
11150
|
+
if (!src || typeof src !== "object" || Array.isArray(src)) {
|
|
11151
|
+
errors.push(`sources[${i}]: must be an object`);
|
|
11377
11152
|
} else {
|
|
11378
|
-
const
|
|
11379
|
-
if (!
|
|
11380
|
-
|
|
11153
|
+
const s = src;
|
|
11154
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`sources[${i}]: missing required "bindTo" property`);
|
|
11155
|
+
if (s.outputFile != null && typeof s.outputFile !== "string") errors.push(`sources[${i}]: outputFile must be a string`);
|
|
11156
|
+
if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
|
|
11157
|
+
errors.push(`sources[${i}]: optionalForCompletionGating must be a boolean`);
|
|
11381
11158
|
}
|
|
11382
11159
|
}
|
|
11383
|
-
}
|
|
11160
|
+
});
|
|
11384
11161
|
}
|
|
11385
11162
|
}
|
|
11386
|
-
if (n.
|
|
11387
|
-
if (n.
|
|
11388
|
-
|
|
11389
|
-
errors.push("view: required for card nodes, must be an object");
|
|
11163
|
+
if (n.view != null) {
|
|
11164
|
+
if (typeof n.view !== "object" || Array.isArray(n.view)) {
|
|
11165
|
+
errors.push("view: must be an object");
|
|
11390
11166
|
} else {
|
|
11391
11167
|
const view = n.view;
|
|
11392
11168
|
if (!Array.isArray(view.elements) || view.elements.length === 0) {
|
|
@@ -11407,28 +11183,8 @@ function validateNode(node) {
|
|
|
11407
11183
|
}
|
|
11408
11184
|
});
|
|
11409
11185
|
}
|
|
11410
|
-
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout)))
|
|
11411
|
-
|
|
11412
|
-
}
|
|
11413
|
-
if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) {
|
|
11414
|
-
errors.push("view.features: must be an object");
|
|
11415
|
-
}
|
|
11416
|
-
}
|
|
11417
|
-
}
|
|
11418
|
-
if (n.type === "source") {
|
|
11419
|
-
if (n.view != null) errors.push('Source nodes must not have "view" \u2014 use type "card" instead');
|
|
11420
|
-
if (n.source == null || typeof n.source !== "object" || Array.isArray(n.source)) {
|
|
11421
|
-
errors.push("source: required for source nodes, must be an object");
|
|
11422
|
-
} else {
|
|
11423
|
-
const src = n.source;
|
|
11424
|
-
if (!src.kind || !VALID_SOURCE_KINDS.has(src.kind)) {
|
|
11425
|
-
errors.push(`source.kind: required, must be one of: ${[...VALID_SOURCE_KINDS].join(", ")}`);
|
|
11426
|
-
}
|
|
11427
|
-
if (typeof src.bindTo !== "string" || !src.bindTo) {
|
|
11428
|
-
errors.push("source.bindTo: required, must be a state path string");
|
|
11429
|
-
} else if (!src.bindTo.startsWith("state.")) {
|
|
11430
|
-
errors.push('source.bindTo: must start with "state."');
|
|
11431
|
-
}
|
|
11186
|
+
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout))) errors.push("view.layout: must be an object");
|
|
11187
|
+
if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) errors.push("view.features: must be an object");
|
|
11432
11188
|
}
|
|
11433
11189
|
}
|
|
11434
11190
|
return { ok: errors.length === 0, errors };
|
|
@@ -11437,14 +11193,7 @@ var CardCompute = {
|
|
|
11437
11193
|
run,
|
|
11438
11194
|
eval: evalExpr,
|
|
11439
11195
|
resolve,
|
|
11440
|
-
validate: validateNode
|
|
11441
|
-
registerFunction,
|
|
11442
|
-
get functions() {
|
|
11443
|
-
const all = {};
|
|
11444
|
-
for (const k of Object.keys(_fns)) all[k] = _fns[k];
|
|
11445
|
-
for (const k of Object.keys(_customFns)) all[k] = _customFns[k];
|
|
11446
|
-
return all;
|
|
11447
|
-
}
|
|
11196
|
+
validate: validateNode
|
|
11448
11197
|
};
|
|
11449
11198
|
|
|
11450
11199
|
// src/continuous-event-graph/live-cards-bridge.ts
|
|
@@ -11477,19 +11226,26 @@ function liveCardsToReactiveGraph(input, options = {}) {
|
|
|
11477
11226
|
}
|
|
11478
11227
|
const sharedState = options.sharedState ?? /* @__PURE__ */ new Map();
|
|
11479
11228
|
const tasks = {};
|
|
11229
|
+
const allTokens = /* @__PURE__ */ new Set();
|
|
11230
|
+
const tokenToCardId = /* @__PURE__ */ new Map();
|
|
11231
|
+
for (const card of cards) {
|
|
11232
|
+
for (const binding of card.provides ?? [{ bindTo: card.id, src: `state.${card.id}` }]) {
|
|
11233
|
+
allTokens.add(binding.bindTo);
|
|
11234
|
+
tokenToCardId.set(binding.bindTo, card.id);
|
|
11235
|
+
}
|
|
11236
|
+
}
|
|
11480
11237
|
for (const card of cards) {
|
|
11481
|
-
const requires = card.
|
|
11238
|
+
const requires = card.requires ?? [];
|
|
11482
11239
|
for (const req of requires) {
|
|
11483
|
-
if (!
|
|
11484
|
-
throw new Error(`Card "${card.id}" requires "${req}" but no card
|
|
11240
|
+
if (!allTokens.has(req)) {
|
|
11241
|
+
throw new Error(`Card "${card.id}" requires "${req}" but no card provides that token`);
|
|
11485
11242
|
}
|
|
11486
11243
|
}
|
|
11487
11244
|
tasks[card.id] = {
|
|
11488
11245
|
requires: requires.length > 0 ? requires : void 0,
|
|
11489
|
-
provides: [card.id],
|
|
11246
|
+
provides: (card.provides ?? [{ bindTo: card.id, src: `state.${card.id}` }]).map((p) => p.bindTo),
|
|
11490
11247
|
taskHandlers: [card.id],
|
|
11491
|
-
|
|
11492
|
-
description: card.meta?.title ?? `${card.type}: ${card.id}`
|
|
11248
|
+
description: card.meta?.title ?? card.id
|
|
11493
11249
|
};
|
|
11494
11250
|
}
|
|
11495
11251
|
const config = {
|
|
@@ -11508,10 +11264,10 @@ function liveCardsToReactiveGraph(input, options = {}) {
|
|
|
11508
11264
|
graphRef.resolveCallback(token, data, errors);
|
|
11509
11265
|
};
|
|
11510
11266
|
for (const card of cards) {
|
|
11511
|
-
if (card.
|
|
11267
|
+
if (card.sources && card.sources.length > 0) {
|
|
11512
11268
|
handlers[card.id] = buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedState, getResolve);
|
|
11513
11269
|
} else {
|
|
11514
|
-
handlers[card.id] = buildCardHandler(card, cardHandlers, sharedState, cardMap, getResolve);
|
|
11270
|
+
handlers[card.id] = buildCardHandler(card, cardHandlers, sharedState, cardMap, tokenToCardId, getResolve);
|
|
11515
11271
|
}
|
|
11516
11272
|
}
|
|
11517
11273
|
const graph = createReactiveGraph(
|
|
@@ -11545,7 +11301,7 @@ function buildSourceHandler(card, sourceHandlers, defaultSourceHandler, sharedSt
|
|
|
11545
11301
|
return "task-initiated";
|
|
11546
11302
|
};
|
|
11547
11303
|
}
|
|
11548
|
-
function buildCardHandler(card, cardHandlers, sharedState,
|
|
11304
|
+
function buildCardHandler(card, cardHandlers, sharedState, _cardMap, tokenToCardId, getResolve) {
|
|
11549
11305
|
if (cardHandlers[card.id]) {
|
|
11550
11306
|
const userHandler = cardHandlers[card.id];
|
|
11551
11307
|
return async (input) => {
|
|
@@ -11553,47 +11309,37 @@ function buildCardHandler(card, cardHandlers, sharedState, cardMap, getResolve)
|
|
|
11553
11309
|
};
|
|
11554
11310
|
}
|
|
11555
11311
|
return async (input) => {
|
|
11312
|
+
const requiresData = {};
|
|
11313
|
+
const requires = card.requires ?? [];
|
|
11314
|
+
for (const token of requires) {
|
|
11315
|
+
const producerId = tokenToCardId.get(token) ?? token;
|
|
11316
|
+
const upstreamState = sharedState.get(producerId);
|
|
11317
|
+
if (upstreamState) {
|
|
11318
|
+
requiresData[token] = upstreamState[token] ?? upstreamState;
|
|
11319
|
+
}
|
|
11320
|
+
}
|
|
11556
11321
|
const computeNode = {
|
|
11557
11322
|
id: card.id,
|
|
11558
11323
|
state: { ...card.state },
|
|
11324
|
+
requires: requiresData,
|
|
11559
11325
|
compute: card.compute
|
|
11560
11326
|
};
|
|
11561
|
-
|
|
11562
|
-
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
const upstreamCard = cardMap.get(upstreamId);
|
|
11568
|
-
if (upstreamCard?.data?.provides && upstreamState) {
|
|
11569
|
-
for (const [key, bindRef] of Object.entries(upstreamCard.data.provides)) {
|
|
11570
|
-
if (typeof bindRef === "string" && bindRef.startsWith("state.")) {
|
|
11571
|
-
const path = bindRef.slice(6);
|
|
11572
|
-
const value = deepGet2(upstreamState, path);
|
|
11573
|
-
if (value !== void 0) {
|
|
11574
|
-
computeNode.state[key] = value;
|
|
11575
|
-
}
|
|
11576
|
-
}
|
|
11577
|
-
}
|
|
11327
|
+
await CardCompute.run(computeNode);
|
|
11328
|
+
let resultData;
|
|
11329
|
+
if (card.provides && card.provides.length > 0) {
|
|
11330
|
+
resultData = {};
|
|
11331
|
+
for (const { bindTo, src } of card.provides) {
|
|
11332
|
+
resultData[bindTo] = CardCompute.resolve(computeNode, src);
|
|
11578
11333
|
}
|
|
11334
|
+
} else {
|
|
11335
|
+
resultData = { ...computeNode.state, ...computeNode.computed_values };
|
|
11579
11336
|
}
|
|
11580
|
-
|
|
11581
|
-
const resultState = { ...computeNode.state };
|
|
11337
|
+
const resultState = { ...computeNode.state, ...computeNode.computed_values };
|
|
11582
11338
|
sharedState.set(card.id, resultState);
|
|
11583
|
-
getResolve()(input.callbackToken,
|
|
11339
|
+
getResolve()(input.callbackToken, resultData);
|
|
11584
11340
|
return "task-initiated";
|
|
11585
11341
|
};
|
|
11586
11342
|
}
|
|
11587
|
-
function deepGet2(obj, path) {
|
|
11588
|
-
if (!path || !obj) return void 0;
|
|
11589
|
-
const parts = path.split(".");
|
|
11590
|
-
let cur = obj;
|
|
11591
|
-
for (const part of parts) {
|
|
11592
|
-
if (cur == null) return void 0;
|
|
11593
|
-
cur = cur[part];
|
|
11594
|
-
}
|
|
11595
|
-
return cur;
|
|
11596
|
-
}
|
|
11597
11343
|
|
|
11598
11344
|
// src/inference/core.ts
|
|
11599
11345
|
var DEFAULT_THRESHOLD = 0.5;
|
|
@@ -11852,7 +11598,6 @@ exports.CardCompute = CardCompute;
|
|
|
11852
11598
|
exports.DEFAULTS = DEFAULTS;
|
|
11853
11599
|
exports.EXECUTION_MODES = EXECUTION_MODES;
|
|
11854
11600
|
exports.EXECUTION_STATUS = EXECUTION_STATUS;
|
|
11855
|
-
exports.FileJournal = FileJournal;
|
|
11856
11601
|
exports.FileStore = FileStore;
|
|
11857
11602
|
exports.FlowEngine = StepMachine;
|
|
11858
11603
|
exports.LocalStorageStore = LocalStorageStore;
|