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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import jsonata2 from 'jsonata';
|
|
1
2
|
import addFormats from 'ajv-formats';
|
|
2
3
|
|
|
3
4
|
var __create = Object.create;
|
|
@@ -6415,13 +6416,11 @@ var require_ajv = __commonJS({
|
|
|
6415
6416
|
var live_cards_schema_default = {
|
|
6416
6417
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
6417
6418
|
$id: "https://nsreehari.github.io/boards/live-cards.schema.json",
|
|
6418
|
-
title: "LiveCards Node Schema",
|
|
6419
|
-
description: "Schema for Card and ExternalSource nodes in the LiveCards Board/Canvas engine",
|
|
6420
6419
|
definitions: {
|
|
6421
6420
|
bind_ref: {
|
|
6422
|
-
description: "A
|
|
6421
|
+
description: "A card data path reference, e.g. 'card_data.raw_quotes' or 'requires.upstream'",
|
|
6423
6422
|
type: "string",
|
|
6424
|
-
pattern: "^
|
|
6423
|
+
pattern: "^(card_data|requires|fetched_sources|computed_values)(\\.|$)"
|
|
6425
6424
|
},
|
|
6426
6425
|
bind_or_literal: {
|
|
6427
6426
|
description: "A literal value or a bind reference object",
|
|
@@ -6490,7 +6489,7 @@ var live_cards_schema_default = {
|
|
|
6490
6489
|
]
|
|
6491
6490
|
},
|
|
6492
6491
|
input: {
|
|
6493
|
-
description: "
|
|
6492
|
+
description: "card_data.path, literal, array of inputs, or nested compute_expr",
|
|
6494
6493
|
oneOf: [
|
|
6495
6494
|
{ type: "string" },
|
|
6496
6495
|
{ type: "number" },
|
|
@@ -6514,38 +6513,43 @@ var live_cards_schema_default = {
|
|
|
6514
6513
|
tags: { type: "array", items: { type: "string" } }
|
|
6515
6514
|
}
|
|
6516
6515
|
},
|
|
6517
|
-
|
|
6516
|
+
requires: {
|
|
6517
|
+
type: "array",
|
|
6518
|
+
items: { type: "string" },
|
|
6519
|
+
description: "IDs of upstream nodes this node depends on"
|
|
6520
|
+
},
|
|
6521
|
+
provides: {
|
|
6522
|
+
type: "array",
|
|
6523
|
+
items: {
|
|
6524
|
+
type: "object",
|
|
6525
|
+
required: ["bindTo", "src"],
|
|
6526
|
+
properties: {
|
|
6527
|
+
bindTo: { type: "string", description: "Token name published downstream" },
|
|
6528
|
+
src: { type: "string", description: "Path to read value from (card_data.*, requires.*, fetched_sources.*, computed_values.*)" }
|
|
6529
|
+
}
|
|
6530
|
+
},
|
|
6531
|
+
description: "Explicit bindings exposing computed or card_data values downstream as named tokens"
|
|
6532
|
+
},
|
|
6533
|
+
compute_step: {
|
|
6534
|
+
description: "A single ordered compute step: reads card_data.*/requires.*/computed_values.*, writes to computed_values[bindTo]",
|
|
6518
6535
|
type: "object",
|
|
6536
|
+
required: ["bindTo", "expr"],
|
|
6519
6537
|
properties: {
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
items: { type: "string" },
|
|
6523
|
-
description: "IDs of upstream nodes this node depends on"
|
|
6524
|
-
},
|
|
6525
|
-
provides: {
|
|
6526
|
-
type: "object",
|
|
6527
|
-
description: "Subset of state exposed downstream. Keys are published names, values are bind refs.",
|
|
6528
|
-
additionalProperties: { $ref: "#/definitions/bind_or_literal" }
|
|
6529
|
-
}
|
|
6538
|
+
bindTo: { type: "string", description: "Key in computed_values to write result" },
|
|
6539
|
+
expr: { type: "string", description: "JSONata expression evaluated against { card_data, requires, fetched_sources, computed_values }" }
|
|
6530
6540
|
}
|
|
6531
6541
|
},
|
|
6532
6542
|
source_def: {
|
|
6543
|
+
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.",
|
|
6533
6544
|
type: "object",
|
|
6534
|
-
required: ["
|
|
6545
|
+
required: ["bindTo"],
|
|
6546
|
+
additionalProperties: true,
|
|
6535
6547
|
properties: {
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
body_template: { type: "object", description: "Request body with {{var}} placeholders or bind refs" },
|
|
6542
|
-
template_vars: {
|
|
6543
|
-
type: "object",
|
|
6544
|
-
additionalProperties: { $ref: "#/definitions/bind_or_literal" },
|
|
6545
|
-
description: "Variables for url/body templates \u2014 static values or bind refs"
|
|
6546
|
-
},
|
|
6547
|
-
poll_interval: { type: "integer", minimum: 0, description: "Auto-refresh in seconds (0 = manual)" },
|
|
6548
|
-
transform: { type: "string", description: "Dot-path to extract from response, e.g. 'data.items'" }
|
|
6548
|
+
bindTo: { type: "string", description: "Key under fetched_sources.* available in compute expressions" },
|
|
6549
|
+
outputFile: { type: "string", description: "Board-relative path the executor writes its JSON result to. Presence of this file signals delivery." },
|
|
6550
|
+
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." },
|
|
6551
|
+
timeout: { type: "integer", minimum: 0, default: 12e4, description: "Executor/script timeout in ms. Default: 120 000 (2 min)." },
|
|
6552
|
+
script: { type: "string", description: "Legacy direct-run: shell command executed when no .task-executor is registered. stdout is captured as the result." }
|
|
6549
6553
|
}
|
|
6550
6554
|
},
|
|
6551
6555
|
render_element: {
|
|
@@ -6569,19 +6573,17 @@ var live_cards_schema_default = {
|
|
|
6569
6573
|
"text",
|
|
6570
6574
|
"markdown",
|
|
6571
6575
|
"custom",
|
|
6572
|
-
"file-upload",
|
|
6573
|
-
"chat",
|
|
6574
6576
|
"actions"
|
|
6575
6577
|
]
|
|
6576
6578
|
},
|
|
6577
6579
|
label: { type: "string", description: "Heading above this element" },
|
|
6578
6580
|
className: { type: "string", description: "Bootstrap grid class, e.g. 'col-12 col-md-6'" },
|
|
6579
|
-
visible: { type: "string", description: "
|
|
6581
|
+
visible: { type: "string", description: "card_data/requires/fetched_sources/computed_values path \u2014 element shown only if truthy" },
|
|
6580
6582
|
data: {
|
|
6581
6583
|
type: "object",
|
|
6582
6584
|
properties: {
|
|
6583
|
-
bind: { $ref: "#/definitions/bind_ref", description: "
|
|
6584
|
-
writeTo: { $ref: "#/definitions/bind_ref", description: "
|
|
6585
|
+
bind: { $ref: "#/definitions/bind_ref", description: "card_data/requires/fetched_sources/computed_values path to read data from" },
|
|
6586
|
+
writeTo: { $ref: "#/definitions/bind_ref", description: "card_data path for user input (form, filter, todo, notes)" },
|
|
6585
6587
|
columns: { type: "array", items: { type: "string" }, description: "table: visible columns" },
|
|
6586
6588
|
maxRows: { type: "integer", description: "table/list: max rows to display" },
|
|
6587
6589
|
sortable: { type: "boolean", default: true, description: "table: enable click-to-sort" },
|
|
@@ -6614,7 +6616,7 @@ var live_cards_schema_default = {
|
|
|
6614
6616
|
label: { type: "string" },
|
|
6615
6617
|
style: { type: "string", description: "Bootstrap button variant, e.g. 'success', 'outline-danger'" },
|
|
6616
6618
|
size: { type: "string", default: "sm" },
|
|
6617
|
-
disabled: { oneOf: [{ type: "boolean" }, { type: "string", description: "
|
|
6619
|
+
disabled: { oneOf: [{ type: "boolean" }, { type: "string", description: "card_data/requires/fetched_sources/computed_values path \u2014 truthy = disabled" }] }
|
|
6618
6620
|
}
|
|
6619
6621
|
}
|
|
6620
6622
|
}
|
|
@@ -6663,69 +6665,118 @@ var live_cards_schema_default = {
|
|
|
6663
6665
|
}
|
|
6664
6666
|
}
|
|
6665
6667
|
},
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6668
|
+
title: "LiveCard",
|
|
6669
|
+
description: "A unified card node. Behavior depends on which sections are present (sources, compute, view, etc.)",
|
|
6670
|
+
type: "object",
|
|
6671
|
+
required: ["id"],
|
|
6672
|
+
additionalProperties: false,
|
|
6673
|
+
properties: {
|
|
6674
|
+
id: { type: "string" },
|
|
6675
|
+
requires: { $ref: "#/definitions/requires" },
|
|
6676
|
+
provides: { $ref: "#/definitions/provides" },
|
|
6677
|
+
meta: { $ref: "#/definitions/meta" },
|
|
6678
|
+
view: { $ref: "#/definitions/view" },
|
|
6679
|
+
card_data: {
|
|
6670
6680
|
type: "object",
|
|
6671
|
-
|
|
6672
|
-
additionalProperties: false,
|
|
6681
|
+
description: "Authored card data supplied in the card definition",
|
|
6673
6682
|
properties: {
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6683
|
+
files: {
|
|
6684
|
+
type: "array",
|
|
6685
|
+
description: "Optional uploaded-file metadata maintained by host handlers. Stored name is normalized and serial-prefixed (for example 001-my_file.pdf).",
|
|
6686
|
+
items: {
|
|
6687
|
+
type: "object",
|
|
6688
|
+
required: ["name", "stored_name"],
|
|
6689
|
+
properties: {
|
|
6690
|
+
name: { type: "string", minLength: 1 },
|
|
6691
|
+
stored_name: {
|
|
6692
|
+
type: "string",
|
|
6693
|
+
minLength: 5,
|
|
6694
|
+
maxLength: 32,
|
|
6695
|
+
pattern: "^[0-9]{3,}-[a-z0-9._-]+$"
|
|
6696
|
+
},
|
|
6697
|
+
size: {
|
|
6698
|
+
oneOf: [
|
|
6699
|
+
{ type: "integer", minimum: 0 },
|
|
6700
|
+
{ type: "null" }
|
|
6701
|
+
]
|
|
6702
|
+
},
|
|
6703
|
+
mime_type: { type: "string" },
|
|
6704
|
+
path: { type: "string", pattern: "^[^\\s]+/files/[0-9]{3,}-[a-z0-9._-]+$" },
|
|
6705
|
+
uploaded_at: { type: "string", format: "date-time" }
|
|
6706
|
+
},
|
|
6707
|
+
additionalProperties: false
|
|
6686
6708
|
}
|
|
6687
|
-
},
|
|
6688
|
-
compute: {
|
|
6689
|
-
type: "object",
|
|
6690
|
-
description: "Derived state: key = state path to write, value = compute_expr",
|
|
6691
|
-
additionalProperties: { $ref: "#/definitions/compute_expr" }
|
|
6692
6709
|
}
|
|
6693
|
-
}
|
|
6710
|
+
},
|
|
6711
|
+
additionalProperties: true
|
|
6694
6712
|
},
|
|
6695
|
-
{
|
|
6696
|
-
|
|
6697
|
-
description: "
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
meta: { $ref: "#/definitions/meta" },
|
|
6705
|
-
data: { $ref: "#/definitions/data" },
|
|
6706
|
-
source: { $ref: "#/definitions/source_def" },
|
|
6707
|
-
state: {
|
|
6708
|
-
type: "object",
|
|
6709
|
-
additionalProperties: true,
|
|
6710
|
-
properties: {
|
|
6711
|
-
status: { enum: ["fresh", "stale", "loading", "error"] },
|
|
6712
|
-
lastRun: { type: "string", format: "date-time" },
|
|
6713
|
-
error: { type: "string" }
|
|
6714
|
-
}
|
|
6715
|
-
},
|
|
6716
|
-
compute: {
|
|
6717
|
-
type: "object",
|
|
6718
|
-
description: "Derived state: key = state path to write, value = compute_expr",
|
|
6719
|
-
additionalProperties: { $ref: "#/definitions/compute_expr" }
|
|
6720
|
-
}
|
|
6721
|
-
}
|
|
6713
|
+
sources: {
|
|
6714
|
+
type: "array",
|
|
6715
|
+
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.",
|
|
6716
|
+
items: { $ref: "#/definitions/source_def" }
|
|
6717
|
+
},
|
|
6718
|
+
compute: {
|
|
6719
|
+
type: "array",
|
|
6720
|
+
description: "Ordered array of compute steps. Each reads card_data.*/requires.*/fetched_sources.*/computed_values.* and writes to ephemeral computed_values[bindTo].",
|
|
6721
|
+
items: { $ref: "#/definitions/compute_step" }
|
|
6722
6722
|
}
|
|
6723
|
-
|
|
6723
|
+
}
|
|
6724
6724
|
};
|
|
6725
6725
|
|
|
6726
6726
|
// src/card-compute/schema-validator.ts
|
|
6727
6727
|
var import_ajv = __toESM(require_ajv());
|
|
6728
6728
|
var _compiled = null;
|
|
6729
|
+
var NAMESPACE_REFERENCE_RE = /\b(card_data|requires|fetched_sources|computed_values|sources)\b/g;
|
|
6730
|
+
var ROOT_PATH_NAMESPACE_RE = /^\s*(card_data|requires|fetched_sources|computed_values|sources)(\.|$)/;
|
|
6731
|
+
function referencedNamespaces(expression) {
|
|
6732
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
6733
|
+
let match;
|
|
6734
|
+
NAMESPACE_REFERENCE_RE.lastIndex = 0;
|
|
6735
|
+
while ((match = NAMESPACE_REFERENCE_RE.exec(expression)) !== null) {
|
|
6736
|
+
namespaces.add(match[1]);
|
|
6737
|
+
}
|
|
6738
|
+
return namespaces;
|
|
6739
|
+
}
|
|
6740
|
+
function parseRootPathNamespace(pathValue) {
|
|
6741
|
+
const match = ROOT_PATH_NAMESPACE_RE.exec(pathValue);
|
|
6742
|
+
return match ? match[1] : null;
|
|
6743
|
+
}
|
|
6744
|
+
function validateJsonataExprWithNamespaces(expr, path, allowedNamespaces, errors) {
|
|
6745
|
+
try {
|
|
6746
|
+
jsonata2(expr);
|
|
6747
|
+
} catch (err) {
|
|
6748
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6749
|
+
errors.push(`${path}: invalid JSONata expression (${message})`);
|
|
6750
|
+
return;
|
|
6751
|
+
}
|
|
6752
|
+
const usedNamespaces = referencedNamespaces(expr);
|
|
6753
|
+
for (const namespace of usedNamespaces) {
|
|
6754
|
+
if (!allowedNamespaces.has(namespace)) {
|
|
6755
|
+
errors.push(`${path}: disallowed namespace "${namespace}" in expression`);
|
|
6756
|
+
}
|
|
6757
|
+
}
|
|
6758
|
+
}
|
|
6759
|
+
function walkViewPathReferences(value, path, errors) {
|
|
6760
|
+
if (Array.isArray(value)) {
|
|
6761
|
+
value.forEach((entry, index) => {
|
|
6762
|
+
walkViewPathReferences(entry, `${path}/${index}`, errors);
|
|
6763
|
+
});
|
|
6764
|
+
return;
|
|
6765
|
+
}
|
|
6766
|
+
if (typeof value === "string") {
|
|
6767
|
+
const rootNamespace = parseRootPathNamespace(value);
|
|
6768
|
+
if (!rootNamespace) return;
|
|
6769
|
+
if (!(/* @__PURE__ */ new Set(["card_data", "requires", "fetched_sources", "computed_values"])).has(rootNamespace)) {
|
|
6770
|
+
errors.push(`${path}: disallowed namespace "${rootNamespace}" in view reference`);
|
|
6771
|
+
}
|
|
6772
|
+
return;
|
|
6773
|
+
}
|
|
6774
|
+
if (!value || typeof value !== "object") return;
|
|
6775
|
+
const record = value;
|
|
6776
|
+
for (const [key, next] of Object.entries(record)) {
|
|
6777
|
+
walkViewPathReferences(next, `${path}/${key}`, errors);
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6729
6780
|
function getValidator() {
|
|
6730
6781
|
if (_compiled) return _compiled;
|
|
6731
6782
|
const ajv = new import_ajv.default({ allErrors: true });
|
|
@@ -6743,6 +6794,42 @@ function validateLiveCardSchema(node) {
|
|
|
6743
6794
|
});
|
|
6744
6795
|
return { ok: false, errors };
|
|
6745
6796
|
}
|
|
6797
|
+
function validateLiveCardRuntimeExpressions(node) {
|
|
6798
|
+
const errors = [];
|
|
6799
|
+
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
6800
|
+
return { ok: true, errors: [] };
|
|
6801
|
+
}
|
|
6802
|
+
const asRecord = node;
|
|
6803
|
+
const compute = asRecord.compute;
|
|
6804
|
+
if (Array.isArray(compute)) {
|
|
6805
|
+
compute.forEach((step, i) => {
|
|
6806
|
+
if (!step || typeof step !== "object" || Array.isArray(step)) return;
|
|
6807
|
+
const expr = step.expr;
|
|
6808
|
+
if (typeof expr !== "string" || expr.trim().length === 0) return;
|
|
6809
|
+
validateJsonataExprWithNamespaces(
|
|
6810
|
+
expr,
|
|
6811
|
+
`/compute/${i}/expr`,
|
|
6812
|
+
/* @__PURE__ */ new Set(["card_data", "requires", "fetched_sources", "computed_values"]),
|
|
6813
|
+
errors
|
|
6814
|
+
);
|
|
6815
|
+
});
|
|
6816
|
+
}
|
|
6817
|
+
const view = asRecord.view;
|
|
6818
|
+
if (view && typeof view === "object" && !Array.isArray(view)) {
|
|
6819
|
+
walkViewPathReferences(view, "/view", errors);
|
|
6820
|
+
}
|
|
6821
|
+
return { ok: errors.length === 0, errors };
|
|
6822
|
+
}
|
|
6823
|
+
function validateLiveCard(node) {
|
|
6824
|
+
return validateLiveCardDefinition(node);
|
|
6825
|
+
}
|
|
6826
|
+
function validateLiveCardDefinition(node) {
|
|
6827
|
+
const schema = validateLiveCardSchema(node);
|
|
6828
|
+
if (!schema.ok) return schema;
|
|
6829
|
+
const runtime = validateLiveCardRuntimeExpressions(node);
|
|
6830
|
+
if (!runtime.ok) return { ok: false, errors: runtime.errors };
|
|
6831
|
+
return { ok: true, errors: [] };
|
|
6832
|
+
}
|
|
6746
6833
|
|
|
6747
6834
|
// src/card-compute/index.ts
|
|
6748
6835
|
function deepGet(obj, path) {
|
|
@@ -6764,288 +6851,43 @@ function deepSet(obj, path, value) {
|
|
|
6764
6851
|
}
|
|
6765
6852
|
cur[parts[parts.length - 1]] = value;
|
|
6766
6853
|
}
|
|
6767
|
-
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
};
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
const
|
|
6779
|
-
const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
|
|
6780
|
-
return vals.length ? Math.min(...vals) : 0;
|
|
6781
|
-
};
|
|
6782
|
-
_fns.max = (input, _e, opts) => {
|
|
6783
|
-
const a = Array.isArray(input) ? input : [];
|
|
6784
|
-
const vals = opts.field ? a.map((r) => Number(r[opts.field])) : a.map(Number);
|
|
6785
|
-
return vals.length ? Math.max(...vals) : 0;
|
|
6786
|
-
};
|
|
6787
|
-
_fns.count = (input) => Array.isArray(input) ? input.length : input != null ? 1 : 0;
|
|
6788
|
-
_fns.first = (input) => Array.isArray(input) ? input[0] : input;
|
|
6789
|
-
_fns.last = (input) => Array.isArray(input) ? input[input.length - 1] : input;
|
|
6790
|
-
_fns.add = (input) => {
|
|
6791
|
-
const a = Array.isArray(input) ? input : [];
|
|
6792
|
-
return a.reduce((s, v) => s + Number(v), 0);
|
|
6793
|
-
};
|
|
6794
|
-
_fns.sub = (input) => {
|
|
6795
|
-
const a = Array.isArray(input) ? input : [];
|
|
6796
|
-
return a.length >= 2 ? Number(a[0]) - Number(a[1]) : 0;
|
|
6797
|
-
};
|
|
6798
|
-
_fns.mul = (input) => {
|
|
6799
|
-
const a = Array.isArray(input) ? input : [];
|
|
6800
|
-
return a.reduce((s, v) => s * Number(v), 1);
|
|
6801
|
-
};
|
|
6802
|
-
_fns.div = (input) => {
|
|
6803
|
-
const a = Array.isArray(input) ? input : [];
|
|
6804
|
-
return a.length >= 2 && Number(a[1]) !== 0 ? Number(a[0]) / Number(a[1]) : 0;
|
|
6805
|
-
};
|
|
6806
|
-
_fns.round = (input, _e, opts) => {
|
|
6807
|
-
const decimals = opts.decimals != null ? opts.decimals : 0;
|
|
6808
|
-
const factor = Math.pow(10, decimals);
|
|
6809
|
-
return Math.round(Number(input) * factor) / factor;
|
|
6810
|
-
};
|
|
6811
|
-
_fns.abs = (input) => Math.abs(Number(input));
|
|
6812
|
-
_fns.mod = (input) => {
|
|
6813
|
-
const a = Array.isArray(input) ? input : [];
|
|
6814
|
-
return a.length >= 2 ? Number(a[0]) % Number(a[1]) : 0;
|
|
6815
|
-
};
|
|
6816
|
-
_fns.gt = (input) => {
|
|
6817
|
-
const a = Array.isArray(input) ? input : [];
|
|
6818
|
-
return a.length >= 2 && Number(a[0]) > Number(a[1]);
|
|
6819
|
-
};
|
|
6820
|
-
_fns.gte = (input) => {
|
|
6821
|
-
const a = Array.isArray(input) ? input : [];
|
|
6822
|
-
return a.length >= 2 && Number(a[0]) >= Number(a[1]);
|
|
6823
|
-
};
|
|
6824
|
-
_fns.lt = (input) => {
|
|
6825
|
-
const a = Array.isArray(input) ? input : [];
|
|
6826
|
-
return a.length >= 2 && Number(a[0]) < Number(a[1]);
|
|
6827
|
-
};
|
|
6828
|
-
_fns.lte = (input) => {
|
|
6829
|
-
const a = Array.isArray(input) ? input : [];
|
|
6830
|
-
return a.length >= 2 && Number(a[0]) <= Number(a[1]);
|
|
6831
|
-
};
|
|
6832
|
-
_fns.eq = (input) => {
|
|
6833
|
-
const a = Array.isArray(input) ? input : [];
|
|
6834
|
-
return a.length >= 2 && a[0] === a[1];
|
|
6835
|
-
};
|
|
6836
|
-
_fns.neq = (input) => {
|
|
6837
|
-
const a = Array.isArray(input) ? input : [];
|
|
6838
|
-
return a.length >= 2 && a[0] !== a[1];
|
|
6839
|
-
};
|
|
6840
|
-
_fns.and = (input) => {
|
|
6841
|
-
const a = Array.isArray(input) ? input : [];
|
|
6842
|
-
return a.every(Boolean);
|
|
6843
|
-
};
|
|
6844
|
-
_fns.or = (input) => {
|
|
6845
|
-
const a = Array.isArray(input) ? input : [];
|
|
6846
|
-
return a.some(Boolean);
|
|
6847
|
-
};
|
|
6848
|
-
_fns.not = (input) => !input;
|
|
6849
|
-
_fns.concat = (input) => {
|
|
6850
|
-
const a = Array.isArray(input) ? input : [];
|
|
6851
|
-
return a.map((v) => v != null ? String(v) : "").join("");
|
|
6852
|
-
};
|
|
6853
|
-
_fns.upper = (input) => String(input || "").toUpperCase();
|
|
6854
|
-
_fns.lower = (input) => String(input || "").toLowerCase();
|
|
6855
|
-
_fns.template = (input, _e, opts) => {
|
|
6856
|
-
let t = String(opts.format || "");
|
|
6857
|
-
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
6858
|
-
for (const k of Object.keys(input)) {
|
|
6859
|
-
const v = input[k];
|
|
6860
|
-
t = t.split("{{" + k + "}}").join(v != null ? String(v) : "");
|
|
6861
|
-
}
|
|
6862
|
-
}
|
|
6863
|
-
return t;
|
|
6864
|
-
};
|
|
6865
|
-
_fns.join = (input, _e, opts) => {
|
|
6866
|
-
const a = Array.isArray(input) ? input : [];
|
|
6867
|
-
const sep = opts.separator != null ? String(opts.separator) : ", ";
|
|
6868
|
-
return a.map((v) => v != null ? String(v) : "").join(sep);
|
|
6869
|
-
};
|
|
6870
|
-
_fns.split = (input, _e, opts) => {
|
|
6871
|
-
const sep = opts.separator != null ? String(opts.separator) : ",";
|
|
6872
|
-
return String(input || "").split(sep).map((s) => s.trim());
|
|
6873
|
-
};
|
|
6874
|
-
_fns.trim = (input) => String(input || "").trim();
|
|
6875
|
-
_fns.pluck = (input, _e, opts) => Array.isArray(input) ? input.map((r) => r[opts.field]) : [];
|
|
6876
|
-
_fns.filter = (input, _e, opts) => {
|
|
6877
|
-
if (!Array.isArray(input)) return [];
|
|
6878
|
-
if (opts.field) return input.filter((r) => !!r[opts.field]);
|
|
6879
|
-
return input.filter(Boolean);
|
|
6880
|
-
};
|
|
6881
|
-
_fns.map = (input) => Array.isArray(input) ? input.slice() : [];
|
|
6882
|
-
_fns.sort = (input, _e, opts) => {
|
|
6883
|
-
const a = Array.isArray(input) ? input.slice() : [];
|
|
6884
|
-
const f = opts.field;
|
|
6885
|
-
const dir = opts.direction === "desc" ? -1 : 1;
|
|
6886
|
-
if (f) return a.sort((x, y) => x[f] > y[f] ? dir : x[f] < y[f] ? -dir : 0);
|
|
6887
|
-
return a.sort((x, y) => x > y ? dir : x < y ? -dir : 0);
|
|
6888
|
-
};
|
|
6889
|
-
_fns.slice = (input, _e, opts) => Array.isArray(input) ? input.slice(opts.start || 0, opts.end) : input;
|
|
6890
|
-
_fns.flat = (input, _e, opts) => {
|
|
6891
|
-
const depth = opts.depth != null ? opts.depth : 1;
|
|
6892
|
-
return Array.isArray(input) ? input.flat(depth) : [input];
|
|
6893
|
-
};
|
|
6894
|
-
_fns.unique = (input) => {
|
|
6895
|
-
if (!Array.isArray(input)) return [input];
|
|
6896
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6897
|
-
return input.filter((v) => {
|
|
6898
|
-
const key = typeof v === "object" ? JSON.stringify(v) : v;
|
|
6899
|
-
if (seen.has(key)) return false;
|
|
6900
|
-
seen.add(key);
|
|
6901
|
-
return true;
|
|
6902
|
-
});
|
|
6903
|
-
};
|
|
6904
|
-
_fns.group = (input, _e, opts) => {
|
|
6905
|
-
const a = Array.isArray(input) ? input : [];
|
|
6906
|
-
const g = {};
|
|
6907
|
-
a.forEach((r) => {
|
|
6908
|
-
const k = String(r[opts.field] || "");
|
|
6909
|
-
if (!g[k]) g[k] = [];
|
|
6910
|
-
g[k].push(r);
|
|
6911
|
-
});
|
|
6912
|
-
return g;
|
|
6913
|
-
};
|
|
6914
|
-
_fns.flatten_keys = (input) => {
|
|
6915
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return [];
|
|
6916
|
-
const result = [];
|
|
6917
|
-
for (const k of Object.keys(input)) {
|
|
6918
|
-
const vals = Array.isArray(input[k]) ? input[k] : [input[k]];
|
|
6919
|
-
vals.forEach((v) => result.push({ key: k, value: v }));
|
|
6920
|
-
}
|
|
6921
|
-
return result;
|
|
6922
|
-
};
|
|
6923
|
-
_fns.entries = (input) => {
|
|
6924
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return [];
|
|
6925
|
-
return Object.keys(input).map((k) => ({ key: k, value: input[k] }));
|
|
6926
|
-
};
|
|
6927
|
-
_fns.from_entries = (input) => {
|
|
6928
|
-
if (!Array.isArray(input)) return {};
|
|
6929
|
-
const obj = {};
|
|
6930
|
-
input.forEach((item) => {
|
|
6931
|
-
if (item.key != null) obj[item.key] = item.value;
|
|
6932
|
-
});
|
|
6933
|
-
return obj;
|
|
6934
|
-
};
|
|
6935
|
-
_fns.length = (input) => {
|
|
6936
|
-
if (Array.isArray(input)) return input.length;
|
|
6937
|
-
if (typeof input === "string") return input.length;
|
|
6938
|
-
if (input && typeof input === "object") return Object.keys(input).length;
|
|
6939
|
-
return 0;
|
|
6940
|
-
};
|
|
6941
|
-
_fns.get = (input, _e, opts) => deepGet(input, opts.field || opts.path || "");
|
|
6942
|
-
_fns.default = (input, _e, opts) => input != null ? input : opts.value;
|
|
6943
|
-
_fns.coalesce = (input) => {
|
|
6944
|
-
const a = Array.isArray(input) ? input : [];
|
|
6945
|
-
for (let i = 0; i < a.length; i++) {
|
|
6946
|
-
if (a[i] != null) return a[i];
|
|
6947
|
-
}
|
|
6948
|
-
return null;
|
|
6949
|
-
};
|
|
6950
|
-
_fns.now = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
6951
|
-
_fns.diff_days = (input) => {
|
|
6952
|
-
const a = Array.isArray(input) ? input : [];
|
|
6953
|
-
return a.length >= 2 ? Math.floor((new Date(a[0]).getTime() - new Date(a[1]).getTime()) / 864e5) : 0;
|
|
6954
|
-
};
|
|
6955
|
-
_fns.format_date = (input, _e, opts) => {
|
|
6956
|
-
try {
|
|
6957
|
-
const d = new Date(input);
|
|
6958
|
-
if (opts.format === "iso") return d.toISOString();
|
|
6959
|
-
if (opts.format === "date") return d.toLocaleDateString();
|
|
6960
|
-
if (opts.format === "time") return d.toLocaleTimeString();
|
|
6961
|
-
return d.toLocaleDateString();
|
|
6962
|
-
} catch {
|
|
6963
|
-
return String(input);
|
|
6964
|
-
}
|
|
6965
|
-
};
|
|
6966
|
-
_fns.parse_date = (input) => {
|
|
6967
|
-
try {
|
|
6968
|
-
return new Date(input).toISOString();
|
|
6969
|
-
} catch {
|
|
6970
|
-
return null;
|
|
6971
|
-
}
|
|
6972
|
-
};
|
|
6973
|
-
_fns.to_number = (input) => Number(input) || 0;
|
|
6974
|
-
_fns.to_string = (input) => input != null ? String(input) : "";
|
|
6975
|
-
_fns.to_bool = (input) => !!input;
|
|
6976
|
-
_fns.type_of = (input) => Array.isArray(input) ? "array" : typeof input;
|
|
6977
|
-
_fns.is_null = (input) => input == null;
|
|
6978
|
-
_fns.is_empty = (input) => {
|
|
6979
|
-
if (input == null) return true;
|
|
6980
|
-
if (Array.isArray(input)) return input.length === 0;
|
|
6981
|
-
if (typeof input === "string") return input.length === 0;
|
|
6982
|
-
if (typeof input === "object") return Object.keys(input).length === 0;
|
|
6983
|
-
return false;
|
|
6984
|
-
};
|
|
6985
|
-
var _customFns = {};
|
|
6986
|
-
function evalExpr(expr, node) {
|
|
6987
|
-
if (expr == null) return expr;
|
|
6988
|
-
if (typeof expr !== "object" || Array.isArray(expr)) return expr;
|
|
6989
|
-
const e = expr;
|
|
6990
|
-
if (!e.fn) return expr;
|
|
6991
|
-
let input = e.input;
|
|
6992
|
-
if (typeof input === "string" && input.startsWith("state.")) {
|
|
6993
|
-
input = deepGet(node, input);
|
|
6994
|
-
} else if (Array.isArray(input)) {
|
|
6995
|
-
input = input.map((v) => {
|
|
6996
|
-
if (typeof v === "string" && v.startsWith("state.")) return deepGet(node, v);
|
|
6997
|
-
if (v && typeof v === "object" && v.fn) return evalExpr(v, node);
|
|
6998
|
-
return v;
|
|
6999
|
-
});
|
|
7000
|
-
} else if (input && typeof input === "object" && input.fn) {
|
|
7001
|
-
input = evalExpr(input, node);
|
|
7002
|
-
}
|
|
7003
|
-
if (e.fn === "if") {
|
|
7004
|
-
const cond = evalExpr(e.cond, node);
|
|
7005
|
-
if (cond) {
|
|
7006
|
-
return e.then && typeof e.then === "object" && e.then.fn ? evalExpr(e.then, node) : e.then;
|
|
7007
|
-
} else {
|
|
7008
|
-
return e.else && typeof e.else === "object" && e.else.fn ? evalExpr(e.else, node) : e.else;
|
|
7009
|
-
}
|
|
7010
|
-
}
|
|
7011
|
-
if (e.fn === "filter" && Array.isArray(input) && e.where) {
|
|
7012
|
-
return input.filter((item) => {
|
|
7013
|
-
const tmp = { state: { ...node.state, $: item } };
|
|
7014
|
-
return evalExpr(e.where, tmp);
|
|
7015
|
-
});
|
|
7016
|
-
}
|
|
7017
|
-
if (e.fn === "map" && Array.isArray(input) && e.apply) {
|
|
7018
|
-
return input.map((item) => {
|
|
7019
|
-
const tmp = { state: { ...node.state, $: item } };
|
|
7020
|
-
return evalExpr(e.apply, tmp);
|
|
7021
|
-
});
|
|
7022
|
-
}
|
|
7023
|
-
const fn = _customFns[e.fn] || _fns[e.fn];
|
|
7024
|
-
if (!fn) {
|
|
7025
|
-
console.warn('CardCompute: unknown function "' + e.fn + '"');
|
|
7026
|
-
return void 0;
|
|
7027
|
-
}
|
|
7028
|
-
return fn(input, evalExpr, e);
|
|
7029
|
-
}
|
|
7030
|
-
function run(node) {
|
|
7031
|
-
if (!node || !node.compute) return node;
|
|
7032
|
-
if (!node.state) node.state = {};
|
|
7033
|
-
for (const key of Object.keys(node.compute)) {
|
|
6854
|
+
async function run(node, options) {
|
|
6855
|
+
if (!node?.compute?.length) return node;
|
|
6856
|
+
if (!node.card_data) node.card_data = {};
|
|
6857
|
+
node.computed_values = {};
|
|
6858
|
+
node._sourcesData = options?.sourcesData ?? {};
|
|
6859
|
+
const ctx = {
|
|
6860
|
+
card_data: node.card_data,
|
|
6861
|
+
requires: node.requires ?? {},
|
|
6862
|
+
fetched_sources: node._sourcesData,
|
|
6863
|
+
computed_values: node.computed_values
|
|
6864
|
+
};
|
|
6865
|
+
for (const step of node.compute) {
|
|
7034
6866
|
try {
|
|
7035
|
-
const val =
|
|
7036
|
-
deepSet(node.
|
|
6867
|
+
const val = await jsonata2(step.expr).evaluate(ctx);
|
|
6868
|
+
deepSet(node.computed_values, step.bindTo, val);
|
|
6869
|
+
ctx.computed_values = node.computed_values;
|
|
7037
6870
|
} catch (err) {
|
|
7038
|
-
console.error(`CardCompute.run error on "${node.id
|
|
6871
|
+
console.error(`CardCompute.run error on "${node.id ?? "?"}.${step.bindTo}":`, err);
|
|
7039
6872
|
}
|
|
7040
6873
|
}
|
|
7041
6874
|
return node;
|
|
7042
6875
|
}
|
|
6876
|
+
async function evalExpr(expr, node) {
|
|
6877
|
+
const ctx = {
|
|
6878
|
+
card_data: node.card_data ?? {},
|
|
6879
|
+
requires: node.requires ?? {},
|
|
6880
|
+
fetched_sources: node._sourcesData ?? {},
|
|
6881
|
+
computed_values: node.computed_values ?? {}
|
|
6882
|
+
};
|
|
6883
|
+
return jsonata2(expr).evaluate(ctx);
|
|
6884
|
+
}
|
|
7043
6885
|
function resolve(node, path) {
|
|
6886
|
+
if (path.startsWith("fetched_sources.")) {
|
|
6887
|
+
return deepGet(node._sourcesData ?? {}, path.slice("fetched_sources.".length));
|
|
6888
|
+
}
|
|
7044
6889
|
return deepGet(node, path);
|
|
7045
6890
|
}
|
|
7046
|
-
function registerFunction(name, fn) {
|
|
7047
|
-
_customFns[name] = fn;
|
|
7048
|
-
}
|
|
7049
6891
|
var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
7050
6892
|
"metric",
|
|
7051
6893
|
"table",
|
|
@@ -7062,34 +6904,19 @@ var VALID_ELEMENT_KINDS = /* @__PURE__ */ new Set([
|
|
|
7062
6904
|
"markdown",
|
|
7063
6905
|
"custom"
|
|
7064
6906
|
]);
|
|
7065
|
-
var
|
|
7066
|
-
var VALID_STATUSES = /* @__PURE__ */ new Set(["fresh", "stale", "loading", "error"]);
|
|
7067
|
-
var CARD_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "view", "state", "compute"]);
|
|
7068
|
-
var SOURCE_ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "type", "meta", "data", "source", "state", "compute"]);
|
|
6907
|
+
var ALLOWED_KEYS = /* @__PURE__ */ new Set(["id", "meta", "requires", "provides", "view", "card_data", "compute", "sources"]);
|
|
7069
6908
|
function validateNode(node) {
|
|
7070
6909
|
const errors = [];
|
|
7071
6910
|
if (!node || typeof node !== "object" || Array.isArray(node)) {
|
|
7072
6911
|
return { ok: false, errors: ["Node must be a non-null object"] };
|
|
7073
6912
|
}
|
|
7074
6913
|
const n = node;
|
|
7075
|
-
if (typeof n.id !== "string" || !n.id)
|
|
7076
|
-
errors.push("id: required, must be a non-empty string");
|
|
7077
|
-
}
|
|
7078
|
-
if (n.type !== "card" && n.type !== "source") {
|
|
7079
|
-
errors.push('type: must be "card" or "source"');
|
|
7080
|
-
return { ok: false, errors };
|
|
7081
|
-
}
|
|
7082
|
-
const allowed = n.type === "card" ? CARD_ALLOWED_KEYS : SOURCE_ALLOWED_KEYS;
|
|
6914
|
+
if (typeof n.id !== "string" || !n.id) errors.push("id: required, must be a non-empty string");
|
|
7083
6915
|
for (const key of Object.keys(n)) {
|
|
7084
|
-
if (!
|
|
6916
|
+
if (!ALLOWED_KEYS.has(key)) errors.push(`Unknown top-level key: "${key}"`);
|
|
7085
6917
|
}
|
|
7086
|
-
if (n.
|
|
7087
|
-
errors.push("
|
|
7088
|
-
} else {
|
|
7089
|
-
const state = n.state;
|
|
7090
|
-
if (state.status != null && !VALID_STATUSES.has(state.status)) {
|
|
7091
|
-
errors.push(`state.status: must be one of: ${[...VALID_STATUSES].join(", ")}`);
|
|
7092
|
-
}
|
|
6918
|
+
if (n.card_data == null || typeof n.card_data !== "object" || Array.isArray(n.card_data)) {
|
|
6919
|
+
errors.push("card_data: required, must be an object");
|
|
7093
6920
|
}
|
|
7094
6921
|
if (n.meta != null) {
|
|
7095
6922
|
if (typeof n.meta !== "object" || Array.isArray(n.meta)) {
|
|
@@ -7100,37 +6927,58 @@ function validateNode(node) {
|
|
|
7100
6927
|
if (meta.tags != null && !Array.isArray(meta.tags)) errors.push("meta.tags: must be an array");
|
|
7101
6928
|
}
|
|
7102
6929
|
}
|
|
7103
|
-
if (n.
|
|
7104
|
-
|
|
7105
|
-
|
|
6930
|
+
if (n.requires != null && !Array.isArray(n.requires)) errors.push("requires: must be an array of strings");
|
|
6931
|
+
if (n.provides != null) {
|
|
6932
|
+
if (!Array.isArray(n.provides)) {
|
|
6933
|
+
errors.push("provides: must be an array of { bindTo, src } bindings");
|
|
7106
6934
|
} else {
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
6935
|
+
n.provides.forEach((p, i) => {
|
|
6936
|
+
if (!p || typeof p !== "object" || Array.isArray(p)) {
|
|
6937
|
+
errors.push(`provides[${i}]: must be an object with bindTo and src`);
|
|
6938
|
+
} else {
|
|
6939
|
+
const b = p;
|
|
6940
|
+
if (typeof b.bindTo !== "string" || !b.bindTo) errors.push(`provides[${i}]: missing required "bindTo" string`);
|
|
6941
|
+
if (typeof b.src !== "string" || !b.src) errors.push(`provides[${i}]: missing required "src" string`);
|
|
6942
|
+
}
|
|
6943
|
+
});
|
|
7110
6944
|
}
|
|
7111
6945
|
}
|
|
7112
6946
|
if (n.compute != null) {
|
|
7113
|
-
if (
|
|
7114
|
-
errors.push("compute: must be an
|
|
6947
|
+
if (!Array.isArray(n.compute)) {
|
|
6948
|
+
errors.push("compute: must be an array of compute steps");
|
|
7115
6949
|
} else {
|
|
7116
|
-
|
|
7117
|
-
if (!
|
|
7118
|
-
errors.push(`compute
|
|
7119
|
-
} else if (!expr.fn) {
|
|
7120
|
-
errors.push(`compute.${key}: missing required "fn" property`);
|
|
6950
|
+
n.compute.forEach((step, i) => {
|
|
6951
|
+
if (!step || typeof step !== "object" || Array.isArray(step)) {
|
|
6952
|
+
errors.push(`compute[${i}]: must be a compute step object`);
|
|
7121
6953
|
} else {
|
|
7122
|
-
const
|
|
7123
|
-
if (!
|
|
7124
|
-
|
|
6954
|
+
const s = step;
|
|
6955
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`compute[${i}]: missing required "bindTo" property`);
|
|
6956
|
+
if (typeof s.expr !== "string" || !s.expr) errors.push(`compute[${i}]: missing required "expr" string (JSONata expression)`);
|
|
6957
|
+
}
|
|
6958
|
+
});
|
|
6959
|
+
}
|
|
6960
|
+
}
|
|
6961
|
+
if (n.sources != null) {
|
|
6962
|
+
if (!Array.isArray(n.sources)) {
|
|
6963
|
+
errors.push("sources: must be an array");
|
|
6964
|
+
} else {
|
|
6965
|
+
n.sources.forEach((src, i) => {
|
|
6966
|
+
if (!src || typeof src !== "object" || Array.isArray(src)) {
|
|
6967
|
+
errors.push(`sources[${i}]: must be an object`);
|
|
6968
|
+
} else {
|
|
6969
|
+
const s = src;
|
|
6970
|
+
if (typeof s.bindTo !== "string" || !s.bindTo) errors.push(`sources[${i}]: missing required "bindTo" property`);
|
|
6971
|
+
if (s.outputFile != null && typeof s.outputFile !== "string") errors.push(`sources[${i}]: outputFile must be a string`);
|
|
6972
|
+
if (s.optionalForCompletionGating != null && typeof s.optionalForCompletionGating !== "boolean") {
|
|
6973
|
+
errors.push(`sources[${i}]: optionalForCompletionGating must be a boolean`);
|
|
7125
6974
|
}
|
|
7126
6975
|
}
|
|
7127
|
-
}
|
|
6976
|
+
});
|
|
7128
6977
|
}
|
|
7129
6978
|
}
|
|
7130
|
-
if (n.
|
|
7131
|
-
if (n.
|
|
7132
|
-
|
|
7133
|
-
errors.push("view: required for card nodes, must be an object");
|
|
6979
|
+
if (n.view != null) {
|
|
6980
|
+
if (typeof n.view !== "object" || Array.isArray(n.view)) {
|
|
6981
|
+
errors.push("view: must be an object");
|
|
7134
6982
|
} else {
|
|
7135
6983
|
const view = n.view;
|
|
7136
6984
|
if (!Array.isArray(view.elements) || view.elements.length === 0) {
|
|
@@ -7151,47 +6999,30 @@ function validateNode(node) {
|
|
|
7151
6999
|
}
|
|
7152
7000
|
});
|
|
7153
7001
|
}
|
|
7154
|
-
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout)))
|
|
7155
|
-
|
|
7156
|
-
}
|
|
7157
|
-
if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) {
|
|
7158
|
-
errors.push("view.features: must be an object");
|
|
7159
|
-
}
|
|
7160
|
-
}
|
|
7161
|
-
}
|
|
7162
|
-
if (n.type === "source") {
|
|
7163
|
-
if (n.view != null) errors.push('Source nodes must not have "view" \u2014 use type "card" instead');
|
|
7164
|
-
if (n.source == null || typeof n.source !== "object" || Array.isArray(n.source)) {
|
|
7165
|
-
errors.push("source: required for source nodes, must be an object");
|
|
7166
|
-
} else {
|
|
7167
|
-
const src = n.source;
|
|
7168
|
-
if (!src.kind || !VALID_SOURCE_KINDS.has(src.kind)) {
|
|
7169
|
-
errors.push(`source.kind: required, must be one of: ${[...VALID_SOURCE_KINDS].join(", ")}`);
|
|
7170
|
-
}
|
|
7171
|
-
if (typeof src.bindTo !== "string" || !src.bindTo) {
|
|
7172
|
-
errors.push("source.bindTo: required, must be a state path string");
|
|
7173
|
-
} else if (!src.bindTo.startsWith("state.")) {
|
|
7174
|
-
errors.push('source.bindTo: must start with "state."');
|
|
7175
|
-
}
|
|
7002
|
+
if (view.layout != null && (typeof view.layout !== "object" || Array.isArray(view.layout))) errors.push("view.layout: must be an object");
|
|
7003
|
+
if (view.features != null && (typeof view.features !== "object" || Array.isArray(view.features))) errors.push("view.features: must be an object");
|
|
7176
7004
|
}
|
|
7177
7005
|
}
|
|
7178
7006
|
return { ok: errors.length === 0, errors };
|
|
7179
7007
|
}
|
|
7008
|
+
function enrichSources(sources, context) {
|
|
7009
|
+
if (!sources || sources.length === 0) return [];
|
|
7010
|
+
return sources.map((src) => ({
|
|
7011
|
+
...src,
|
|
7012
|
+
_requires: context.requires ?? {},
|
|
7013
|
+
_sourcesData: context.sourcesData ?? {},
|
|
7014
|
+
_computed_values: context.computed_values ?? {}
|
|
7015
|
+
}));
|
|
7016
|
+
}
|
|
7180
7017
|
var CardCompute = {
|
|
7181
7018
|
run,
|
|
7182
7019
|
eval: evalExpr,
|
|
7183
7020
|
resolve,
|
|
7184
7021
|
validate: validateNode,
|
|
7185
|
-
|
|
7186
|
-
get functions() {
|
|
7187
|
-
const all = {};
|
|
7188
|
-
for (const k of Object.keys(_fns)) all[k] = _fns[k];
|
|
7189
|
-
for (const k of Object.keys(_customFns)) all[k] = _customFns[k];
|
|
7190
|
-
return all;
|
|
7191
|
-
}
|
|
7022
|
+
enrichSources
|
|
7192
7023
|
};
|
|
7193
7024
|
var card_compute_default = CardCompute;
|
|
7194
7025
|
|
|
7195
|
-
export { CardCompute, card_compute_default as default, validateLiveCardSchema };
|
|
7026
|
+
export { CardCompute, card_compute_default as default, validateLiveCard, validateLiveCardDefinition, validateLiveCardRuntimeExpressions, validateLiveCardSchema };
|
|
7196
7027
|
//# sourceMappingURL=index.js.map
|
|
7197
7028
|
//# sourceMappingURL=index.js.map
|