yaml-flow 3.1.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +81 -20
- package/board-live-cards-cli.js +37 -0
- package/browser/board-livegraph-runtime.js +1453 -0
- package/browser/board-livegraph-runtime.js.map +1 -0
- package/browser/card-compute.js +153 -433
- package/browser/live-cards.js +868 -115
- package/browser/live-cards.schema.json +90 -83
- package/dist/board-livegraph-runtime/index.cjs +1448 -0
- package/dist/board-livegraph-runtime/index.cjs.map +1 -0
- package/dist/board-livegraph-runtime/index.d.cts +101 -0
- package/dist/board-livegraph-runtime/index.d.ts +101 -0
- package/dist/board-livegraph-runtime/index.js +1441 -0
- package/dist/board-livegraph-runtime/index.js.map +1 -0
- package/dist/card-compute/index.cjs +266 -431
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.d.cts +77 -49
- package/dist/card-compute/index.d.ts +77 -49
- package/dist/card-compute/index.js +263 -432
- package/dist/card-compute/index.js.map +1 -1
- package/dist/cli/board-live-cards-cli.cjs +2750 -0
- package/dist/cli/board-live-cards-cli.cjs.map +1 -0
- package/dist/cli/board-live-cards-cli.d.cts +205 -0
- package/dist/cli/board-live-cards-cli.d.ts +205 -0
- package/dist/cli/board-live-cards-cli.js +2702 -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 +258 -464
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.d.cts +18 -358
- package/dist/continuous-event-graph/index.d.ts +18 -358
- package/dist/continuous-event-graph/index.js +255 -464
- 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 +1684 -555
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -7
- package/dist/index.d.ts +26 -7
- package/dist/index.js +1678 -555
- 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-DRfJiheM.d.cts +28 -0
- package/dist/journal-NLYuqege.d.ts +28 -0
- package/dist/live-cards-bridge-Or7fdEJV.d.ts +316 -0
- package/dist/live-cards-bridge-vGJ6tMzN.d.cts +316 -0
- package/dist/schedule-CMcZe5Ny.d.ts +21 -0
- package/dist/schedule-CiucyCan.d.cts +21 -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-task-executor.cjs +96 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.bat +7 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.js +217 -0
- package/examples/browser/livecards-browser/index.html +41 -0
- package/examples/browser/{index.html → step-machine-browser/index.html} +53 -53
- 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/example-board/board.yaml +23 -0
- package/examples/example-board/bootstrap_payload.json +1 -0
- package/examples/example-board/cards/card-chain-region-alert.json +39 -0
- package/examples/example-board/cards/card-chain-region-totals.json +26 -0
- package/examples/example-board/cards/card-chain-top-region.json +24 -0
- package/examples/example-board/cards/card-ex-actions.json +32 -0
- package/examples/example-board/cards/card-ex-chart.json +30 -0
- package/examples/example-board/cards/card-ex-filter.json +36 -0
- package/examples/example-board/cards/card-ex-filtered-by-preference.json +59 -0
- package/examples/example-board/cards/card-ex-form.json +91 -0
- package/examples/example-board/cards/card-ex-list.json +22 -0
- package/examples/example-board/cards/card-ex-markdown.json +17 -0
- package/examples/example-board/cards/card-ex-metric.json +19 -0
- package/examples/example-board/cards/card-ex-narrative.json +36 -0
- package/examples/example-board/cards/card-ex-source-http.json +28 -0
- package/examples/example-board/cards/card-ex-source.json +21 -0
- package/examples/example-board/cards/card-ex-status.json +35 -0
- package/examples/example-board/cards/card-ex-table.json +30 -0
- package/examples/example-board/cards/card-ex-todo.json +29 -0
- package/examples/example-board/demo-chat-handler.js +69 -0
- package/examples/example-board/demo-server.js +87 -0
- package/examples/example-board/demo-shell-browser.html +806 -0
- package/examples/example-board/demo-shell-with-server.html +280 -0
- package/examples/example-board/demo-shell.html +62 -0
- package/examples/example-board/demo-task-executor.js +255 -0
- package/examples/example-board/mock.db +15 -0
- package/examples/example-board/reusable-board-runtime-client.js +265 -0
- package/examples/example-board/reusable-runtime-artifacts-adapter.js +233 -0
- package/examples/example-board/reusable-server-runtime.js +1284 -0
- package/examples/index.html +799 -0
- package/examples/{batch → npm-libs/batch}/batch-step-machine.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-cards-board.ts +18 -18
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/live-portfolio-dashboard.ts +24 -24
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/portfolio-tracker.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-monitoring.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/reactive-pipeline.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/soc-incident-board.ts +1 -1
- package/examples/{continuous-event-graph → npm-libs/continuous-event-graph}/stock-dashboard.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/ci-cd-pipeline.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/executor-diamond.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/executor-pipeline.ts +1 -1
- package/examples/{event-graph → npm-libs/event-graph}/research-pipeline.ts +1 -1
- package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/multi-stage-etl.ts +1 -1
- package/examples/{graph-of-graphs → npm-libs/graph-of-graphs}/url-processing-pipeline.ts +1 -1
- package/examples/{inference → npm-libs/inference}/azure-deployment.ts +1 -1
- package/examples/{inference → npm-libs/inference}/copilot-cli.ts +1 -1
- package/examples/{inference → npm-libs/inference}/data-pipeline.ts +1 -1
- package/examples/{inference → npm-libs/inference}/pluggable-adapters.ts +1 -1
- package/examples/{node → npm-libs/node}/ai-conversation.ts +1 -1
- package/examples/{node → npm-libs/node}/simple-greeting.ts +2 -2
- 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-task-executor.cjs +96 -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 +27 -2
- package/schema/board-status.schema.json +118 -0
- package/schema/card-runtime.schema.json +25 -0
- package/schema/flow.schema.json +5 -0
- package/schema/live-cards.schema.json +90 -83
- package/step-machine-cli.js +674 -0
- package/browser/ingest-board.js +0 -296
- package/examples/ingest.js +0 -733
- /package/examples/{flows → npm-libs/flows}/ai-conversation.yaml +0 -0
- /package/examples/{flows → npm-libs/flows}/order-processing.yaml +0 -0
- /package/examples/{flows → npm-libs/flows}/simple-greeting.yaml +0 -0
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
var jsonata2 = require('jsonata');
|
|
5
6
|
var addFormats = require('ajv-formats');
|
|
6
7
|
|
|
7
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
9
|
|
|
10
|
+
var jsonata2__default = /*#__PURE__*/_interopDefault(jsonata2);
|
|
9
11
|
var addFormats__default = /*#__PURE__*/_interopDefault(addFormats);
|
|
10
12
|
|
|
11
13
|
var __create = Object.create;
|
|
@@ -6423,13 +6425,11 @@ var require_ajv = __commonJS({
|
|
|
6423
6425
|
var live_cards_schema_default = {
|
|
6424
6426
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
6425
6427
|
$id: "https://nsreehari.github.io/boards/live-cards.schema.json",
|
|
6426
|
-
title: "LiveCards Node Schema",
|
|
6427
|
-
description: "Schema for Card and ExternalSource nodes in the LiveCards Board/Canvas engine",
|
|
6428
6428
|
definitions: {
|
|
6429
6429
|
bind_ref: {
|
|
6430
|
-
description: "A
|
|
6430
|
+
description: "A card data path reference, e.g. 'card_data.raw_quotes' or 'requires.upstream'",
|
|
6431
6431
|
type: "string",
|
|
6432
|
-
pattern: "^
|
|
6432
|
+
pattern: "^(card_data|requires|fetched_sources|computed_values)(\\.|$)"
|
|
6433
6433
|
},
|
|
6434
6434
|
bind_or_literal: {
|
|
6435
6435
|
description: "A literal value or a bind reference object",
|
|
@@ -6498,7 +6498,7 @@ var live_cards_schema_default = {
|
|
|
6498
6498
|
]
|
|
6499
6499
|
},
|
|
6500
6500
|
input: {
|
|
6501
|
-
description: "
|
|
6501
|
+
description: "card_data.path, literal, array of inputs, or nested compute_expr",
|
|
6502
6502
|
oneOf: [
|
|
6503
6503
|
{ type: "string" },
|
|
6504
6504
|
{ type: "number" },
|
|
@@ -6522,38 +6522,43 @@ var live_cards_schema_default = {
|
|
|
6522
6522
|
tags: { type: "array", items: { type: "string" } }
|
|
6523
6523
|
}
|
|
6524
6524
|
},
|
|
6525
|
-
|
|
6525
|
+
requires: {
|
|
6526
|
+
type: "array",
|
|
6527
|
+
items: { type: "string" },
|
|
6528
|
+
description: "IDs of upstream nodes this node depends on"
|
|
6529
|
+
},
|
|
6530
|
+
provides: {
|
|
6531
|
+
type: "array",
|
|
6532
|
+
items: {
|
|
6533
|
+
type: "object",
|
|
6534
|
+
required: ["bindTo", "src"],
|
|
6535
|
+
properties: {
|
|
6536
|
+
bindTo: { type: "string", description: "Token name published downstream" },
|
|
6537
|
+
src: { type: "string", description: "Path to read value from (card_data.*, requires.*, fetched_sources.*, computed_values.*)" }
|
|
6538
|
+
}
|
|
6539
|
+
},
|
|
6540
|
+
description: "Explicit bindings exposing computed or card_data values downstream as named tokens"
|
|
6541
|
+
},
|
|
6542
|
+
compute_step: {
|
|
6543
|
+
description: "A single ordered compute step: reads card_data.*/requires.*/computed_values.*, writes to computed_values[bindTo]",
|
|
6526
6544
|
type: "object",
|
|
6545
|
+
required: ["bindTo", "expr"],
|
|
6527
6546
|
properties: {
|
|
6528
|
-
|
|
6529
|
-
|
|
6530
|
-
items: { type: "string" },
|
|
6531
|
-
description: "IDs of upstream nodes this node depends on"
|
|
6532
|
-
},
|
|
6533
|
-
provides: {
|
|
6534
|
-
type: "object",
|
|
6535
|
-
description: "Subset of state exposed downstream. Keys are published names, values are bind refs.",
|
|
6536
|
-
additionalProperties: { $ref: "#/definitions/bind_or_literal" }
|
|
6537
|
-
}
|
|
6547
|
+
bindTo: { type: "string", description: "Key in computed_values to write result" },
|
|
6548
|
+
expr: { type: "string", description: "JSONata expression evaluated against { card_data, requires, fetched_sources, computed_values }" }
|
|
6538
6549
|
}
|
|
6539
6550
|
},
|
|
6540
6551
|
source_def: {
|
|
6552
|
+
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.",
|
|
6541
6553
|
type: "object",
|
|
6542
|
-
required: ["
|
|
6554
|
+
required: ["bindTo"],
|
|
6555
|
+
additionalProperties: true,
|
|
6543
6556
|
properties: {
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
body_template: { type: "object", description: "Request body with {{var}} placeholders or bind refs" },
|
|
6550
|
-
template_vars: {
|
|
6551
|
-
type: "object",
|
|
6552
|
-
additionalProperties: { $ref: "#/definitions/bind_or_literal" },
|
|
6553
|
-
description: "Variables for url/body templates \u2014 static values or bind refs"
|
|
6554
|
-
},
|
|
6555
|
-
poll_interval: { type: "integer", minimum: 0, description: "Auto-refresh in seconds (0 = manual)" },
|
|
6556
|
-
transform: { type: "string", description: "Dot-path to extract from response, e.g. 'data.items'" }
|
|
6557
|
+
bindTo: { type: "string", description: "Key under fetched_sources.* available in compute expressions" },
|
|
6558
|
+
outputFile: { type: "string", description: "Board-relative path the executor writes its JSON result to. Presence of this file signals delivery." },
|
|
6559
|
+
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." },
|
|
6560
|
+
timeout: { type: "integer", minimum: 0, default: 12e4, description: "Executor/script timeout in ms. Default: 120 000 (2 min)." },
|
|
6561
|
+
script: { type: "string", description: "Legacy direct-run: shell command executed when no .task-executor is registered. stdout is captured as the result." }
|
|
6557
6562
|
}
|
|
6558
6563
|
},
|
|
6559
6564
|
render_element: {
|
|
@@ -6577,19 +6582,17 @@ var live_cards_schema_default = {
|
|
|
6577
6582
|
"text",
|
|
6578
6583
|
"markdown",
|
|
6579
6584
|
"custom",
|
|
6580
|
-
"file-upload",
|
|
6581
|
-
"chat",
|
|
6582
6585
|
"actions"
|
|
6583
6586
|
]
|
|
6584
6587
|
},
|
|
6585
6588
|
label: { type: "string", description: "Heading above this element" },
|
|
6586
6589
|
className: { type: "string", description: "Bootstrap grid class, e.g. 'col-12 col-md-6'" },
|
|
6587
|
-
visible: { type: "string", description: "
|
|
6590
|
+
visible: { type: "string", description: "card_data/requires/fetched_sources/computed_values path \u2014 element shown only if truthy" },
|
|
6588
6591
|
data: {
|
|
6589
6592
|
type: "object",
|
|
6590
6593
|
properties: {
|
|
6591
|
-
bind: { $ref: "#/definitions/bind_ref", description: "
|
|
6592
|
-
writeTo: { $ref: "#/definitions/bind_ref", description: "
|
|
6594
|
+
bind: { $ref: "#/definitions/bind_ref", description: "card_data/requires/fetched_sources/computed_values path to read data from" },
|
|
6595
|
+
writeTo: { $ref: "#/definitions/bind_ref", description: "card_data path for user input (form, filter, todo, notes)" },
|
|
6593
6596
|
columns: { type: "array", items: { type: "string" }, description: "table: visible columns" },
|
|
6594
6597
|
maxRows: { type: "integer", description: "table/list: max rows to display" },
|
|
6595
6598
|
sortable: { type: "boolean", default: true, description: "table: enable click-to-sort" },
|
|
@@ -6622,7 +6625,7 @@ var live_cards_schema_default = {
|
|
|
6622
6625
|
label: { type: "string" },
|
|
6623
6626
|
style: { type: "string", description: "Bootstrap button variant, e.g. 'success', 'outline-danger'" },
|
|
6624
6627
|
size: { type: "string", default: "sm" },
|
|
6625
|
-
disabled: { oneOf: [{ type: "boolean" }, { type: "string", description: "
|
|
6628
|
+
disabled: { oneOf: [{ type: "boolean" }, { type: "string", description: "card_data/requires/fetched_sources/computed_values path \u2014 truthy = disabled" }] }
|
|
6626
6629
|
}
|
|
6627
6630
|
}
|
|
6628
6631
|
}
|
|
@@ -6671,69 +6674,118 @@ var live_cards_schema_default = {
|
|
|
6671
6674
|
}
|
|
6672
6675
|
}
|
|
6673
6676
|
},
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6677
|
+
title: "LiveCard",
|
|
6678
|
+
description: "A unified card node. Behavior depends on which sections are present (sources, compute, view, etc.)",
|
|
6679
|
+
type: "object",
|
|
6680
|
+
required: ["id"],
|
|
6681
|
+
additionalProperties: false,
|
|
6682
|
+
properties: {
|
|
6683
|
+
id: { type: "string" },
|
|
6684
|
+
requires: { $ref: "#/definitions/requires" },
|
|
6685
|
+
provides: { $ref: "#/definitions/provides" },
|
|
6686
|
+
meta: { $ref: "#/definitions/meta" },
|
|
6687
|
+
view: { $ref: "#/definitions/view" },
|
|
6688
|
+
card_data: {
|
|
6678
6689
|
type: "object",
|
|
6679
|
-
|
|
6680
|
-
additionalProperties: false,
|
|
6690
|
+
description: "Authored card data supplied in the card definition",
|
|
6681
6691
|
properties: {
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6688
|
-
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
|
|
6692
|
+
files: {
|
|
6693
|
+
type: "array",
|
|
6694
|
+
description: "Optional uploaded-file metadata maintained by host handlers. Stored name is normalized and serial-prefixed (for example 001-my_file.pdf).",
|
|
6695
|
+
items: {
|
|
6696
|
+
type: "object",
|
|
6697
|
+
required: ["name", "stored_name"],
|
|
6698
|
+
properties: {
|
|
6699
|
+
name: { type: "string", minLength: 1 },
|
|
6700
|
+
stored_name: {
|
|
6701
|
+
type: "string",
|
|
6702
|
+
minLength: 5,
|
|
6703
|
+
maxLength: 32,
|
|
6704
|
+
pattern: "^[0-9]{3,}-[a-z0-9._-]+$"
|
|
6705
|
+
},
|
|
6706
|
+
size: {
|
|
6707
|
+
oneOf: [
|
|
6708
|
+
{ type: "integer", minimum: 0 },
|
|
6709
|
+
{ type: "null" }
|
|
6710
|
+
]
|
|
6711
|
+
},
|
|
6712
|
+
mime_type: { type: "string" },
|
|
6713
|
+
path: { type: "string", pattern: "^[^\\s]+/files/[0-9]{3,}-[a-z0-9._-]+$" },
|
|
6714
|
+
uploaded_at: { type: "string", format: "date-time" }
|
|
6715
|
+
},
|
|
6716
|
+
additionalProperties: false
|
|
6694
6717
|
}
|
|
6695
|
-
},
|
|
6696
|
-
compute: {
|
|
6697
|
-
type: "object",
|
|
6698
|
-
description: "Derived state: key = state path to write, value = compute_expr",
|
|
6699
|
-
additionalProperties: { $ref: "#/definitions/compute_expr" }
|
|
6700
6718
|
}
|
|
6701
|
-
}
|
|
6719
|
+
},
|
|
6720
|
+
additionalProperties: true
|
|
6702
6721
|
},
|
|
6703
|
-
{
|
|
6704
|
-
|
|
6705
|
-
description: "
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
meta: { $ref: "#/definitions/meta" },
|
|
6713
|
-
data: { $ref: "#/definitions/data" },
|
|
6714
|
-
source: { $ref: "#/definitions/source_def" },
|
|
6715
|
-
state: {
|
|
6716
|
-
type: "object",
|
|
6717
|
-
additionalProperties: true,
|
|
6718
|
-
properties: {
|
|
6719
|
-
status: { enum: ["fresh", "stale", "loading", "error"] },
|
|
6720
|
-
lastRun: { type: "string", format: "date-time" },
|
|
6721
|
-
error: { type: "string" }
|
|
6722
|
-
}
|
|
6723
|
-
},
|
|
6724
|
-
compute: {
|
|
6725
|
-
type: "object",
|
|
6726
|
-
description: "Derived state: key = state path to write, value = compute_expr",
|
|
6727
|
-
additionalProperties: { $ref: "#/definitions/compute_expr" }
|
|
6728
|
-
}
|
|
6729
|
-
}
|
|
6722
|
+
sources: {
|
|
6723
|
+
type: "array",
|
|
6724
|
+
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.",
|
|
6725
|
+
items: { $ref: "#/definitions/source_def" }
|
|
6726
|
+
},
|
|
6727
|
+
compute: {
|
|
6728
|
+
type: "array",
|
|
6729
|
+
description: "Ordered array of compute steps. Each reads card_data.*/requires.*/fetched_sources.*/computed_values.* and writes to ephemeral computed_values[bindTo].",
|
|
6730
|
+
items: { $ref: "#/definitions/compute_step" }
|
|
6730
6731
|
}
|
|
6731
|
-
|
|
6732
|
+
}
|
|
6732
6733
|
};
|
|
6733
6734
|
|
|
6734
6735
|
// src/card-compute/schema-validator.ts
|
|
6735
6736
|
var import_ajv = __toESM(require_ajv());
|
|
6736
6737
|
var _compiled = null;
|
|
6738
|
+
var NAMESPACE_REFERENCE_RE = /\b(card_data|requires|fetched_sources|computed_values|sources)\b/g;
|
|
6739
|
+
var ROOT_PATH_NAMESPACE_RE = /^\s*(card_data|requires|fetched_sources|computed_values|sources)(\.|$)/;
|
|
6740
|
+
function referencedNamespaces(expression) {
|
|
6741
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
6742
|
+
let match;
|
|
6743
|
+
NAMESPACE_REFERENCE_RE.lastIndex = 0;
|
|
6744
|
+
while ((match = NAMESPACE_REFERENCE_RE.exec(expression)) !== null) {
|
|
6745
|
+
namespaces.add(match[1]);
|
|
6746
|
+
}
|
|
6747
|
+
return namespaces;
|
|
6748
|
+
}
|
|
6749
|
+
function parseRootPathNamespace(pathValue) {
|
|
6750
|
+
const match = ROOT_PATH_NAMESPACE_RE.exec(pathValue);
|
|
6751
|
+
return match ? match[1] : null;
|
|
6752
|
+
}
|
|
6753
|
+
function validateJsonataExprWithNamespaces(expr, path, allowedNamespaces, errors) {
|
|
6754
|
+
try {
|
|
6755
|
+
jsonata2__default.default(expr);
|
|
6756
|
+
} catch (err) {
|
|
6757
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6758
|
+
errors.push(`${path}: invalid JSONata expression (${message})`);
|
|
6759
|
+
return;
|
|
6760
|
+
}
|
|
6761
|
+
const usedNamespaces = referencedNamespaces(expr);
|
|
6762
|
+
for (const namespace of usedNamespaces) {
|
|
6763
|
+
if (!allowedNamespaces.has(namespace)) {
|
|
6764
|
+
errors.push(`${path}: disallowed namespace "${namespace}" in expression`);
|
|
6765
|
+
}
|
|
6766
|
+
}
|
|
6767
|
+
}
|
|
6768
|
+
function walkViewPathReferences(value, path, errors) {
|
|
6769
|
+
if (Array.isArray(value)) {
|
|
6770
|
+
value.forEach((entry, index) => {
|
|
6771
|
+
walkViewPathReferences(entry, `${path}/${index}`, errors);
|
|
6772
|
+
});
|
|
6773
|
+
return;
|
|
6774
|
+
}
|
|
6775
|
+
if (typeof value === "string") {
|
|
6776
|
+
const rootNamespace = parseRootPathNamespace(value);
|
|
6777
|
+
if (!rootNamespace) return;
|
|
6778
|
+
if (!(/* @__PURE__ */ new Set(["card_data", "requires", "fetched_sources", "computed_values"])).has(rootNamespace)) {
|
|
6779
|
+
errors.push(`${path}: disallowed namespace "${rootNamespace}" in view reference`);
|
|
6780
|
+
}
|
|
6781
|
+
return;
|
|
6782
|
+
}
|
|
6783
|
+
if (!value || typeof value !== "object") return;
|
|
6784
|
+
const record = value;
|
|
6785
|
+
for (const [key, next] of Object.entries(record)) {
|
|
6786
|
+
walkViewPathReferences(next, `${path}/${key}`, errors);
|
|
6787
|
+
}
|
|
6788
|
+
}
|
|
6737
6789
|
function getValidator() {
|
|
6738
6790
|
if (_compiled) return _compiled;
|
|
6739
6791
|
const ajv = new import_ajv.default({ allErrors: true });
|
|
@@ -6751,6 +6803,42 @@ function validateLiveCardSchema(node) {
|
|
|
6751
6803
|
});
|
|
6752
6804
|
return { ok: false, errors };
|
|
6753
6805
|
}
|
|
6806
|
+
function validateLiveCardRuntimeExpressions(node) {
|
|
6807
|
+
const errors = [];
|
|
6808
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
6809
|
+
return { ok: true, errors: [] };
|
|
6810
|
+
}
|
|
6811
|
+
const asRecord = node;
|
|
6812
|
+
const compute = asRecord.compute;
|
|
6813
|
+
if (Array.isArray(compute)) {
|
|
6814
|
+
compute.forEach((step, i) => {
|
|
6815
|
+
if (!step || typeof step !== "object" || Array.isArray(step)) return;
|
|
6816
|
+
const expr = step.expr;
|
|
6817
|
+
if (typeof expr !== "string" || expr.trim().length === 0) return;
|
|
6818
|
+
validateJsonataExprWithNamespaces(
|
|
6819
|
+
expr,
|
|
6820
|
+
`/compute/${i}/expr`,
|
|
6821
|
+
/* @__PURE__ */ new Set(["card_data", "requires", "fetched_sources", "computed_values"]),
|
|
6822
|
+
errors
|
|
6823
|
+
);
|
|
6824
|
+
});
|
|
6825
|
+
}
|
|
6826
|
+
const view = asRecord.view;
|
|
6827
|
+
if (view && typeof view === "object" && !Array.isArray(view)) {
|
|
6828
|
+
walkViewPathReferences(view, "/view", errors);
|
|
6829
|
+
}
|
|
6830
|
+
return { ok: errors.length === 0, errors };
|
|
6831
|
+
}
|
|
6832
|
+
function validateLiveCard(node) {
|
|
6833
|
+
return validateLiveCardDefinition(node);
|
|
6834
|
+
}
|
|
6835
|
+
function validateLiveCardDefinition(node) {
|
|
6836
|
+
const schema = validateLiveCardSchema(node);
|
|
6837
|
+
if (!schema.ok) return schema;
|
|
6838
|
+
const runtime = validateLiveCardRuntimeExpressions(node);
|
|
6839
|
+
if (!runtime.ok) return { ok: false, errors: runtime.errors };
|
|
6840
|
+
return { ok: true, errors: [] };
|
|
6841
|
+
}
|
|
6754
6842
|
|
|
6755
6843
|
// src/card-compute/index.ts
|
|
6756
6844
|
function deepGet(obj, path) {
|
|
@@ -6772,288 +6860,43 @@ function deepSet(obj, path, value) {
|
|
|
6772
6860
|
}
|
|
6773
6861
|
cur[parts[parts.length - 1]] = value;
|
|
6774
6862
|
}
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
};
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
const
|
|
6787
|
-
const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
|
|
6788
|
-
return vals.length ? Math.min(...vals) : 0;
|
|
6789
|
-
};
|
|
6790
|
-
_fns.max = (input, _e, opts) => {
|
|
6791
|
-
const a = Array.isArray(input) ? input : [];
|
|
6792
|
-
const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
|
|
6793
|
-
return vals.length ? Math.max(...vals) : 0;
|
|
6794
|
-
};
|
|
6795
|
-
_fns.count = (input) => Array.isArray(input) ? input.length : input != null ? 1 : 0;
|
|
6796
|
-
_fns.first = (input) => Array.isArray(input) ? input[0] : input;
|
|
6797
|
-
_fns.last = (input) => Array.isArray(input) ? input[input.length - 1] : input;
|
|
6798
|
-
_fns.add = (input) => {
|
|
6799
|
-
const a = Array.isArray(input) ? input : [];
|
|
6800
|
-
return a.reduce((s, v) => s + Number(v), 0);
|
|
6801
|
-
};
|
|
6802
|
-
_fns.sub = (input) => {
|
|
6803
|
-
const a = Array.isArray(input) ? input : [];
|
|
6804
|
-
return a.length >= 2 ? Number(a[0]) - Number(a[1]) : 0;
|
|
6805
|
-
};
|
|
6806
|
-
_fns.mul = (input) => {
|
|
6807
|
-
const a = Array.isArray(input) ? input : [];
|
|
6808
|
-
return a.reduce((s, v) => s * Number(v), 1);
|
|
6809
|
-
};
|
|
6810
|
-
_fns.div = (input) => {
|
|
6811
|
-
const a = Array.isArray(input) ? input : [];
|
|
6812
|
-
return a.length >= 2 && Number(a[1]) !== 0 ? Number(a[0]) / Number(a[1]) : 0;
|
|
6813
|
-
};
|
|
6814
|
-
_fns.round = (input, _e, opts) => {
|
|
6815
|
-
const decimals = opts.decimals != null ? opts.decimals : 0;
|
|
6816
|
-
const factor = Math.pow(10, decimals);
|
|
6817
|
-
return Math.round(Number(input) * factor) / factor;
|
|
6818
|
-
};
|
|
6819
|
-
_fns.abs = (input) => Math.abs(Number(input));
|
|
6820
|
-
_fns.mod = (input) => {
|
|
6821
|
-
const a = Array.isArray(input) ? input : [];
|
|
6822
|
-
return a.length >= 2 ? Number(a[0]) % Number(a[1]) : 0;
|
|
6823
|
-
};
|
|
6824
|
-
_fns.gt = (input) => {
|
|
6825
|
-
const a = Array.isArray(input) ? input : [];
|
|
6826
|
-
return a.length >= 2 && Number(a[0]) > Number(a[1]);
|
|
6827
|
-
};
|
|
6828
|
-
_fns.gte = (input) => {
|
|
6829
|
-
const a = Array.isArray(input) ? input : [];
|
|
6830
|
-
return a.length >= 2 && Number(a[0]) >= Number(a[1]);
|
|
6831
|
-
};
|
|
6832
|
-
_fns.lt = (input) => {
|
|
6833
|
-
const a = Array.isArray(input) ? input : [];
|
|
6834
|
-
return a.length >= 2 && Number(a[0]) < Number(a[1]);
|
|
6835
|
-
};
|
|
6836
|
-
_fns.lte = (input) => {
|
|
6837
|
-
const a = Array.isArray(input) ? input : [];
|
|
6838
|
-
return a.length >= 2 && Number(a[0]) <= Number(a[1]);
|
|
6839
|
-
};
|
|
6840
|
-
_fns.eq = (input) => {
|
|
6841
|
-
const a = Array.isArray(input) ? input : [];
|
|
6842
|
-
return a.length >= 2 && a[0] === a[1];
|
|
6843
|
-
};
|
|
6844
|
-
_fns.neq = (input) => {
|
|
6845
|
-
const a = Array.isArray(input) ? input : [];
|
|
6846
|
-
return a.length >= 2 && a[0] !== a[1];
|
|
6847
|
-
};
|
|
6848
|
-
_fns.and = (input) => {
|
|
6849
|
-
const a = Array.isArray(input) ? input : [];
|
|
6850
|
-
return a.every(Boolean);
|
|
6851
|
-
};
|
|
6852
|
-
_fns.or = (input) => {
|
|
6853
|
-
const a = Array.isArray(input) ? input : [];
|
|
6854
|
-
return a.some(Boolean);
|
|
6855
|
-
};
|
|
6856
|
-
_fns.not = (input) => !input;
|
|
6857
|
-
_fns.concat = (input) => {
|
|
6858
|
-
const a = Array.isArray(input) ? input : [];
|
|
6859
|
-
return a.map((v) => v != null ? String(v) : "").join("");
|
|
6860
|
-
};
|
|
6861
|
-
_fns.upper = (input) => String(input || "").toUpperCase();
|
|
6862
|
-
_fns.lower = (input) => String(input || "").toLowerCase();
|
|
6863
|
-
_fns.template = (input, _e, opts) => {
|
|
6864
|
-
let t = String(opts.format || "");
|
|
6865
|
-
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
6866
|
-
for (const k of Object.keys(input)) {
|
|
6867
|
-
const v = input[k];
|
|
6868
|
-
t = t.split("{{" + k + "}}").join(v != null ? String(v) : "");
|
|
6869
|
-
}
|
|
6870
|
-
}
|
|
6871
|
-
return t;
|
|
6872
|
-
};
|
|
6873
|
-
_fns.join = (input, _e, opts) => {
|
|
6874
|
-
const a = Array.isArray(input) ? input : [];
|
|
6875
|
-
const sep = opts.separator != null ? String(opts.separator) : ", ";
|
|
6876
|
-
return a.map((v) => v != null ? String(v) : "").join(sep);
|
|
6877
|
-
};
|
|
6878
|
-
_fns.split = (input, _e, opts) => {
|
|
6879
|
-
const sep = opts.separator != null ? String(opts.separator) : ",";
|
|
6880
|
-
return String(input || "").split(sep).map((s) => s.trim());
|
|
6881
|
-
};
|
|
6882
|
-
_fns.trim = (input) => String(input || "").trim();
|
|
6883
|
-
_fns.pluck = (input, _e, opts) => Array.isArray(input) ? input.map((r) => r[opts.field]) : [];
|
|
6884
|
-
_fns.filter = (input, _e, opts) => {
|
|
6885
|
-
if (!Array.isArray(input)) return [];
|
|
6886
|
-
if (opts.field) return input.filter((r) => !!r[opts.field]);
|
|
6887
|
-
return input.filter(Boolean);
|
|
6888
|
-
};
|
|
6889
|
-
_fns.map = (input) => Array.isArray(input) ? input.slice() : [];
|
|
6890
|
-
_fns.sort = (input, _e, opts) => {
|
|
6891
|
-
const a = Array.isArray(input) ? input.slice() : [];
|
|
6892
|
-
const f = opts.field;
|
|
6893
|
-
const dir = opts.direction === "desc" ? -1 : 1;
|
|
6894
|
-
if (f) return a.sort((x, y) => x[f] > y[f] ? dir : x[f] < y[f] ? -dir : 0);
|
|
6895
|
-
return a.sort((x, y) => x > y ? dir : x < y ? -dir : 0);
|
|
6896
|
-
};
|
|
6897
|
-
_fns.slice = (input, _e, opts) => Array.isArray(input) ? input.slice(opts.start || 0, opts.end) : input;
|
|
6898
|
-
_fns.flat = (input, _e, opts) => {
|
|
6899
|
-
const depth = opts.depth != null ? opts.depth : 1;
|
|
6900
|
-
return Array.isArray(input) ? input.flat(depth) : [input];
|
|
6901
|
-
};
|
|
6902
|
-
_fns.unique = (input) => {
|
|
6903
|
-
if (!Array.isArray(input)) return [input];
|
|
6904
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6905
|
-
return input.filter((v) => {
|
|
6906
|
-
const key = typeof v === "object" ? JSON.stringify(v) : v;
|
|
6907
|
-
if (seen.has(key)) return false;
|
|
6908
|
-
seen.add(key);
|
|
6909
|
-
return true;
|
|
6910
|
-
});
|
|
6911
|
-
};
|
|
6912
|
-
_fns.group = (input, _e, opts) => {
|
|
6913
|
-
const a = Array.isArray(input) ? input : [];
|
|
6914
|
-
const g = {};
|
|
6915
|
-
a.forEach((r) => {
|
|
6916
|
-
const k = String(r[opts.field] || "");
|
|
6917
|
-
if (!g[k]) g[k] = [];
|
|
6918
|
-
g[k].push(r);
|
|
6919
|
-
});
|
|
6920
|
-
return g;
|
|
6921
|
-
};
|
|
6922
|
-
_fns.flatten_keys = (input) => {
|
|
6923
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return [];
|
|
6924
|
-
const result = [];
|
|
6925
|
-
for (const k of Object.keys(input)) {
|
|
6926
|
-
const vals = Array.isArray(input[k]) ? input[k] : [input[k]];
|
|
6927
|
-
vals.forEach((v) => result.push({ key: k, value: v }));
|
|
6928
|
-
}
|
|
6929
|
-
return result;
|
|
6930
|
-
};
|
|
6931
|
-
_fns.entries = (input) => {
|
|
6932
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return [];
|
|
6933
|
-
return Object.keys(input).map((k) => ({ key: k, value: input[k] }));
|
|
6934
|
-
};
|
|
6935
|
-
_fns.from_entries = (input) => {
|
|
6936
|
-
if (!Array.isArray(input)) return {};
|
|
6937
|
-
const obj = {};
|
|
6938
|
-
input.forEach((item) => {
|
|
6939
|
-
if (item.key != null) obj[item.key] = item.value;
|
|
6940
|
-
});
|
|
6941
|
-
return obj;
|
|
6942
|
-
};
|
|
6943
|
-
_fns.length = (input) => {
|
|
6944
|
-
if (Array.isArray(input)) return input.length;
|
|
6945
|
-
if (typeof input === "string") return input.length;
|
|
6946
|
-
if (input && typeof input === "object") return Object.keys(input).length;
|
|
6947
|
-
return 0;
|
|
6948
|
-
};
|
|
6949
|
-
_fns.get = (input, _e, opts) => deepGet(input, opts.field || opts.path || "");
|
|
6950
|
-
_fns.default = (input, _e, opts) => input != null ? input : opts.value;
|
|
6951
|
-
_fns.coalesce = (input) => {
|
|
6952
|
-
const a = Array.isArray(input) ? input : [];
|
|
6953
|
-
for (let i = 0; i < a.length; i++) {
|
|
6954
|
-
if (a[i] != null) return a[i];
|
|
6955
|
-
}
|
|
6956
|
-
return null;
|
|
6957
|
-
};
|
|
6958
|
-
_fns.now = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
6959
|
-
_fns.diff_days = (input) => {
|
|
6960
|
-
const a = Array.isArray(input) ? input : [];
|
|
6961
|
-
return a.length >= 2 ? Math.floor((new Date(a[0]).getTime() - new Date(a[1]).getTime()) / 864e5) : 0;
|
|
6962
|
-
};
|
|
6963
|
-
_fns.format_date = (input, _e, opts) => {
|
|
6964
|
-
try {
|
|
6965
|
-
const d = new Date(input);
|
|
6966
|
-
if (opts.format === "iso") return d.toISOString();
|
|
6967
|
-
if (opts.format === "date") return d.toLocaleDateString();
|
|
6968
|
-
if (opts.format === "time") return d.toLocaleTimeString();
|
|
6969
|
-
return d.toLocaleDateString();
|
|
6970
|
-
} catch {
|
|
6971
|
-
return String(input);
|
|
6972
|
-
}
|
|
6973
|
-
};
|
|
6974
|
-
_fns.parse_date = (input) => {
|
|
6975
|
-
try {
|
|
6976
|
-
return new Date(input).toISOString();
|
|
6977
|
-
} catch {
|
|
6978
|
-
return null;
|
|
6979
|
-
}
|
|
6980
|
-
};
|
|
6981
|
-
_fns.to_number = (input) => Number(input) || 0;
|
|
6982
|
-
_fns.to_string = (input) => input != null ? String(input) : "";
|
|
6983
|
-
_fns.to_bool = (input) => !!input;
|
|
6984
|
-
_fns.type_of = (input) => Array.isArray(input) ? "array" : typeof input;
|
|
6985
|
-
_fns.is_null = (input) => input == null;
|
|
6986
|
-
_fns.is_empty = (input) => {
|
|
6987
|
-
if (input == null) return true;
|
|
6988
|
-
if (Array.isArray(input)) return input.length === 0;
|
|
6989
|
-
if (typeof input === "string") return input.length === 0;
|
|
6990
|
-
if (typeof input === "object") return Object.keys(input).length === 0;
|
|
6991
|
-
return false;
|
|
6992
|
-
};
|
|
6993
|
-
var _customFns = {};
|
|
6994
|
-
function evalExpr(expr, node) {
|
|
6995
|
-
if (expr == null) return expr;
|
|
6996
|
-
if (typeof expr !== "object" || Array.isArray(expr)) return expr;
|
|
6997
|
-
const e = expr;
|
|
6998
|
-
if (!e.fn) return expr;
|
|
6999
|
-
let input = e.input;
|
|
7000
|
-
if (typeof input === "string" && input.startsWith("state.")) {
|
|
7001
|
-
input = deepGet(node, input);
|
|
7002
|
-
} else if (Array.isArray(input)) {
|
|
7003
|
-
input = input.map((v) => {
|
|
7004
|
-
if (typeof v === "string" && v.startsWith("state.")) return deepGet(node, v);
|
|
7005
|
-
if (v && typeof v === "object" && v.fn) return evalExpr(v, node);
|
|
7006
|
-
return v;
|
|
7007
|
-
});
|
|
7008
|
-
} else if (input && typeof input === "object" && input.fn) {
|
|
7009
|
-
input = evalExpr(input, node);
|
|
7010
|
-
}
|
|
7011
|
-
if (e.fn === "if") {
|
|
7012
|
-
const cond = evalExpr(e.cond, node);
|
|
7013
|
-
if (cond) {
|
|
7014
|
-
return e.then && typeof e.then === "object" && e.then.fn ? evalExpr(e.then, node) : e.then;
|
|
7015
|
-
} else {
|
|
7016
|
-
return e.else && typeof e.else === "object" && e.else.fn ? evalExpr(e.else, node) : e.else;
|
|
7017
|
-
}
|
|
7018
|
-
}
|
|
7019
|
-
if (e.fn === "filter" && Array.isArray(input) && e.where) {
|
|
7020
|
-
return input.filter((item) => {
|
|
7021
|
-
const tmp = { state: { ...node.state, $: item } };
|
|
7022
|
-
return evalExpr(e.where, tmp);
|
|
7023
|
-
});
|
|
7024
|
-
}
|
|
7025
|
-
if (e.fn === "map" && Array.isArray(input) && e.apply) {
|
|
7026
|
-
return input.map((item) => {
|
|
7027
|
-
const tmp = { state: { ...node.state, $: item } };
|
|
7028
|
-
return evalExpr(e.apply, tmp);
|
|
7029
|
-
});
|
|
7030
|
-
}
|
|
7031
|
-
const fn = _customFns[e.fn] || _fns[e.fn];
|
|
7032
|
-
if (!fn) {
|
|
7033
|
-
console.warn('CardCompute: unknown function "' + e.fn + '"');
|
|
7034
|
-
return void 0;
|
|
7035
|
-
}
|
|
7036
|
-
return fn(input, evalExpr, e);
|
|
7037
|
-
}
|
|
7038
|
-
function run(node) {
|
|
7039
|
-
if (!node || !node.compute) return node;
|
|
7040
|
-
if (!node.state) node.state = {};
|
|
7041
|
-
for (const key of Object.keys(node.compute)) {
|
|
6863
|
+
async function run(node, options) {
|
|
6864
|
+
if (!node?.compute?.length) return node;
|
|
6865
|
+
if (!node.card_data) node.card_data = {};
|
|
6866
|
+
node.computed_values = {};
|
|
6867
|
+
node._sourcesData = options?.sourcesData ?? {};
|
|
6868
|
+
const ctx = {
|
|
6869
|
+
card_data: node.card_data,
|
|
6870
|
+
requires: node.requires ?? {},
|
|
6871
|
+
fetched_sources: node._sourcesData,
|
|
6872
|
+
computed_values: node.computed_values
|
|
6873
|
+
};
|
|
6874
|
+
for (const step of node.compute) {
|
|
7042
6875
|
try {
|
|
7043
|
-
const val =
|
|
7044
|
-
deepSet(node.
|
|
6876
|
+
const val = await jsonata2__default.default(step.expr).evaluate(ctx);
|
|
6877
|
+
deepSet(node.computed_values, step.bindTo, val);
|
|
6878
|
+
ctx.computed_values = node.computed_values;
|
|
7045
6879
|
} catch (err) {
|
|
7046
|
-
console.error(`CardCompute.run error on "${node.id
|
|
6880
|
+
console.error(`CardCompute.run error on "${node.id ?? "?"}.${step.bindTo}":`, err);
|
|
7047
6881
|
}
|
|
7048
6882
|
}
|
|
7049
6883
|
return node;
|
|
7050
6884
|
}
|
|
6885
|
+
async function evalExpr(expr, node) {
|
|
6886
|
+
const ctx = {
|
|
6887
|
+
card_data: node.card_data ?? {},
|
|
6888
|
+
requires: node.requires ?? {},
|
|
6889
|
+
fetched_sources: node._sourcesData ?? {},
|
|
6890
|
+
computed_values: node.computed_values ?? {}
|
|
6891
|
+
};
|
|
6892
|
+
return jsonata2__default.default(expr).evaluate(ctx);
|
|
6893
|
+
}
|
|
7051
6894
|
function resolve(node, path) {
|
|
6895
|
+
if (path.startsWith("fetched_sources.")) {
|
|
6896
|
+
return deepGet(node._sourcesData ?? {}, path.slice("fetched_sources.".length));
|
|
6897
|
+
}
|
|
7052
6898
|
return deepGet(node, path);
|
|
7053
6899
|
}
|
|
7054
|
-
function registerFunction(name, fn) {
|
|
7055
|
-
_customFns[name] = fn;
|
|
7056
|
-
}
|
|
7057
6900
|
var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
7058
6901
|
"metric",
|
|
7059
6902
|
"table",
|
|
@@ -7070,34 +6913,19 @@ var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
|
7070
6913
|
"markdown",
|
|
7071
6914
|
"custom"
|
|
7072
6915
|
]);
|
|
7073
|
-
var
|
|
7074
|
-
var VALID_STATUSES = /* @__PURE__ */ new Set(["fresh", "stale", "loading", "error"]);
|
|
7075
|
-
var CARD_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "view", "state", "compute"]);
|
|
7076
|
-
var SOURCE_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "source", "state", "compute"]);
|
|
6916
|
+
var ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "meta", "requires", "provides", "view", "card_data", "compute", "sources"]);
|
|
7077
6917
|
function validateNode(node) {
|
|
7078
6918
|
const errors = [];
|
|
7079
6919
|
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
7080
6920
|
return { ok: false, errors: ["Node must be a non-null object"] };
|
|
7081
6921
|
}
|
|
7082
6922
|
const n = node;
|
|
7083
|
-
if (typeof n.id !== "string" || !n.id)
|
|
7084
|
-
errors.push("id: required, must be a non-empty string");
|
|
7085
|
-
}
|
|
7086
|
-
if (n.type !== "card" && n.type !== "source") {
|
|
7087
|
-
errors.push('type: must be "card" or "source"');
|
|
7088
|
-
return { ok: false, errors };
|
|
7089
|
-
}
|
|
7090
|
-
const allowed = n.type === "card" ? CARD_ALLOWED_KEYS : SOURCE_ALLOWED_KEYS;
|
|
6923
|
+
if (typeof n.id !== "string" || !n.id) errors.push("id: required, must be a non-empty string");
|
|
7091
6924
|
for (const key of Object.keys(n)) {
|
|
7092
|
-
if (!
|
|
6925
|
+
if (!ALLOWED_KEYS.has(key)) errors.push(`Unknown top-level key: "${key}"`);
|
|
7093
6926
|
}
|
|
7094
|
-
if (n.
|
|
7095
|
-
errors.push("
|
|
7096
|
-
} else {
|
|
7097
|
-
const state = n.state;
|
|
7098
|
-
if (state.status != null && !VALID_STATUSES.has(state.status)) {
|
|
7099
|
-
errors.push(`state.status: must be one of: ${[...VALID_STATUSES].join(", ")}`);
|
|
7100
|
-
}
|
|
6927
|
+
if (n.card_data == null || typeof n.card_data !== "object" || Array.isArray(n.card_data)) {
|
|
6928
|
+
errors.push("card_data: required, must be an object");
|
|
7101
6929
|
}
|
|
7102
6930
|
if (n.meta != null) {
|
|
7103
6931
|
if (typeof n.meta !== "object" || Array.isArray(n.meta)) {
|
|
@@ -7108,37 +6936,58 @@ function validateNode(node) {
|
|
|
7108
6936
|
if (meta.tags != null && !Array.isArray(meta.tags)) errors.push("meta.tags: must be an array");
|
|
7109
6937
|
}
|
|
7110
6938
|
}
|
|
7111
|
-
if (n.
|
|
7112
|
-
|
|
7113
|
-
|
|
6939
|
+
if (n.requires != null && !Array.isArray(n.requires)) errors.push("requires: must be an array of strings");
|
|
6940
|
+
if (n.provides != null) {
|
|
6941
|
+
if (!Array.isArray(n.provides)) {
|
|
6942
|
+
errors.push("provides: must be an array of { bindTo, src } bindings");
|
|
7114
6943
|
} else {
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
6944
|
+
n.provides.forEach((p, i) => {
|
|
6945
|
+
if (!p || typeof p !== "object" || Array.isArray(p)) {
|
|
6946
|
+
errors.push(`provides[${i}]: must be an object with bindTo and src`);
|
|
6947
|
+
} else {
|
|
6948
|
+
const b = p;
|
|
6949
|
+
if (typeof b.bindTo !== "string" || !b.bindTo) errors.push(`provides[${i}]: missing required "bindTo" string`);
|
|
6950
|
+
if (typeof b.src !== "string" || !b.src) errors.push(`provides[${i}]: missing required "src" string`);
|
|
6951
|
+
}
|
|
6952
|
+
});
|
|
7118
6953
|
}
|
|
7119
6954
|
}
|
|
7120
6955
|
if (n.compute != null) {
|
|
7121
|
-
if (
|
|
7122
|
-
errors.push("compute: must be an
|
|
6956
|
+
if (!Array.isArray(n.compute)) {
|
|
6957
|
+
errors.push("compute: must be an array of compute steps");
|
|
7123
6958
|
} else {
|
|
7124
|
-
|
|
7125
|
-
if (!
|
|
7126
|
-
errors.push(`compute
|
|
7127
|
-
} else if (!expr.fn) {
|
|
7128
|
-
errors.push(`compute.${key}: missing required "fn" property`);
|
|
6959
|
+
n.compute.forEach((step, i) => {
|
|
6960
|
+
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
6961
|
+
errors.push(`compute[${i}]: must be a compute step object`);
|
|
7129
6962
|
} else {
|
|
7130
|
-
const
|
|
7131
|
-
if (!
|
|
7132
|
-
|
|
6963
|
+
const s = step;
|
|
6964
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`compute[${i}]: missing required "bindTo" property`);
|
|
6965
|
+
if (typeof s.expr !== "string" || !s.expr) errors.push(`compute[${i}]: missing required "expr" string (JSONata expression)`);
|
|
6966
|
+
}
|
|
6967
|
+
});
|
|
6968
|
+
}
|
|
6969
|
+
}
|
|
6970
|
+
if (n.sources != null) {
|
|
6971
|
+
if (!Array.isArray(n.sources)) {
|
|
6972
|
+
errors.push("sources: must be an array");
|
|
6973
|
+
} else {
|
|
6974
|
+
n.sources.forEach((src, i) => {
|
|
6975
|
+
if (!src || typeof src !== "object" || Array.isArray(src)) {
|
|
6976
|
+
errors.push(`sources[${i}]: must be an object`);
|
|
6977
|
+
} else {
|
|
6978
|
+
const s = src;
|
|
6979
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`sources[${i}]: missing required "bindTo" property`);
|
|
6980
|
+
if (s.outputFile != null && typeof s.outputFile !== "string") errors.push(`sources[${i}]: outputFile must be a string`);
|
|
6981
|
+
if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
|
|
6982
|
+
errors.push(`sources[${i}]: optionalForCompletionGating must be a boolean`);
|
|
7133
6983
|
}
|
|
7134
6984
|
}
|
|
7135
|
-
}
|
|
6985
|
+
});
|
|
7136
6986
|
}
|
|
7137
6987
|
}
|
|
7138
|
-
if (n.
|
|
7139
|
-
if (n.
|
|
7140
|
-
|
|
7141
|
-
errors.push("view: required for card nodes, must be an object");
|
|
6988
|
+
if (n.view != null) {
|
|
6989
|
+
if (typeof n.view !== "object" || Array.isArray(n.view)) {
|
|
6990
|
+
errors.push("view: must be an object");
|
|
7142
6991
|
} else {
|
|
7143
6992
|
const view = n.view;
|
|
7144
6993
|
if (!Array.isArray(view.elements) || view.elements.length === 0) {
|
|
@@ -7159,49 +7008,35 @@ function validateNode(node) {
|
|
|
7159
7008
|
}
|
|
7160
7009
|
});
|
|
7161
7010
|
}
|
|
7162
|
-
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout)))
|
|
7163
|
-
|
|
7164
|
-
}
|
|
7165
|
-
if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) {
|
|
7166
|
-
errors.push("view.features: must be an object");
|
|
7167
|
-
}
|
|
7168
|
-
}
|
|
7169
|
-
}
|
|
7170
|
-
if (n.type === "source") {
|
|
7171
|
-
if (n.view != null) errors.push('Source nodes must not have "view" \u2014 use type "card" instead');
|
|
7172
|
-
if (n.source == null || typeof n.source !== "object" || Array.isArray(n.source)) {
|
|
7173
|
-
errors.push("source: required for source nodes, must be an object");
|
|
7174
|
-
} else {
|
|
7175
|
-
const src = n.source;
|
|
7176
|
-
if (!src.kind || !VALID_SOURCE_KINDS.has(src.kind)) {
|
|
7177
|
-
errors.push(`source.kind: required, must be one of: ${[...VALID_SOURCE_KINDS].join(", ")}`);
|
|
7178
|
-
}
|
|
7179
|
-
if (typeof src.bindTo !== "string" || !src.bindTo) {
|
|
7180
|
-
errors.push("source.bindTo: required, must be a state path string");
|
|
7181
|
-
} else if (!src.bindTo.startsWith("state.")) {
|
|
7182
|
-
errors.push('source.bindTo: must start with "state."');
|
|
7183
|
-
}
|
|
7011
|
+
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout))) errors.push("view.layout: must be an object");
|
|
7012
|
+
if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) errors.push("view.features: must be an object");
|
|
7184
7013
|
}
|
|
7185
7014
|
}
|
|
7186
7015
|
return { ok: errors.length === 0, errors };
|
|
7187
7016
|
}
|
|
7017
|
+
function enrichSources(sources, context) {
|
|
7018
|
+
if (!sources || sources.length === 0) return [];
|
|
7019
|
+
return sources.map((src) => ({
|
|
7020
|
+
...src,
|
|
7021
|
+
_requires: context.requires ?? {},
|
|
7022
|
+
_sourcesData: context.sourcesData ?? {},
|
|
7023
|
+
_computed_values: context.computed_values ?? {}
|
|
7024
|
+
}));
|
|
7025
|
+
}
|
|
7188
7026
|
var CardCompute = {
|
|
7189
7027
|
run,
|
|
7190
7028
|
eval: evalExpr,
|
|
7191
7029
|
resolve,
|
|
7192
7030
|
validate: validateNode,
|
|
7193
|
-
|
|
7194
|
-
get functions() {
|
|
7195
|
-
const all = {};
|
|
7196
|
-
for (const k of Object.keys(_fns)) all[k] = _fns[k];
|
|
7197
|
-
for (const k of Object.keys(_customFns)) all[k] = _customFns[k];
|
|
7198
|
-
return all;
|
|
7199
|
-
}
|
|
7031
|
+
enrichSources
|
|
7200
7032
|
};
|
|
7201
7033
|
var card_compute_default = CardCompute;
|
|
7202
7034
|
|
|
7203
7035
|
exports.CardCompute = CardCompute;
|
|
7204
7036
|
exports.default = card_compute_default;
|
|
7037
|
+
exports.validateLiveCard = validateLiveCard;
|
|
7038
|
+
exports.validateLiveCardDefinition = validateLiveCardDefinition;
|
|
7039
|
+
exports.validateLiveCardRuntimeExpressions = validateLiveCardRuntimeExpressions;
|
|
7205
7040
|
exports.validateLiveCardSchema = validateLiveCardSchema;
|
|
7206
7041
|
//# sourceMappingURL=index.cjs.map
|
|
7207
7042
|
//# sourceMappingURL=index.cjs.map
|