yaml-flow 6.0.0 → 7.1.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/board-live-cards-cli.js +4 -4
- package/browser/asset-integrity.json +3 -3
- package/browser/board-livecards-client.js +2 -0
- package/browser/board-livecards-client.js.map +1 -0
- package/browser/board-livecards-localstorage.js +10 -0
- package/browser/board-livecards-localstorage.js.map +1 -0
- package/browser/board-livegraph-engine.js +2 -2
- package/browser/board-livegraph-engine.js.map +1 -1
- package/browser/card-compute.js +28 -28
- package/browser/compute-jsonata.js +5 -0
- package/browser/compute-jsonata.js.map +1 -0
- package/browser/live-cards.js +264 -151
- package/card-store.js +4 -4
- package/dist/{board-live-cards-public-CltXYgaY.d.cts → board-live-cards-public-5n1-syA3.d.cts} +8 -5
- package/dist/{board-live-cards-public-f-E-FAyp.d.ts → board-live-cards-public-CK_J8uv0.d.ts} +8 -5
- package/dist/board-livegraph-runtime/index.cjs +2 -2
- package/dist/board-livegraph-runtime/index.cjs.map +1 -1
- package/dist/board-livegraph-runtime/index.d.cts +11 -9
- package/dist/board-livegraph-runtime/index.d.ts +11 -9
- package/dist/board-livegraph-runtime/index.js +2 -2
- package/dist/board-livegraph-runtime/index.js.map +1 -1
- package/dist/board-livegraph-runtime/jsonata-sync.cjs +37 -1
- package/dist/card-compute/index.cjs +4 -4
- package/dist/card-compute/index.cjs.map +1 -1
- package/dist/card-compute/index.d.cts +5 -1
- package/dist/card-compute/index.d.ts +5 -1
- package/dist/card-compute/index.js +4 -4
- package/dist/card-compute/index.js.map +1 -1
- package/dist/card-compute/jsonata-sync.cjs +37 -1
- package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs +2 -1
- package/dist/cli/browser-api/board-live-cards-browser-adapter.cjs.map +1 -1
- package/dist/cli/browser-api/board-live-cards-browser-adapter.d.cts +27 -14
- package/dist/cli/browser-api/board-live-cards-browser-adapter.d.ts +27 -14
- package/dist/cli/browser-api/board-live-cards-browser-adapter.js +2 -1
- package/dist/cli/browser-api/board-live-cards-browser-adapter.js.map +1 -1
- package/dist/cli/browser-api/card-store-browser-api.cjs +1 -1
- package/dist/cli/browser-api/card-store-browser-api.cjs.map +1 -1
- package/dist/cli/browser-api/card-store-browser-api.js +1 -1
- package/dist/cli/browser-api/card-store-browser-api.js.map +1 -1
- package/dist/cli/browser-api/jsonata-sync.cjs +37 -1
- package/dist/cli/node/artifacts-store-cli.cjs +8 -8
- package/dist/cli/node/artifacts-store-cli.cjs.map +1 -1
- package/dist/cli/node/artifacts-store-cli.js +8 -8
- package/dist/cli/node/artifacts-store-cli.js.map +1 -1
- package/dist/cli/node/board-live-cards-cli.cjs +7 -7
- package/dist/cli/node/board-live-cards-cli.cjs.map +1 -1
- package/dist/cli/node/board-live-cards-cli.js +7 -7
- package/dist/cli/node/board-live-cards-cli.js.map +1 -1
- package/dist/cli/node/card-store-cli.cjs +5 -5
- package/dist/cli/node/card-store-cli.cjs.map +1 -1
- package/dist/cli/node/card-store-cli.js +5 -5
- package/dist/cli/node/card-store-cli.js.map +1 -1
- package/dist/cli/node/execution-adapter.cjs +3 -0
- package/dist/cli/node/execution-adapter.cjs.map +1 -0
- package/dist/cli/node/execution-adapter.d.cts +174 -0
- package/dist/cli/node/execution-adapter.d.ts +174 -0
- package/dist/cli/node/execution-adapter.js +3 -0
- package/dist/cli/node/execution-adapter.js.map +1 -0
- package/dist/cli/node/fs-board-adapter.cjs +7 -7
- package/dist/cli/node/fs-board-adapter.cjs.map +1 -1
- package/dist/cli/node/fs-board-adapter.d.cts +2 -2
- package/dist/cli/node/fs-board-adapter.d.ts +2 -2
- package/dist/cli/node/fs-board-adapter.js +7 -7
- package/dist/cli/node/fs-board-adapter.js.map +1 -1
- package/dist/cli/node/jsonata-sync.cjs +37 -1
- package/dist/cli/node/source-cli-task-executor.cjs +4 -4
- package/dist/cli/node/source-cli-task-executor.cjs.map +1 -1
- package/dist/cli/node/source-cli-task-executor.js +4 -4
- package/dist/cli/node/source-cli-task-executor.js.map +1 -1
- package/dist/continuous-event-graph/index.cjs +2 -2
- package/dist/continuous-event-graph/index.cjs.map +1 -1
- package/dist/continuous-event-graph/index.js +2 -2
- package/dist/continuous-event-graph/index.js.map +1 -1
- package/dist/continuous-event-graph/jsonata-sync.cjs +37 -1
- package/dist/execution-refs.cjs +2 -1
- package/dist/execution-refs.cjs.map +1 -1
- package/dist/execution-refs.d.cts +55 -12
- package/dist/execution-refs.d.ts +55 -12
- package/dist/execution-refs.js +2 -1
- package/dist/execution-refs.js.map +1 -1
- package/dist/index.cjs +10 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/jsonata-sync.cjs +37 -1
- package/dist/server-runtime/index.cjs +9 -0
- package/dist/server-runtime/index.cjs.map +1 -0
- package/dist/server-runtime/index.d.cts +31 -0
- package/dist/server-runtime/index.d.ts +31 -0
- package/dist/server-runtime/index.js +9 -0
- package/dist/server-runtime/index.js.map +1 -0
- package/dist/server-runtime/jsonata-sync.cjs +7623 -0
- package/dist/step-machine-public/index.cjs +3 -0
- package/dist/step-machine-public/index.cjs.map +1 -0
- package/dist/step-machine-public/index.d.cts +166 -0
- package/dist/step-machine-public/index.d.ts +166 -0
- package/dist/step-machine-public/index.js +3 -0
- package/dist/step-machine-public/index.js.map +1 -0
- package/dist/step-machine-public/jsonata-sync.cjs +7623 -0
- package/dist/storage-refs.cjs +2 -2
- package/dist/storage-refs.cjs.map +1 -1
- package/dist/storage-refs.d.cts +6 -6
- package/dist/storage-refs.d.ts +6 -6
- package/dist/storage-refs.js +2 -2
- package/dist/storage-refs.js.map +1 -1
- package/dist/types-CU3DjTKL.d.cts +147 -0
- package/dist/types-HGDTWIun.d.ts +147 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-t4.js +9 -10
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.js +370 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-http-test.py +398 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-public.js +9 -10
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.js +300 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-server.py +617 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker-sse-worker.js +48 -0
- package/examples/browser/boards/portfolio-tracker/portfolio-tracker.py +11 -10
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/_board-cli.js +19 -4
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/add-cards-cli.js +4 -8
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/init-board-cli.js +6 -10
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/poll-status-cli.js +8 -16
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/reset-board-dir-cli.js +2 -6
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/retrigger-cli.js +4 -8
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/status-cli.js +3 -7
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/update-holdings-cli.js +4 -8
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/wait-completed-cli.js +7 -16
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers/write-prices-cli.js +2 -6
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/_board_pycli.py +13 -3
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/add-cards.py +2 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/init-board.py +2 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/handlers-py/poll-status.py +2 -1
- package/examples/cli/step-machine-cli/portfolio-tracker/portfolio-tracker.flow.yaml +20 -24
- package/examples/cli/step-machine-cli/portfolio-tracker/run-inline-python-demo-pycli.py +0 -3
- package/examples/cli/step-machine-demo/jsonata-init-board-cli.js +8 -13
- package/examples/cli/step-machine-demo/jsonata-init-board.flow.yaml +33 -9
- package/examples/cli/step-machine-demo/one-step-cli-only.flow.yaml +3 -1
- package/examples/cli/step-machine-demo/step2-double-cli.js +6 -12
- package/examples/cli/step-machine-demo/two-step-math.flow.yaml +66 -4
- package/examples/cli/step-machine-demo/two-step-mixed.flow.yaml +13 -5
- package/examples/example-board/agent-instructions.md +1 -1
- package/examples/example-board/cards/card-my-identity.json +30 -6
- package/examples/example-board/cards/card-portfolio-action.json +24 -6
- package/examples/example-board/cards/card-portfolio-intelligence.json +97 -0
- package/examples/example-board/cards/card-portfolio-risks.json +24 -6
- package/examples/example-board/cards/card-rebalance-impact.json +22 -6
- package/examples/example-board/cards/card-rebalance-sim.json +66 -15
- package/examples/example-board/cards/cardT-market-prices.json +80 -0
- package/examples/example-board/cards/{card-portfolio-value.json → cardT-portfolio-value.json} +38 -10
- package/examples/example-board/cards/cardT-portfolio.json +78 -0
- package/examples/example-board/demo-server-config.json +1 -1
- package/examples/example-board/demo-server.js +383 -69
- package/examples/example-board/demo-shell-localstorage.html +774 -0
- package/examples/example-board/demo-shell-with-server.html +18 -36
- package/examples/example-board/demo-shell.html +5 -4
- package/examples/example-board/demo-task-executor.js +213 -265
- package/package.json +15 -13
- package/step-machine-cli.js +43 -310
- package/board-livecards-server-runtime.js +0 -1513
- package/browser/board-livecards-runtime-client.js +0 -263
- package/dist/pycli/quickjs-board-runtime.global.js +0 -9
- package/dist/pycli/quickjs-board-runtime.global.js.map +0 -1
- package/dist/pycli/quickjs-step-machine-runtime.global.js +0 -5
- package/dist/pycli/quickjs-step-machine-runtime.global.js.map +0 -1
- package/examples/cli/step-machine-demo/two-step-math-handlers.js +0 -32
- package/examples/cli/step-machine-demo/two-step-mixed-handlers.js +0 -24
- package/examples/example-board/cards/card-market-prices.json +0 -56
- package/examples/example-board/cards/card-portfolio.json +0 -44
- package/examples/example-board/demo-shell-browser.html +0 -675
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';var module$1=require('module');var _documentCurrentScript=typeof document!=='undefined'?document.currentScript:null;var A=module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))),p=A("./jsonata-sync.cjs");function m(r,e){if(!r||typeof r!="object")throw new Error(`[step-machine-public] Step "${e}" returned a non-object result.`);let t=r,n=t.result??t.status;if(typeof n=="string"&&n.trim().length>0){let a=t.data&&typeof t.data=="object"&&!Array.isArray(t.data)?{...t.data}:{},s=typeof t.error=="string"?t.error:void 0;return s&&!("error"in a)&&(a.error=s),{result:n,data:a,...s?{error:s}:{}}}return {result:"success",data:{...t}}}function w(r,e){if(!e||e.length===0)return r;let t={};for(let n of e)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n]);return t}function g(r,e){return async(t,n)=>{let a=await r(t,n),s=m(a,n?.stepName??"unknown");return {result:s.result,data:w(s.data,e),...s.error?{error:s.error}:{}}}}function k(r,e,t){if(!e||e.length===0)return null;for(let n of e)try{if(!p(n).evaluate(r))return {result:"failure",data:{error:`[${t}] input validation failed: ${n}`}}}catch(a){let s=a instanceof Error?a.message:String(a);return {result:"failure",data:{error:`[${t}] input validation error on "${n}": ${s}`}}}return null}function y(r,e,t){return !e||e.length===0?r:async(n,a)=>{let s=k(n,e,t);return s||r(n,a)}}var h=module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));function O(){try{return h("./jsonata-sync.cjs")}catch{return h("../../card-compute/jsonata-sync.cjs")}}var f=O();function S(r,e,t){if(!r||typeof r!="object")return e;let n={output:e},a=e.result,s=e.data,i=e.error;if(typeof r.resultExpr=="string")try{let o=f(r.resultExpr).evaluate(n);if(typeof o!="string"||!o.trim())throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(o)})`);a=o;}catch(o){let u=o instanceof Error?o.message:String(o);throw new Error(`[${t}] outputTransforms.resultExpr failed: ${u}`)}if(typeof r.dataTemplate=="string")try{let o=f(r.dataTemplate).evaluate(n);if(!o||typeof o!="object"||Array.isArray(o))throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(o)})`);s=o;}catch(o){let u=o instanceof Error?o.message:String(o);throw new Error(`[${t}] outputTransforms.dataTemplate failed: ${u}`)}if(typeof r.errorExpr=="string")try{let o=f(r.errorExpr).evaluate(n);i=o!=null?String(o):void 0;}catch(o){let u=o instanceof Error?o.message:String(o);throw new Error(`[${t}] outputTransforms.errorExpr failed: ${u}`)}return i!==void 0?{result:a,data:s,error:i}:{result:a,data:s}}var F="b64:";function z(r){let e=new TextEncoder().encode(r),t=globalThis.Buffer,n;if(t)n=t.from(e).toString("base64");else if(typeof btoa=="function"){let a="";for(let s of e)a+=String.fromCharCode(s);n=btoa(a);}else throw new Error("No base64 encoder available in this runtime");return n.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function R(r){return `${F}${z(JSON.stringify(r))}`}function x(r){return !!r&&typeof r=="object"&&r.type==="compute-jsonata"&&Array.isArray(r.expr)&&r.expr.length>0}function b(r){if(!r||typeof r!="object")return false;let e=r;if(e.type!=="ref"||typeof e.howToRun!="string")return false;if(typeof e.whatToRun=="string")return true;if(e.whatToRun&&typeof e.whatToRun=="object"){let t=e.whatToRun;return typeof t.kind=="string"&&typeof t.value=="string"}return false}function I(r){if(typeof r=="string"){let e=r.indexOf("=");if(e<1)throw new Error(`[step-machine-public] Invalid compute expression (missing "="): "${r}"`);return {bindTo:r.slice(0,e).trim(),expr:r.slice(e+1).trim()}}if(r&&typeof r=="object"&&typeof r.bindTo=="string"&&typeof r.expr=="string")return r;throw new Error(`[step-machine-public] Invalid compute step: ${JSON.stringify(r)}`)}function B(r,e,t){let n=e.split("."),a=r;for(let s=0;s<n.length-1;s++){let i=n[s];(a[i]==null||typeof a[i]!="object")&&(a[i]={}),a=a[i];}a[n[n.length-1]]=t;}function v(r,e,t){let n=r.expr.map(I);return async a=>{let s=a&&typeof a=="object"&&!Array.isArray(a)?{...a}:{},i={},o={expects_data:s,data:i,...t?{config:t}:{}},u,d;for(let l of n)try{let c=p(l.expr).evaluate(o);if(l.bindTo==="result")u=c!=null?String(c):"success";else if(l.bindTo==="error")d=c!=null?String(c):void 0;else if(l.bindTo.startsWith("data."))B(i,l.bindTo.slice(5),c);else return {result:"failure",data:{},error:`[${e}] invalid bindTo "${l.bindTo}": must be "result", "error", or start with "data."`}}catch(c){let H=c instanceof Error?c.message:String(c);return {result:"failure",data:{},error:`[${e}] compute "${l.bindTo}" failed: ${H}`}}return u===void 0?{result:"failure",data:{},error:`[${e}] compute-jsonata: no "result" binding declared \u2014 add '- result = "success"' to expr`}:d?{result:u,data:i,error:d}:{result:u,data:i}}}function j(r,e,t,n){let{type:a,...s}=r,i={...s,whatToRun:typeof s.whatToRun=="object"?R(s.whatToRun):s.whatToRun};return async o=>{let u=o&&typeof o=="object"&&!Array.isArray(o)?{...o}:{};n&&(u.config=n);try{let d=await t(i,u);if(!r.outputTransforms)return d;try{return S(r.outputTransforms,d,e)}catch(l){let c=l instanceof Error?l.message:String(l);return {result:"failure",data:{},error:c}}}catch(d){let l=d instanceof Error?d.message:String(d);return {result:"failure",data:{error:`[step-machine-public] step "${e}" invoke threw: ${l}`}}}}}function E(){return async r=>({result:"success",data:r&&typeof r=="object"&&!Array.isArray(r)?r:{}})}function T(r,e,t){let n=Array.isArray(e?.produces_data)?e?.produces_data:void 0,a=Array.isArray(e?.input_validations)?e?.input_validations:void 0,s=e?.config??void 0,i=e?.handler,o;return x(i)?o=v(i,r,s):b(i)?o=j(i,r,t.invoke,s):o=E(),y(g(o,n),a,r)}function C(r,e){let t={};for(let[n,a]of Object.entries(r.steps??{}))t[n]=T(n,a,e);return t}
|
|
2
|
+
exports.buildStepHandlersForFlow=C;exports.createComputeJsonataHandler=v;exports.createPassthroughHandler=E;exports.createRefStepHandler=j;exports.filterProducedData=w;exports.isComputeJsonataSpec=x;exports.isRefSpec=b;exports.jsonata=p;exports.normalizeHandlerResult=m;exports.resolveStepHandler=T;exports.runInputValidations=k;exports.wrapWithInputValidations=y;exports.wrapWithOutputFiltering=g;//# sourceMappingURL=index.cjs.map
|
|
3
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/step-machine-public/jsonata-loader.ts","../../src/step-machine-public/result-utils.ts","../../src/cli/common/jsonata-loader.ts","../../src/cli/common/args-massaging.ts","../../src/cli/common/storage-interface.ts","../../src/step-machine-public/handler-factory.ts"],"names":["_require","createRequire","jsonata","normalizeHandlerResult","raw","stepName","obj","result","data","error","filterProducedData","produces","filtered","key","wrapWithOutputFiltering","handler","input","context","normalized","runInputValidations","validations","expr","err","msg","wrapWithInputValidations","failure","_loadJsonata","resolveOutputTransforms","transforms","label","ctx","val","REF_PREFIX","toBase64Url","utf8","buf","base64","binary","byte","serializeRef","ref","isComputeJsonataSpec","spec","isRefSpec","s","w","normalizeComputeStep","item","eq","deepSet","path","value","parts","cur","i","k","createComputeJsonataHandler","config","steps","expects_data","transitionResult","transitionError","step","createRefStepHandler","invoke","_t","refOnly","stepInput","createPassthroughHandler","resolveStepHandler","stepConfig","options","inputValidations","base","buildStepHandlersForFlow","flow","handlers"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * step-machine-public — jsonata loader\n *\n * Synchronous jsonata wrapper. Mirrors the loader pattern in\n * src/card-compute/index.ts — uses createRequire to load the vendored\n * synchronous CommonJS build.\n *\n * Runtime portability:\n * - Node ESM: createRequire works.\n * - Browser/cloud: package this lib for that runtime; the consumer ships\n * jsonata-sync.cjs alongside (tsup post-build does this automatically).\n */\n\nimport { createRequire } from 'module';\n\nconst _require = createRequire(import.meta.url);\n\nexport type JsonataExpression = {\n evaluate: (data: unknown) => unknown;\n};\n\nexport const jsonata: (expr: string) => JsonataExpression = _require('./jsonata-sync.cjs');\n","/**\n * step-machine-public — result utilities\n *\n * Pure helpers that:\n * - Normalize handler return shapes into NormalizedHandlerResult.\n * - Filter `data` to the keys declared in `produces_data`.\n * - Wrap a handler with output filtering / input validation.\n *\n * No transport, no I/O — only object reshaping.\n */\n\nimport type { NormalizedHandlerResult, StepHandler } from './types.js';\nimport { jsonata } from './jsonata-loader.js';\n\n// ============================================================================\n// normalizeHandlerResult — accept legacy or strict shape\n// ============================================================================\n\nexport function normalizeHandlerResult(\n raw: unknown,\n stepName: string,\n): NormalizedHandlerResult {\n if (!raw || typeof raw !== 'object') {\n throw new Error(`[step-machine-public] Step \"${stepName}\" returned a non-object result.`);\n }\n\n const obj = raw as Record<string, unknown>;\n const result = (obj.result ?? obj.status) as unknown;\n\n // Strict envelope: { result, data, error? }\n if (typeof result === 'string' && result.trim().length > 0) {\n const data: Record<string, unknown> =\n obj.data && typeof obj.data === 'object' && !Array.isArray(obj.data)\n ? { ...(obj.data as Record<string, unknown>) }\n : {};\n const error = typeof obj.error === 'string' ? (obj.error as string) : undefined;\n if (error && !('error' in data)) {\n data.error = error;\n }\n return { result, data, ...(error ? { error } : {}) };\n }\n\n // Bare object — treat the whole thing as data, intent = success.\n return { result: 'success', data: { ...obj } };\n}\n\n// ============================================================================\n// filterProducedData — narrow data to declared produces_data keys\n// ============================================================================\n\nexport function filterProducedData(\n data: Record<string, unknown>,\n produces: string[] | undefined,\n): Record<string, unknown> {\n if (!produces || produces.length === 0) return data;\n const filtered: Record<string, unknown> = {};\n for (const key of produces) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n filtered[key] = data[key];\n }\n }\n return filtered;\n}\n\n// ============================================================================\n// wrapWithOutputFiltering — compose normalization + produces_data filtering\n// ============================================================================\n\nexport function wrapWithOutputFiltering(\n handler: StepHandler,\n produces: string[] | undefined,\n): StepHandler {\n return async (input, context) => {\n const raw = await handler(input, context);\n const normalized = normalizeHandlerResult(raw, context?.stepName ?? 'unknown');\n return {\n result: normalized.result,\n data: filterProducedData(normalized.data, produces),\n ...(normalized.error ? { error: normalized.error } : {}),\n };\n };\n}\n\n// ============================================================================\n// runInputValidations — evaluate validation expressions\n// ============================================================================\n\n/**\n * Evaluate each validation as a JSONata expression returning truthy.\n *\n * Returns `null` on success, or a normalized failure result on the first\n * failed/throwing validation.\n */\nexport function runInputValidations(\n input: Record<string, unknown>,\n validations: string[] | undefined,\n stepName: string,\n): NormalizedHandlerResult | null {\n if (!validations || validations.length === 0) return null;\n for (const expr of validations) {\n try {\n const ok = jsonata(expr).evaluate(input);\n if (!ok) {\n return {\n result: 'failure',\n data: { error: `[${stepName}] input validation failed: ${expr}` },\n };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: 'failure',\n data: { error: `[${stepName}] input validation error on \"${expr}\": ${msg}` },\n };\n }\n }\n return null;\n}\n\n// ============================================================================\n// wrapWithInputValidations — short-circuit if any validation fails\n// ============================================================================\n\nexport function wrapWithInputValidations(\n handler: StepHandler,\n validations: string[] | undefined,\n stepName: string,\n): StepHandler {\n if (!validations || validations.length === 0) return handler;\n return async (input, context) => {\n const failure = runInputValidations(input, validations, stepName);\n if (failure) return failure;\n return handler(input, context);\n };\n}\n","/**\n * cli/common/jsonata-loader — synchronous jsonata wrapper.\n *\n * Mirrors the loader pattern used by card-compute. Uses createRequire so the\n * vendored CommonJS sync build can be loaded from ESM. The canonical source\n * file is `src/card-compute/jsonata-sync.cjs`; the tsup post-build hook copies\n * it next to every dist bundle that references it.\n */\n\nimport { createRequire } from 'module';\n\nconst _require = createRequire(import.meta.url);\n\nexport type JsonataExpression = {\n evaluate: (data: unknown) => unknown;\n};\n\n// Source path resolves via the file's location at src/cli/common/.\n// Dist path resolves via the post-build copy that places jsonata-sync.cjs\n// alongside the bundled output (handled by tsup's copyJsonataSyncToDistDirs).\nfunction _loadJsonata(): (expr: string) => JsonataExpression {\n // Try sibling first (dist layout). If that fails, fall back to the canonical\n // source location (used when running TypeScript directly under vitest/tsx).\n try {\n return _require('./jsonata-sync.cjs');\n } catch {\n return _require('../../card-compute/jsonata-sync.cjs');\n }\n}\n\nexport const jsonata: (expr: string) => JsonataExpression = _loadJsonata();\n","/**\n * cli/common/args-massaging — JSONata-based mapping from logical args to\n * transport-specific shape.\n *\n * `argsMassaging` is a property of `ExecutionRef`, so honoring it is the job\n * of every adapter (Node spawn, HTTP, Azure Function, etc.). This helper is\n * the shared pure-JSONata implementation reused by all adapters.\n *\n * Adapters call this as the first step inside their `invokeRefSync` /\n * `dispatchExecution` implementation, then perform their transport using\n * `cmdArgs` / `body` / `url`.\n */\n\nimport { jsonata } from './jsonata-loader.js';\nimport type { ArgsMassaging, OutputTransforms } from './execution-interface.js';\nimport type { NormalizedHandlerResult } from '../../step-machine-public/types.js';\n\nexport interface MassagedArgs {\n /** Resolved argv tail for local transports. */\n cmdArgs?: string[];\n /** Resolved request body for http transports (or stdin payload for local). */\n body?: unknown;\n /** Resolved final URL string for http transports. */\n url?: string;\n}\n\n/**\n * Evaluate `argsMassaging` against the supplied context.\n *\n * Throws with a label-tagged message if any expression fails. Adapters\n * should catch and convert to a normalized failure result.\n */\nexport function resolveArgsMassaging(\n argsMassaging: ArgsMassaging | undefined,\n context: Record<string, unknown>,\n label: string,\n): MassagedArgs {\n if (!argsMassaging || typeof argsMassaging !== 'object') return {};\n\n const out: MassagedArgs = {};\n\n if (Array.isArray(argsMassaging.cmdTemplate)) {\n const resolved: string[] = [];\n for (const expr of argsMassaging.cmdTemplate) {\n try {\n resolved.push(String(jsonata(expr).evaluate(context)));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.cmdTemplate failed on \"${expr}\": ${msg}`,\n );\n }\n }\n out.cmdArgs = resolved;\n }\n\n if (typeof argsMassaging.bodyTemplate === 'string') {\n try {\n out.body = jsonata(argsMassaging.bodyTemplate).evaluate(context);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.bodyTemplate failed: ${msg}`,\n );\n }\n }\n\n if (typeof argsMassaging.urlTemplate === 'string') {\n try {\n out.url = String(jsonata(argsMassaging.urlTemplate).evaluate(context));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.urlTemplate failed: ${msg}`,\n );\n }\n }\n\n return out;\n}\n\n/**\n * Apply `outputTransforms` to a raw invoke result.\n *\n * Context for all expressions: `{ output }` where `output` is the raw\n * { result, data, error? } envelope from invokeRefSync.\n *\n * Returns a new NormalizedHandlerResult with overrides applied.\n * Throws with a label-tagged message if any expression fails.\n */\nexport function resolveOutputTransforms(\n transforms: OutputTransforms | undefined,\n raw: NormalizedHandlerResult,\n label: string,\n): NormalizedHandlerResult {\n if (!transforms || typeof transforms !== 'object') return raw;\n\n const ctx = { output: raw };\n let result = raw.result;\n let data = raw.data;\n let error = raw.error;\n\n if (typeof transforms.resultExpr === 'string') {\n try {\n const val = jsonata(transforms.resultExpr).evaluate(ctx);\n if (typeof val !== 'string' || !val.trim()) {\n throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(val)})`);\n }\n result = val;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.resultExpr failed: ${msg}`);\n }\n }\n\n if (typeof transforms.dataTemplate === 'string') {\n try {\n const val = jsonata(transforms.dataTemplate).evaluate(ctx);\n if (!val || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(val)})`);\n }\n data = val as Record<string, unknown>;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.dataTemplate failed: ${msg}`);\n }\n }\n\n if (typeof transforms.errorExpr === 'string') {\n try {\n const val = jsonata(transforms.errorExpr).evaluate(ctx);\n // $undefined() evaluates to undefined — clears the error field\n error = val != null ? String(val) : undefined;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.errorExpr failed: ${msg}`);\n }\n }\n\n return error !== undefined\n ? { result, data, error }\n : { result, data };\n}\n","/**\n * storage-interface.ts\n *\n * Three minimal storage primitives that together cover all persistence needs\n * of the board-live-cards system. Any backend (Node fs, CosmosDB, Azure Blob,\n * browser localStorage, in-memory test double) implements these three interfaces.\n *\n * The pure-logic stores in board-live-cards-all-stores.ts depend only on these\n * interfaces — never on Node built-ins.\n *\n * Blob — raw string content at a logical, backend-neutral key\n * Journal — append-only log with cursor-based reads\n * KV — key-value store with list/delete\n *\n * Mapping to existing storage adapters:\n *\n * CardStorageAdapter\n * inventory (cardId → { blobRef, checksum, fileMetadata? }) → KV\n * card JSON files → Blob\n * source output files → Blob\n *\n * JournalStorageAdapter → Journal (board-journal.jsonl)\n *\n * ExecutionRequestStore → KV (keyed by journalId, via createFsKvStorage)\n *\n * StateSnapshotStorageAdapter\n * board-graph.json (packed single JSON, written atomically) → Blob\n * per-card sidecars (cards/<id>/runtime, fetched-sources-manifest) → KV\n */\n\n// ============================================================================\n// Blob — raw content at an opaque key\n//\n// The key is backend-specific (file path, blob name, storage key).\n// Text helpers are always available. Binary helpers are optional so existing\n// backends can adopt incrementally.\n// ============================================================================\n\nexport interface BlobStat {\n key: string;\n size: number;\n updatedAt?: string;\n contentType?: string;\n}\n\nexport interface BlobStorage {\n /** Returns raw content string, or null if the blob does not exist. */\n read(key: string): string | null;\n\n /** Write content at key. Implementations should be atomic (write-rename). */\n write(key: string, content: string): void;\n\n /** Returns true if a blob exists at key. */\n exists(key: string): boolean;\n\n /** Delete the blob at key. No-op if it does not exist. */\n remove(key: string): void;\n\n /** Optional binary read for file-like artifacts. */\n readBytes?(key: string): Uint8Array | null;\n\n /** Optional binary write for file-like artifacts. */\n writeBytes?(key: string, content: Uint8Array): void;\n\n /** Optional key listing by prefix. */\n listKeys?(prefix?: string): string[];\n\n /** Optional metadata lookup. */\n stat?(key: string): BlobStat | null;\n}\n\n// ============================================================================\n// KindValueRef — backend-neutral typed reference\n//\n// A ref describes WHERE content lives without carrying the bytes.\n// Serialized on the CLI wire as: b64:<base64url({\"kind\":\"...\",\"value\":\"...\"})>\n// kind = 'fs-path': value is an absolute file path\n// Additional kinds (e.g. 'cosmos') are added in public-storage-adapter.ts as new backends are supported.\n// ============================================================================\n\nexport interface KindValueRef {\n readonly kind: string;\n readonly value: string;\n}\n\nconst REF_PREFIX = 'b64:';\n\nfunction toBase64Url(raw: string): string {\n const utf8 = new TextEncoder().encode(raw);\n const buf = (globalThis as { Buffer?: { from(data: Uint8Array): { toString(enc: string): string } } }).Buffer;\n let base64: string;\n if (buf) {\n base64 = buf.from(utf8).toString('base64');\n } else if (typeof btoa === 'function') {\n let binary = '';\n for (const byte of utf8) binary += String.fromCharCode(byte);\n base64 = btoa(binary);\n } else {\n throw new Error('No base64 encoder available in this runtime');\n }\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction fromBase64Url(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/')\n + '='.repeat((4 - (input.length % 4)) % 4);\n const buf = (globalThis as { Buffer?: { from(data: string, enc: string): { toString(enc: string): string } } }).Buffer;\n if (buf) return buf.from(base64, 'base64').toString('utf8');\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n throw new Error('No base64 decoder available in this runtime');\n}\n\n/** Serialize a KindValueRef to the wire format: b64:<base64url(json)> */\nexport function serializeRef(ref: KindValueRef): string {\n return `${REF_PREFIX}${toBase64Url(JSON.stringify(ref))}`;\n}\n\n/** Parse a wire-format ref string (b64:<base64url(json)>) into a KindValueRef. */\nexport function parseRef(s: string): KindValueRef {\n if (!s.startsWith(REF_PREFIX)) throw new Error(`Invalid ref format (expected ${REF_PREFIX}<base64url(json)>): ${s}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(fromBase64Url(s.slice(REF_PREFIX.length)));\n } catch {\n throw new Error(`Invalid ref format (malformed base64url/json): ${s}`);\n }\n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid ref format (expected object payload): ${s}`);\n }\n const candidate = parsed as { kind?: unknown; value?: unknown };\n if (typeof candidate.kind !== 'string' || typeof candidate.value !== 'string') {\n throw new Error(`Invalid ref format (payload must contain string kind/value): ${s}`);\n }\n return { kind: candidate.kind, value: candidate.value };\n}\n\n// ============================================================================\n// Journal — append-only log, cursor-based reads\n//\n// Each entry has a string id (UUID or monotonic token) and an opaque payload.\n// Cursors are entry ids — readAfter returns entries strictly after that id.\n// A null/empty cursor means \"read from the beginning\".\n// ============================================================================\n\nexport interface JournalEntry {\n id: string;\n payload: unknown;\n}\n\nexport interface JournalReadResult {\n entries: JournalEntry[];\n /** The id of the last entry returned, suitable for use as the next cursor. */\n newCursor: string | null;\n}\n\nexport interface JournalStorage {\n /** Append an entry. The storage layer assigns the id. */\n append(payload: unknown): JournalEntry;\n\n /** Read ALL entries (for index rebuilds, full replay). */\n readAll(): JournalEntry[];\n\n /**\n * Read entries appended after the given cursor id.\n * If cursor is null/empty, returns all entries from the beginning.\n */\n readAfter(cursor: string | null): JournalReadResult;\n}\n\n// ============================================================================\n// KV — key-value store with list and delete\n//\n// Values are opaque unknown — callers own serialisation.\n// Keys are scoped by the adapter factory (e.g. a boardDir prefix is closed\n// over in the adapter, not passed per-call).\n// ============================================================================\n\nexport interface KVStorage {\n /** Returns the stored value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /**\n * List all keys, optionally filtered to those starting with prefix.\n * Order is implementation-defined.\n */\n listKeys(prefix?: string): string[];\n}\n\n// ============================================================================\n// JSONStorage — KV store with JSON-aware merge operations\n//\n// Backed by KVStorage under the hood. Adds deepMerge and shallowMerge so\n// callers never need to read-modify-write manually for partial updates.\n// ============================================================================\n\nexport interface JSONStorage {\n /** Returns the stored JSON value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /**\n * Read a nested value inside the stored object using a dot-notation path.\n * e.g. get('myKey', 'a.b.c') returns the value at { a: { b: { c: ... } } }.\n * Returns null if the key does not exist or the path cannot be traversed.\n */\n get(key: string, jsonPath: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /** List all keys, optionally filtered by prefix. */\n listKeys(prefix?: string): string[];\n\n /**\n * Shallow-merge patch into the existing object at key.\n * Equivalent to: write(key, { ...read(key), ...patch })\n * Creates the key if it does not exist.\n */\n shallowMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Deep-merge patch into the existing object at key.\n * Recursively merges nested plain objects; arrays and primitives are replaced.\n * Creates the key if it does not exist.\n */\n deepMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Set a nested value inside the stored object using a dot-notation path.\n * e.g. patch('myKey', 'a.b.c', 42) sets { a: { b: { c: 42 } } } into the stored object.\n * Intermediate objects are created if absent. Arrays are not traversed — use integer\n * segments to index into them (e.g. 'items.0.name').\n * Creates the top-level key if it does not exist.\n */\n patch(key: string, jsonPath: string, value: unknown): void;\n}\n\n// ============================================================================\n// StorageProvider — aggregate of all three primitives\n//\n// Adapter factories receive a StorageProvider and close over any scope (e.g.\n// boardDir) themselves. This is the single injection point for swapping\n// backends (Node fs → CosmosDB, browser localStorage, test doubles, etc.).\n// ============================================================================\n\nexport interface StorageProvider {\n blob: BlobStorage;\n journal: JournalStorage;\n kv: KVStorage;\n}\n\n// ============================================================================\n// AtomicRelayLock — non-blocking try-acquire lock with relay-on-busy semantics\n//\n// This interface serves TWO tightly coupled purposes which are intentionally\n// unified into a single primitive:\n//\n// 1. ATOMICITY — ensures that a read-mutate-save cycle is executed by at\n// most one actor at a time, preventing concurrent actors from racing on\n// stale state and writing conflicting snapshots.\n//\n// 2. RELAY SIGNAL — when tryAcquire() returns null, the caller knows the\n// cycle is already in progress. Because the holder always reads fresh\n// state upon entry, it will pick up every change appended by the skipping\n// caller before the lock was attempted. The caller can therefore safely\n// exit — its work will be completed by the holder. This is the\n// \"relay baton\" pattern: the lock being held IS the in-progress signal.\n//\n// These two purposes are not an accidental overload — they are the same\n// invariant expressed at different scopes. Any backend implementation\n// (FS lockfile, Cosmos document lease, Azure entity lock, in-memory flag)\n// that satisfies \"at most one holder at a time\" automatically satisfies both.\n//\n// Contract:\n// - tryAcquire() is non-blocking. It never waits.\n// - Returns a release function on success, or null if already held.\n// - The release function must be called exactly once (use try/finally).\n// - Behaviour after calling release() more than once is undefined.\n// ============================================================================\n\nexport interface AtomicRelayLock {\n /**\n * Attempt to acquire the lock without blocking.\n * Returns a `release` function if successful, or `null` if the lock is\n * already held by another actor (relay: that actor will complete the work).\n */\n tryAcquire(): (() => void) | null;\n}\n\n/**\n * Execute `work` under an `AtomicRelayLock`.\n *\n * - If the lock is busy, returns false immediately (relay: the holder will\n * complete the work on behalf of this caller).\n * - If acquired, runs `work` exclusively, releases the lock, then calls\n * `continuation` if provided — allowing the caller to schedule the next\n * cycle (e.g. spawn a detached process) after the lock is free.\n * - Returns true if work ran.\n */\nexport async function withRelayLock(\n lock: AtomicRelayLock,\n work: () => Promise<void>,\n continuation?: () => void,\n): Promise<boolean> {\n const release = lock.tryAcquire();\n if (!release) return false; // relay: holder is already doing the work\n try {\n await work();\n } finally {\n release(); // release before continuation so it can immediately re-acquire\n }\n continuation?.();\n return true;\n}\n","/**\n * step-machine-public — handler factory\n *\n * Builds engine-facing StepHandlers from declarative HandlerSpec entries.\n * Pure: no Node imports, no transport. Refs are dispatched through the\n * caller-supplied `InvokeFn`, which is the single boundary between this lib\n * and any transport (Node spawn, HTTP, Azure Function, etc.).\n *\n * Layering:\n *\n * step-machine (pure FSM) — runs handlers, never builds them.\n * step-machine-public (this lib) — declarative spec → StepHandler map.\n * adapter (e.g. node-spawn-invoker) — InvokeFn implementation per transport.\n * step-machine-cli (thin shell) — wires adapter + flow loader + run.\n */\n\nimport { jsonata } from './jsonata-loader.js';\nimport { wrapWithInputValidations, wrapWithOutputFiltering } from './result-utils.js';\nimport { resolveOutputTransforms } from '../cli/common/args-massaging.js';\nimport { serializeRef } from '../cli/common/storage-interface.js';\nimport type {\n ComputeJsonataSpec,\n HandlerSpec,\n InvokeRefFn,\n NormalizedHandlerResult,\n RefSpec,\n StepConfigForFactory,\n StepHandler,\n} from './types.js';\n\n// ============================================================================\n// Discriminators\n// ============================================================================\n\nexport function isComputeJsonataSpec(spec: unknown): spec is ComputeJsonataSpec {\n return (\n !!spec &&\n typeof spec === 'object' &&\n (spec as Record<string, unknown>).type === 'compute-jsonata' &&\n Array.isArray((spec as Record<string, unknown>).expr) &&\n ((spec as Record<string, unknown>).expr as unknown[]).length > 0\n );\n}\n\nexport function isRefSpec(spec: unknown): spec is RefSpec {\n if (!spec || typeof spec !== 'object') return false;\n const s = spec as Record<string, unknown>;\n if (s.type !== 'ref' || typeof s.howToRun !== 'string') return false;\n if (typeof s.whatToRun === 'string') return true;\n if (s.whatToRun && typeof s.whatToRun === 'object') {\n const w = s.whatToRun as Record<string, unknown>;\n return typeof w.kind === 'string' && typeof w.value === 'string';\n }\n return false;\n}\n\n// ============================================================================\n// Compute-jsonata handler\n// ============================================================================\n\ninterface NormalizedComputeStep {\n bindTo: string;\n expr: string;\n}\n\nfunction normalizeComputeStep(item: string | { bindTo: string; expr: string }): NormalizedComputeStep {\n if (typeof item === 'string') {\n const eq = item.indexOf('=');\n if (eq < 1) {\n throw new Error(`[step-machine-public] Invalid compute expression (missing \"=\"): \"${item}\"`);\n }\n return { bindTo: item.slice(0, eq).trim(), expr: item.slice(eq + 1).trim() };\n }\n if (item && typeof item === 'object' && typeof item.bindTo === 'string' && typeof item.expr === 'string') {\n return item;\n }\n throw new Error(`[step-machine-public] Invalid compute step: ${JSON.stringify(item)}`);\n}\n\n/** Mutate nested dict via dot-path key. */\nfunction deepSet(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split('.');\n let cur: Record<string, unknown> = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i];\n if (cur[k] == null || typeof cur[k] !== 'object') cur[k] = {};\n cur = cur[k] as Record<string, unknown>;\n }\n cur[parts[parts.length - 1]] = value;\n}\n\nexport function createComputeJsonataHandler(\n spec: ComputeJsonataSpec,\n stepName: string,\n config?: Record<string, unknown>,\n): StepHandler {\n const steps = spec.expr.map(normalizeComputeStep);\n return async (input) => {\n const expects_data: Record<string, unknown> =\n input && typeof input === 'object' && !Array.isArray(input)\n ? { ...input }\n : {};\n\n // `data` accumulates computed outputs; it is placed in ctx by reference\n // so subsequent expressions can read `data.x` after earlier steps set it.\n const data: Record<string, unknown> = {};\n\n // Context shape:\n // expects_data — named namespace for declared step inputs (from flow state)\n // data — accumulating output namespace (required, mutated by reference)\n // config — optional step-level config\n const ctx: Record<string, unknown> = {\n expects_data,\n data, // same reference — mutations visible in later steps\n ...(config ? { config } : {}),\n };\n\n let transitionResult: string | undefined;\n let transitionError: string | undefined;\n\n for (const step of steps) {\n try {\n const val = jsonata(step.expr).evaluate(ctx);\n\n if (step.bindTo === 'result') {\n // Transition outcome\n transitionResult = val != null ? String(val) : 'success';\n } else if (step.bindTo === 'error') {\n // Transition error detail\n transitionError = val != null ? String(val) : undefined;\n } else if (step.bindTo.startsWith('data.')) {\n // Namespaced output — mutates the shared data reference\n deepSet(data, step.bindTo.slice('data.'.length), val);\n } else {\n return {\n result: 'failure',\n data: {},\n error: `[${stepName}] invalid bindTo \"${step.bindTo}\": must be \"result\", \"error\", or start with \"data.\"`,\n };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: 'failure',\n data: {},\n error: `[${stepName}] compute \"${step.bindTo}\" failed: ${msg}`,\n };\n }\n }\n\n if (transitionResult === undefined) {\n return {\n result: 'failure',\n data: {},\n error: `[${stepName}] compute-jsonata: no \"result\" binding declared — add '- result = \"success\"' to expr`,\n };\n }\n return transitionError\n ? { result: transitionResult, data, error: transitionError }\n : { result: transitionResult, data };\n };\n}\n\n// ============================================================================\n// Ref handler — dispatches via InvokeFn\n// ============================================================================\n\nexport function createRefStepHandler(\n spec: RefSpec,\n stepName: string,\n invoke: InvokeRefFn,\n config?: Record<string, unknown>,\n): StepHandler {\n // The handler spec itself is a superset of ExecutionRef. Strip the discriminator\n // before passing to the adapter so it sees a plain ExecutionRef.\n // Normalize whatToRun from object form { kind, value } → b64 string.\n const { type: _t, ...refOnly } = spec;\n const ref = {\n ...refOnly,\n whatToRun: typeof refOnly.whatToRun === 'object'\n ? serializeRef(refOnly.whatToRun)\n : refOnly.whatToRun,\n };\n\n return async (input) => {\n const stepInput: Record<string, unknown> =\n input && typeof input === 'object' && !Array.isArray(input)\n ? { ...input }\n : {};\n if (config) stepInput.config = config;\n\n try {\n const raw = await invoke(ref, stepInput);\n if (!spec.outputTransforms) return raw;\n try {\n return resolveOutputTransforms(spec.outputTransforms, raw, stepName);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { result: 'failure', data: {}, error: msg };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: 'failure',\n data: { error: `[step-machine-public] step \"${stepName}\" invoke threw: ${msg}` },\n };\n }\n };\n}\n\n// ============================================================================\n// Passthrough handler\n// ============================================================================\n\nexport function createPassthroughHandler(): StepHandler {\n return async (input) => {\n const data: Record<string, unknown> =\n input && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n return { result: 'success', data };\n };\n}\n\n// ============================================================================\n// resolveStepHandler — pick + decorate the right handler for a step\n// ============================================================================\n\nexport interface ResolveStepHandlerOptions {\n invoke: InvokeRefFn;\n}\n\nexport function resolveStepHandler(\n stepName: string,\n stepConfig: StepConfigForFactory | undefined,\n options: ResolveStepHandlerOptions,\n): StepHandler {\n const produces = Array.isArray(stepConfig?.produces_data) ? stepConfig?.produces_data : undefined;\n const inputValidations = Array.isArray(stepConfig?.input_validations)\n ? stepConfig?.input_validations\n : undefined;\n const config = stepConfig?.config ?? undefined;\n const spec: HandlerSpec | undefined = stepConfig?.handler;\n\n let base: StepHandler;\n if (isComputeJsonataSpec(spec)) {\n // compute-jsonata: validations are baked in via the wrapper as well; both work.\n base = createComputeJsonataHandler(spec, stepName, config);\n } else if (isRefSpec(spec)) {\n base = createRefStepHandler(spec, stepName, options.invoke, config);\n } else {\n base = createPassthroughHandler();\n }\n\n return wrapWithInputValidations(\n wrapWithOutputFiltering(base, produces),\n inputValidations,\n stepName,\n );\n}\n\n// ============================================================================\n// buildStepHandlersForFlow — produce the Record<stepName, StepHandler> map\n// ============================================================================\n\nexport interface BuildStepHandlersOptions {\n invoke: InvokeRefFn;\n}\n\nexport function buildStepHandlersForFlow(\n flow: { steps?: Record<string, StepConfigForFactory> },\n options: BuildStepHandlersOptions,\n): Record<string, StepHandler> {\n const handlers: Record<string, StepHandler> = {};\n for (const [stepName, stepConfig] of Object.entries(flow.steps ?? {})) {\n handlers[stepName] = resolveStepHandler(stepName, stepConfig, options);\n }\n return handlers;\n}\n\n// Re-export for adapter convenience.\nexport type { NormalizedHandlerResult };\n"]}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { ExecutionRef } from '../execution-refs.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* step-machine-public — types
|
|
5
|
+
*
|
|
6
|
+
* Platform-free types for the declarative handler model.
|
|
7
|
+
* No Node imports. Safe for any runtime (Node, browser, Python via codegen, etc.).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The single normalized shape the engine consumes.
|
|
12
|
+
*
|
|
13
|
+
* - `result` drives transitions (e.g. 'success' | 'failure' | 'timeout' | <custom>)
|
|
14
|
+
* - `data` drives produces_data projection into flow context
|
|
15
|
+
* - `error` optional human-readable failure detail
|
|
16
|
+
*
|
|
17
|
+
* Adapters MUST normalize their transport-specific output into this shape
|
|
18
|
+
* before returning. The engine never inspects payload format.
|
|
19
|
+
*/
|
|
20
|
+
interface NormalizedHandlerResult {
|
|
21
|
+
result: string;
|
|
22
|
+
data: Record<string, unknown>;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Pure JSONata compute step.
|
|
27
|
+
* Each `expr` entry is `"<bindTo> = <jsonata-expression>"` or
|
|
28
|
+
* `{ bindTo: "...", expr: "..." }`.
|
|
29
|
+
*
|
|
30
|
+
* Evaluated sequentially against the flat flow context; each binding is added
|
|
31
|
+
* before the next expression is evaluated.
|
|
32
|
+
*/
|
|
33
|
+
interface ComputeJsonataSpec {
|
|
34
|
+
type: 'compute-jsonata';
|
|
35
|
+
expr: Array<string | {
|
|
36
|
+
bindTo: string;
|
|
37
|
+
expr: string;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* External reference step. The handler spec IS an ExecutionRef plus a
|
|
42
|
+
* `type: 'ref'` discriminator.
|
|
43
|
+
*
|
|
44
|
+
* The engine never invokes refs directly — invocation is delegated to an
|
|
45
|
+
* `InvokeFn` adapter (e.g. Node spawn, HTTP, Azure Function).
|
|
46
|
+
*
|
|
47
|
+
* `whatToRun` may be either:
|
|
48
|
+
* - a `b64:<base64url(json)>` wire string (programmatically generated)
|
|
49
|
+
* - a plain `{ kind, value }` object (human-authored flow files)
|
|
50
|
+
*
|
|
51
|
+
* The handler factory normalizes the object form via `serializeRef` before
|
|
52
|
+
* dispatching, so downstream adapters always receive the string form.
|
|
53
|
+
*/
|
|
54
|
+
interface RefSpec extends ExecutionRef {
|
|
55
|
+
type: 'ref';
|
|
56
|
+
}
|
|
57
|
+
type HandlerSpec = ComputeJsonataSpec | RefSpec;
|
|
58
|
+
/**
|
|
59
|
+
* Single invocation boundary. The framework calls this for every ref step;
|
|
60
|
+
* the adapter (Node spawn / HTTP / Azure Function / etc.) decides how to
|
|
61
|
+
* actually invoke the ref and normalizes the outcome to {result, data, error?}.
|
|
62
|
+
*
|
|
63
|
+
* `args` is the flat flow context for the step. The adapter is responsible
|
|
64
|
+
* for honoring `ref.argsMassaging` (cmdTemplate / urlTemplate / bodyTemplate)
|
|
65
|
+
* before performing the transport.
|
|
66
|
+
*
|
|
67
|
+
* May return synchronously (sync transports) or as a Promise (async transports).
|
|
68
|
+
* The framework awaits regardless.
|
|
69
|
+
*/
|
|
70
|
+
type InvokeRefFn = (ref: ExecutionRef, args: Record<string, unknown>) => NormalizedHandlerResult | Promise<NormalizedHandlerResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Handler signature consumed by the existing pure step machine.
|
|
73
|
+
*
|
|
74
|
+
* (Mirrors the StepHandler type in src/step-machine/types.ts but typed in
|
|
75
|
+
* platform-free terms.)
|
|
76
|
+
*/
|
|
77
|
+
type StepHandler = (input: Record<string, unknown>, context?: {
|
|
78
|
+
stepName?: string;
|
|
79
|
+
runId?: string;
|
|
80
|
+
}) => Promise<NormalizedHandlerResult>;
|
|
81
|
+
/**
|
|
82
|
+
* The subset of step configuration the handler factory consumes.
|
|
83
|
+
*
|
|
84
|
+
* (We do NOT re-export StepFlowConfig here — that lives in src/step-machine/.
|
|
85
|
+
* This is just the shape the factory needs.)
|
|
86
|
+
*/
|
|
87
|
+
interface StepConfigForFactory {
|
|
88
|
+
handler?: HandlerSpec;
|
|
89
|
+
produces_data?: string[];
|
|
90
|
+
input_validations?: string[];
|
|
91
|
+
config?: Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* step-machine-public — handler factory
|
|
96
|
+
*
|
|
97
|
+
* Builds engine-facing StepHandlers from declarative HandlerSpec entries.
|
|
98
|
+
* Pure: no Node imports, no transport. Refs are dispatched through the
|
|
99
|
+
* caller-supplied `InvokeFn`, which is the single boundary between this lib
|
|
100
|
+
* and any transport (Node spawn, HTTP, Azure Function, etc.).
|
|
101
|
+
*
|
|
102
|
+
* Layering:
|
|
103
|
+
*
|
|
104
|
+
* step-machine (pure FSM) — runs handlers, never builds them.
|
|
105
|
+
* step-machine-public (this lib) — declarative spec → StepHandler map.
|
|
106
|
+
* adapter (e.g. node-spawn-invoker) — InvokeFn implementation per transport.
|
|
107
|
+
* step-machine-cli (thin shell) — wires adapter + flow loader + run.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
declare function isComputeJsonataSpec(spec: unknown): spec is ComputeJsonataSpec;
|
|
111
|
+
declare function isRefSpec(spec: unknown): spec is RefSpec;
|
|
112
|
+
declare function createComputeJsonataHandler(spec: ComputeJsonataSpec, stepName: string, config?: Record<string, unknown>): StepHandler;
|
|
113
|
+
declare function createRefStepHandler(spec: RefSpec, stepName: string, invoke: InvokeRefFn, config?: Record<string, unknown>): StepHandler;
|
|
114
|
+
declare function createPassthroughHandler(): StepHandler;
|
|
115
|
+
interface ResolveStepHandlerOptions {
|
|
116
|
+
invoke: InvokeRefFn;
|
|
117
|
+
}
|
|
118
|
+
declare function resolveStepHandler(stepName: string, stepConfig: StepConfigForFactory | undefined, options: ResolveStepHandlerOptions): StepHandler;
|
|
119
|
+
interface BuildStepHandlersOptions {
|
|
120
|
+
invoke: InvokeRefFn;
|
|
121
|
+
}
|
|
122
|
+
declare function buildStepHandlersForFlow(flow: {
|
|
123
|
+
steps?: Record<string, StepConfigForFactory>;
|
|
124
|
+
}, options: BuildStepHandlersOptions): Record<string, StepHandler>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* step-machine-public — result utilities
|
|
128
|
+
*
|
|
129
|
+
* Pure helpers that:
|
|
130
|
+
* - Normalize handler return shapes into NormalizedHandlerResult.
|
|
131
|
+
* - Filter `data` to the keys declared in `produces_data`.
|
|
132
|
+
* - Wrap a handler with output filtering / input validation.
|
|
133
|
+
*
|
|
134
|
+
* No transport, no I/O — only object reshaping.
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
declare function normalizeHandlerResult(raw: unknown, stepName: string): NormalizedHandlerResult;
|
|
138
|
+
declare function filterProducedData(data: Record<string, unknown>, produces: string[] | undefined): Record<string, unknown>;
|
|
139
|
+
declare function wrapWithOutputFiltering(handler: StepHandler, produces: string[] | undefined): StepHandler;
|
|
140
|
+
/**
|
|
141
|
+
* Evaluate each validation as a JSONata expression returning truthy.
|
|
142
|
+
*
|
|
143
|
+
* Returns `null` on success, or a normalized failure result on the first
|
|
144
|
+
* failed/throwing validation.
|
|
145
|
+
*/
|
|
146
|
+
declare function runInputValidations(input: Record<string, unknown>, validations: string[] | undefined, stepName: string): NormalizedHandlerResult | null;
|
|
147
|
+
declare function wrapWithInputValidations(handler: StepHandler, validations: string[] | undefined, stepName: string): StepHandler;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* step-machine-public — jsonata loader
|
|
151
|
+
*
|
|
152
|
+
* Synchronous jsonata wrapper. Mirrors the loader pattern in
|
|
153
|
+
* src/card-compute/index.ts — uses createRequire to load the vendored
|
|
154
|
+
* synchronous CommonJS build.
|
|
155
|
+
*
|
|
156
|
+
* Runtime portability:
|
|
157
|
+
* - Node ESM: createRequire works.
|
|
158
|
+
* - Browser/cloud: package this lib for that runtime; the consumer ships
|
|
159
|
+
* jsonata-sync.cjs alongside (tsup post-build does this automatically).
|
|
160
|
+
*/
|
|
161
|
+
type JsonataExpression = {
|
|
162
|
+
evaluate: (data: unknown) => unknown;
|
|
163
|
+
};
|
|
164
|
+
declare const jsonata: (expr: string) => JsonataExpression;
|
|
165
|
+
|
|
166
|
+
export { type BuildStepHandlersOptions, type ComputeJsonataSpec, type HandlerSpec, type InvokeRefFn, type JsonataExpression, type NormalizedHandlerResult, type RefSpec, type ResolveStepHandlerOptions, type StepConfigForFactory, type StepHandler, buildStepHandlersForFlow, createComputeJsonataHandler, createPassthroughHandler, createRefStepHandler, filterProducedData, isComputeJsonataSpec, isRefSpec, jsonata, normalizeHandlerResult, resolveStepHandler, runInputValidations, wrapWithInputValidations, wrapWithOutputFiltering };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { ExecutionRef } from '../execution-refs.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* step-machine-public — types
|
|
5
|
+
*
|
|
6
|
+
* Platform-free types for the declarative handler model.
|
|
7
|
+
* No Node imports. Safe for any runtime (Node, browser, Python via codegen, etc.).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The single normalized shape the engine consumes.
|
|
12
|
+
*
|
|
13
|
+
* - `result` drives transitions (e.g. 'success' | 'failure' | 'timeout' | <custom>)
|
|
14
|
+
* - `data` drives produces_data projection into flow context
|
|
15
|
+
* - `error` optional human-readable failure detail
|
|
16
|
+
*
|
|
17
|
+
* Adapters MUST normalize their transport-specific output into this shape
|
|
18
|
+
* before returning. The engine never inspects payload format.
|
|
19
|
+
*/
|
|
20
|
+
interface NormalizedHandlerResult {
|
|
21
|
+
result: string;
|
|
22
|
+
data: Record<string, unknown>;
|
|
23
|
+
error?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Pure JSONata compute step.
|
|
27
|
+
* Each `expr` entry is `"<bindTo> = <jsonata-expression>"` or
|
|
28
|
+
* `{ bindTo: "...", expr: "..." }`.
|
|
29
|
+
*
|
|
30
|
+
* Evaluated sequentially against the flat flow context; each binding is added
|
|
31
|
+
* before the next expression is evaluated.
|
|
32
|
+
*/
|
|
33
|
+
interface ComputeJsonataSpec {
|
|
34
|
+
type: 'compute-jsonata';
|
|
35
|
+
expr: Array<string | {
|
|
36
|
+
bindTo: string;
|
|
37
|
+
expr: string;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* External reference step. The handler spec IS an ExecutionRef plus a
|
|
42
|
+
* `type: 'ref'` discriminator.
|
|
43
|
+
*
|
|
44
|
+
* The engine never invokes refs directly — invocation is delegated to an
|
|
45
|
+
* `InvokeFn` adapter (e.g. Node spawn, HTTP, Azure Function).
|
|
46
|
+
*
|
|
47
|
+
* `whatToRun` may be either:
|
|
48
|
+
* - a `b64:<base64url(json)>` wire string (programmatically generated)
|
|
49
|
+
* - a plain `{ kind, value }` object (human-authored flow files)
|
|
50
|
+
*
|
|
51
|
+
* The handler factory normalizes the object form via `serializeRef` before
|
|
52
|
+
* dispatching, so downstream adapters always receive the string form.
|
|
53
|
+
*/
|
|
54
|
+
interface RefSpec extends ExecutionRef {
|
|
55
|
+
type: 'ref';
|
|
56
|
+
}
|
|
57
|
+
type HandlerSpec = ComputeJsonataSpec | RefSpec;
|
|
58
|
+
/**
|
|
59
|
+
* Single invocation boundary. The framework calls this for every ref step;
|
|
60
|
+
* the adapter (Node spawn / HTTP / Azure Function / etc.) decides how to
|
|
61
|
+
* actually invoke the ref and normalizes the outcome to {result, data, error?}.
|
|
62
|
+
*
|
|
63
|
+
* `args` is the flat flow context for the step. The adapter is responsible
|
|
64
|
+
* for honoring `ref.argsMassaging` (cmdTemplate / urlTemplate / bodyTemplate)
|
|
65
|
+
* before performing the transport.
|
|
66
|
+
*
|
|
67
|
+
* May return synchronously (sync transports) or as a Promise (async transports).
|
|
68
|
+
* The framework awaits regardless.
|
|
69
|
+
*/
|
|
70
|
+
type InvokeRefFn = (ref: ExecutionRef, args: Record<string, unknown>) => NormalizedHandlerResult | Promise<NormalizedHandlerResult>;
|
|
71
|
+
/**
|
|
72
|
+
* Handler signature consumed by the existing pure step machine.
|
|
73
|
+
*
|
|
74
|
+
* (Mirrors the StepHandler type in src/step-machine/types.ts but typed in
|
|
75
|
+
* platform-free terms.)
|
|
76
|
+
*/
|
|
77
|
+
type StepHandler = (input: Record<string, unknown>, context?: {
|
|
78
|
+
stepName?: string;
|
|
79
|
+
runId?: string;
|
|
80
|
+
}) => Promise<NormalizedHandlerResult>;
|
|
81
|
+
/**
|
|
82
|
+
* The subset of step configuration the handler factory consumes.
|
|
83
|
+
*
|
|
84
|
+
* (We do NOT re-export StepFlowConfig here — that lives in src/step-machine/.
|
|
85
|
+
* This is just the shape the factory needs.)
|
|
86
|
+
*/
|
|
87
|
+
interface StepConfigForFactory {
|
|
88
|
+
handler?: HandlerSpec;
|
|
89
|
+
produces_data?: string[];
|
|
90
|
+
input_validations?: string[];
|
|
91
|
+
config?: Record<string, unknown>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* step-machine-public — handler factory
|
|
96
|
+
*
|
|
97
|
+
* Builds engine-facing StepHandlers from declarative HandlerSpec entries.
|
|
98
|
+
* Pure: no Node imports, no transport. Refs are dispatched through the
|
|
99
|
+
* caller-supplied `InvokeFn`, which is the single boundary between this lib
|
|
100
|
+
* and any transport (Node spawn, HTTP, Azure Function, etc.).
|
|
101
|
+
*
|
|
102
|
+
* Layering:
|
|
103
|
+
*
|
|
104
|
+
* step-machine (pure FSM) — runs handlers, never builds them.
|
|
105
|
+
* step-machine-public (this lib) — declarative spec → StepHandler map.
|
|
106
|
+
* adapter (e.g. node-spawn-invoker) — InvokeFn implementation per transport.
|
|
107
|
+
* step-machine-cli (thin shell) — wires adapter + flow loader + run.
|
|
108
|
+
*/
|
|
109
|
+
|
|
110
|
+
declare function isComputeJsonataSpec(spec: unknown): spec is ComputeJsonataSpec;
|
|
111
|
+
declare function isRefSpec(spec: unknown): spec is RefSpec;
|
|
112
|
+
declare function createComputeJsonataHandler(spec: ComputeJsonataSpec, stepName: string, config?: Record<string, unknown>): StepHandler;
|
|
113
|
+
declare function createRefStepHandler(spec: RefSpec, stepName: string, invoke: InvokeRefFn, config?: Record<string, unknown>): StepHandler;
|
|
114
|
+
declare function createPassthroughHandler(): StepHandler;
|
|
115
|
+
interface ResolveStepHandlerOptions {
|
|
116
|
+
invoke: InvokeRefFn;
|
|
117
|
+
}
|
|
118
|
+
declare function resolveStepHandler(stepName: string, stepConfig: StepConfigForFactory | undefined, options: ResolveStepHandlerOptions): StepHandler;
|
|
119
|
+
interface BuildStepHandlersOptions {
|
|
120
|
+
invoke: InvokeRefFn;
|
|
121
|
+
}
|
|
122
|
+
declare function buildStepHandlersForFlow(flow: {
|
|
123
|
+
steps?: Record<string, StepConfigForFactory>;
|
|
124
|
+
}, options: BuildStepHandlersOptions): Record<string, StepHandler>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* step-machine-public — result utilities
|
|
128
|
+
*
|
|
129
|
+
* Pure helpers that:
|
|
130
|
+
* - Normalize handler return shapes into NormalizedHandlerResult.
|
|
131
|
+
* - Filter `data` to the keys declared in `produces_data`.
|
|
132
|
+
* - Wrap a handler with output filtering / input validation.
|
|
133
|
+
*
|
|
134
|
+
* No transport, no I/O — only object reshaping.
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
declare function normalizeHandlerResult(raw: unknown, stepName: string): NormalizedHandlerResult;
|
|
138
|
+
declare function filterProducedData(data: Record<string, unknown>, produces: string[] | undefined): Record<string, unknown>;
|
|
139
|
+
declare function wrapWithOutputFiltering(handler: StepHandler, produces: string[] | undefined): StepHandler;
|
|
140
|
+
/**
|
|
141
|
+
* Evaluate each validation as a JSONata expression returning truthy.
|
|
142
|
+
*
|
|
143
|
+
* Returns `null` on success, or a normalized failure result on the first
|
|
144
|
+
* failed/throwing validation.
|
|
145
|
+
*/
|
|
146
|
+
declare function runInputValidations(input: Record<string, unknown>, validations: string[] | undefined, stepName: string): NormalizedHandlerResult | null;
|
|
147
|
+
declare function wrapWithInputValidations(handler: StepHandler, validations: string[] | undefined, stepName: string): StepHandler;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* step-machine-public — jsonata loader
|
|
151
|
+
*
|
|
152
|
+
* Synchronous jsonata wrapper. Mirrors the loader pattern in
|
|
153
|
+
* src/card-compute/index.ts — uses createRequire to load the vendored
|
|
154
|
+
* synchronous CommonJS build.
|
|
155
|
+
*
|
|
156
|
+
* Runtime portability:
|
|
157
|
+
* - Node ESM: createRequire works.
|
|
158
|
+
* - Browser/cloud: package this lib for that runtime; the consumer ships
|
|
159
|
+
* jsonata-sync.cjs alongside (tsup post-build does this automatically).
|
|
160
|
+
*/
|
|
161
|
+
type JsonataExpression = {
|
|
162
|
+
evaluate: (data: unknown) => unknown;
|
|
163
|
+
};
|
|
164
|
+
declare const jsonata: (expr: string) => JsonataExpression;
|
|
165
|
+
|
|
166
|
+
export { type BuildStepHandlersOptions, type ComputeJsonataSpec, type HandlerSpec, type InvokeRefFn, type JsonataExpression, type NormalizedHandlerResult, type RefSpec, type ResolveStepHandlerOptions, type StepConfigForFactory, type StepHandler, buildStepHandlersForFlow, createComputeJsonataHandler, createPassthroughHandler, createRefStepHandler, filterProducedData, isComputeJsonataSpec, isRefSpec, jsonata, normalizeHandlerResult, resolveStepHandler, runInputValidations, wrapWithInputValidations, wrapWithOutputFiltering };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import {createRequire}from'module';var A=createRequire(import.meta.url),p=A("./jsonata-sync.cjs");function m(r,e){if(!r||typeof r!="object")throw new Error(`[step-machine-public] Step "${e}" returned a non-object result.`);let t=r,n=t.result??t.status;if(typeof n=="string"&&n.trim().length>0){let a=t.data&&typeof t.data=="object"&&!Array.isArray(t.data)?{...t.data}:{},s=typeof t.error=="string"?t.error:void 0;return s&&!("error"in a)&&(a.error=s),{result:n,data:a,...s?{error:s}:{}}}return {result:"success",data:{...t}}}function w(r,e){if(!e||e.length===0)return r;let t={};for(let n of e)Object.prototype.hasOwnProperty.call(r,n)&&(t[n]=r[n]);return t}function g(r,e){return async(t,n)=>{let a=await r(t,n),s=m(a,n?.stepName??"unknown");return {result:s.result,data:w(s.data,e),...s.error?{error:s.error}:{}}}}function k(r,e,t){if(!e||e.length===0)return null;for(let n of e)try{if(!p(n).evaluate(r))return {result:"failure",data:{error:`[${t}] input validation failed: ${n}`}}}catch(a){let s=a instanceof Error?a.message:String(a);return {result:"failure",data:{error:`[${t}] input validation error on "${n}": ${s}`}}}return null}function y(r,e,t){return !e||e.length===0?r:async(n,a)=>{let s=k(n,e,t);return s||r(n,a)}}var h=createRequire(import.meta.url);function O(){try{return h("./jsonata-sync.cjs")}catch{return h("../../card-compute/jsonata-sync.cjs")}}var f=O();function S(r,e,t){if(!r||typeof r!="object")return e;let n={output:e},a=e.result,s=e.data,i=e.error;if(typeof r.resultExpr=="string")try{let o=f(r.resultExpr).evaluate(n);if(typeof o!="string"||!o.trim())throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(o)})`);a=o;}catch(o){let u=o instanceof Error?o.message:String(o);throw new Error(`[${t}] outputTransforms.resultExpr failed: ${u}`)}if(typeof r.dataTemplate=="string")try{let o=f(r.dataTemplate).evaluate(n);if(!o||typeof o!="object"||Array.isArray(o))throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(o)})`);s=o;}catch(o){let u=o instanceof Error?o.message:String(o);throw new Error(`[${t}] outputTransforms.dataTemplate failed: ${u}`)}if(typeof r.errorExpr=="string")try{let o=f(r.errorExpr).evaluate(n);i=o!=null?String(o):void 0;}catch(o){let u=o instanceof Error?o.message:String(o);throw new Error(`[${t}] outputTransforms.errorExpr failed: ${u}`)}return i!==void 0?{result:a,data:s,error:i}:{result:a,data:s}}var F="b64:";function z(r){let e=new TextEncoder().encode(r),t=globalThis.Buffer,n;if(t)n=t.from(e).toString("base64");else if(typeof btoa=="function"){let a="";for(let s of e)a+=String.fromCharCode(s);n=btoa(a);}else throw new Error("No base64 encoder available in this runtime");return n.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function R(r){return `${F}${z(JSON.stringify(r))}`}function x(r){return !!r&&typeof r=="object"&&r.type==="compute-jsonata"&&Array.isArray(r.expr)&&r.expr.length>0}function b(r){if(!r||typeof r!="object")return false;let e=r;if(e.type!=="ref"||typeof e.howToRun!="string")return false;if(typeof e.whatToRun=="string")return true;if(e.whatToRun&&typeof e.whatToRun=="object"){let t=e.whatToRun;return typeof t.kind=="string"&&typeof t.value=="string"}return false}function I(r){if(typeof r=="string"){let e=r.indexOf("=");if(e<1)throw new Error(`[step-machine-public] Invalid compute expression (missing "="): "${r}"`);return {bindTo:r.slice(0,e).trim(),expr:r.slice(e+1).trim()}}if(r&&typeof r=="object"&&typeof r.bindTo=="string"&&typeof r.expr=="string")return r;throw new Error(`[step-machine-public] Invalid compute step: ${JSON.stringify(r)}`)}function B(r,e,t){let n=e.split("."),a=r;for(let s=0;s<n.length-1;s++){let i=n[s];(a[i]==null||typeof a[i]!="object")&&(a[i]={}),a=a[i];}a[n[n.length-1]]=t;}function v(r,e,t){let n=r.expr.map(I);return async a=>{let s=a&&typeof a=="object"&&!Array.isArray(a)?{...a}:{},i={},o={expects_data:s,data:i,...t?{config:t}:{}},u,d;for(let l of n)try{let c=p(l.expr).evaluate(o);if(l.bindTo==="result")u=c!=null?String(c):"success";else if(l.bindTo==="error")d=c!=null?String(c):void 0;else if(l.bindTo.startsWith("data."))B(i,l.bindTo.slice(5),c);else return {result:"failure",data:{},error:`[${e}] invalid bindTo "${l.bindTo}": must be "result", "error", or start with "data."`}}catch(c){let H=c instanceof Error?c.message:String(c);return {result:"failure",data:{},error:`[${e}] compute "${l.bindTo}" failed: ${H}`}}return u===void 0?{result:"failure",data:{},error:`[${e}] compute-jsonata: no "result" binding declared \u2014 add '- result = "success"' to expr`}:d?{result:u,data:i,error:d}:{result:u,data:i}}}function j(r,e,t,n){let{type:a,...s}=r,i={...s,whatToRun:typeof s.whatToRun=="object"?R(s.whatToRun):s.whatToRun};return async o=>{let u=o&&typeof o=="object"&&!Array.isArray(o)?{...o}:{};n&&(u.config=n);try{let d=await t(i,u);if(!r.outputTransforms)return d;try{return S(r.outputTransforms,d,e)}catch(l){let c=l instanceof Error?l.message:String(l);return {result:"failure",data:{},error:c}}}catch(d){let l=d instanceof Error?d.message:String(d);return {result:"failure",data:{error:`[step-machine-public] step "${e}" invoke threw: ${l}`}}}}}function E(){return async r=>({result:"success",data:r&&typeof r=="object"&&!Array.isArray(r)?r:{}})}function T(r,e,t){let n=Array.isArray(e?.produces_data)?e?.produces_data:void 0,a=Array.isArray(e?.input_validations)?e?.input_validations:void 0,s=e?.config??void 0,i=e?.handler,o;return x(i)?o=v(i,r,s):b(i)?o=j(i,r,t.invoke,s):o=E(),y(g(o,n),a,r)}function C(r,e){let t={};for(let[n,a]of Object.entries(r.steps??{}))t[n]=T(n,a,e);return t}
|
|
2
|
+
export{C as buildStepHandlersForFlow,v as createComputeJsonataHandler,E as createPassthroughHandler,j as createRefStepHandler,w as filterProducedData,x as isComputeJsonataSpec,b as isRefSpec,p as jsonata,m as normalizeHandlerResult,T as resolveStepHandler,k as runInputValidations,y as wrapWithInputValidations,g as wrapWithOutputFiltering};//# sourceMappingURL=index.js.map
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/step-machine-public/jsonata-loader.ts","../../src/step-machine-public/result-utils.ts","../../src/cli/common/jsonata-loader.ts","../../src/cli/common/args-massaging.ts","../../src/cli/common/storage-interface.ts","../../src/step-machine-public/handler-factory.ts"],"names":["_require","createRequire","jsonata","normalizeHandlerResult","raw","stepName","obj","result","data","error","filterProducedData","produces","filtered","key","wrapWithOutputFiltering","handler","input","context","normalized","runInputValidations","validations","expr","err","msg","wrapWithInputValidations","failure","_loadJsonata","resolveOutputTransforms","transforms","label","ctx","val","REF_PREFIX","toBase64Url","utf8","buf","base64","binary","byte","serializeRef","ref","isComputeJsonataSpec","spec","isRefSpec","s","w","normalizeComputeStep","item","eq","deepSet","path","value","parts","cur","i","k","createComputeJsonataHandler","config","steps","expects_data","transitionResult","transitionError","step","createRefStepHandler","invoke","_t","refOnly","stepInput","createPassthroughHandler","resolveStepHandler","stepConfig","options","inputValidations","base","buildStepHandlersForFlow","flow","handlers"],"mappings":"mCAeA,IAAMA,EAAWC,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA,CAMjCC,EAA+CF,CAAAA,CAAS,oBAAoB,ECHlF,SAASG,EACdC,CAAAA,CACAC,CAAAA,CACyB,CACzB,GAAI,CAACD,CAAAA,EAAO,OAAOA,CAAAA,EAAQ,QAAA,CACzB,MAAM,IAAI,KAAA,CAAM,CAAA,4BAAA,EAA+BC,CAAQ,iCAAiC,CAAA,CAG1F,IAAMC,CAAAA,CAAMF,CAAAA,CACNG,EAAUD,CAAAA,CAAI,MAAA,EAAUA,CAAAA,CAAI,MAAA,CAGlC,GAAI,OAAOC,CAAAA,EAAW,QAAA,EAAYA,CAAAA,CAAO,MAAK,CAAE,MAAA,CAAS,CAAA,CAAG,CAC1D,IAAMC,CAAAA,CACJF,CAAAA,CAAI,IAAA,EAAQ,OAAOA,EAAI,IAAA,EAAS,QAAA,EAAY,CAAC,KAAA,CAAM,QAAQA,CAAAA,CAAI,IAAI,CAAA,CAC/D,CAAE,GAAIA,CAAAA,CAAI,IAAiC,CAAA,CAC3C,GACAG,CAAAA,CAAQ,OAAOH,CAAAA,CAAI,KAAA,EAAU,SAAYA,CAAAA,CAAI,KAAA,CAAmB,MAAA,CACtE,OAAIG,CAAAA,EAAS,EAAE,OAAA,GAAWD,CAAAA,CAAAA,GACxBA,EAAK,KAAA,CAAQC,CAAAA,CAAAA,CAER,CAAE,MAAA,CAAAF,EAAQ,IAAA,CAAAC,CAAAA,CAAM,GAAIC,CAAAA,CAAQ,CAAE,KAAA,CAAAA,CAAM,CAAA,CAAI,EAAI,CACrD,CAGA,OAAO,CAAE,OAAQ,SAAA,CAAW,IAAA,CAAM,CAAE,GAAGH,CAAI,CAAE,CAC/C,CAMO,SAASI,EACdF,CAAAA,CACAG,CAAAA,CACyB,CACzB,GAAI,CAACA,CAAAA,EAAYA,CAAAA,CAAS,MAAA,GAAW,CAAA,CAAG,OAAOH,CAAAA,CAC/C,IAAMI,CAAAA,CAAoC,GAC1C,IAAA,IAAWC,CAAAA,IAAOF,CAAAA,CACZ,MAAA,CAAO,UAAU,cAAA,CAAe,IAAA,CAAKH,CAAAA,CAAMK,CAAG,IAChDD,CAAAA,CAASC,CAAG,CAAA,CAAIL,CAAAA,CAAKK,CAAG,CAAA,CAAA,CAG5B,OAAOD,CACT,CAMO,SAASE,CAAAA,CACdC,CAAAA,CACAJ,CAAAA,CACa,CACb,OAAO,MAAOK,CAAAA,CAAOC,CAAAA,GAAY,CAC/B,IAAMb,CAAAA,CAAM,MAAMW,CAAAA,CAAQC,EAAOC,CAAO,CAAA,CAClCC,CAAAA,CAAaf,CAAAA,CAAuBC,EAAKa,CAAAA,EAAS,QAAA,EAAY,SAAS,CAAA,CAC7E,OAAO,CACL,MAAA,CAAQC,CAAAA,CAAW,MAAA,CACnB,KAAMR,CAAAA,CAAmBQ,CAAAA,CAAW,IAAA,CAAMP,CAAQ,EAClD,GAAIO,CAAAA,CAAW,KAAA,CAAQ,CAAE,MAAOA,CAAAA,CAAW,KAAM,CAAA,CAAI,EACvD,CACF,CACF,CAYO,SAASC,EACdH,CAAAA,CACAI,CAAAA,CACAf,CAAAA,CACgC,CAChC,GAAI,CAACe,CAAAA,EAAeA,CAAAA,CAAY,MAAA,GAAW,EAAG,OAAO,IAAA,CACrD,IAAA,IAAWC,CAAAA,IAAQD,EACjB,GAAI,CAEF,GAAI,CADOlB,EAAQmB,CAAI,CAAA,CAAE,QAAA,CAASL,CAAK,EAErC,OAAO,CACL,MAAA,CAAQ,SAAA,CACR,KAAM,CAAE,KAAA,CAAO,CAAA,CAAA,EAAIX,CAAQ,8BAA8BgB,CAAI,CAAA,CAAG,CAClE,CAEJ,OAASC,CAAAA,CAAK,CACZ,IAAMC,CAAAA,CAAMD,aAAe,KAAA,CAAQA,CAAAA,CAAI,OAAA,CAAU,MAAA,CAAOA,CAAG,CAAA,CAC3D,OAAO,CACL,MAAA,CAAQ,UACR,IAAA,CAAM,CAAE,KAAA,CAAO,CAAA,CAAA,EAAIjB,CAAQ,CAAA,6BAAA,EAAgCgB,CAAI,CAAA,GAAA,EAAME,CAAG,EAAG,CAC7E,CACF,CAEF,OAAO,IACT,CAMO,SAASC,CAAAA,CACdT,CAAAA,CACAK,EACAf,CAAAA,CACa,CACb,OAAI,CAACe,GAAeA,CAAAA,CAAY,MAAA,GAAW,CAAA,CAAUL,CAAAA,CAC9C,MAAOC,CAAAA,CAAOC,CAAAA,GAAY,CAC/B,IAAMQ,EAAUN,CAAAA,CAAoBH,CAAAA,CAAOI,CAAAA,CAAaf,CAAQ,EAChE,OAAIoB,CAAAA,EACGV,CAAAA,CAAQC,CAAAA,CAAOC,CAAO,CAC/B,CACF,CC3HA,IAAMjB,CAAAA,CAAWC,cAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA,CAS9C,SAASyB,GAAoD,CAG3D,GAAI,CACF,OAAO1B,CAAAA,CAAS,oBAAoB,CACtC,CAAA,KAAQ,CACN,OAAOA,CAAAA,CAAS,qCAAqC,CACvD,CACF,CAEO,IAAME,CAAAA,CAA+CwB,CAAAA,GC4DrD,SAASC,CAAAA,CACdC,CAAAA,CACAxB,CAAAA,CACAyB,EACyB,CACzB,GAAI,CAACD,CAAAA,EAAc,OAAOA,CAAAA,EAAe,QAAA,CAAU,OAAOxB,CAAAA,CAE1D,IAAM0B,CAAAA,CAAM,CAAE,MAAA,CAAQ1B,CAAI,EACtBG,CAAAA,CAASH,CAAAA,CAAI,MAAA,CACbI,CAAAA,CAAOJ,EAAI,IAAA,CACXK,CAAAA,CAAQL,CAAAA,CAAI,KAAA,CAEhB,GAAI,OAAOwB,CAAAA,CAAW,UAAA,EAAe,QAAA,CACnC,GAAI,CACF,IAAMG,CAAAA,CAAM7B,CAAAA,CAAQ0B,EAAW,UAAU,CAAA,CAAE,QAAA,CAASE,CAAG,EACvD,GAAI,OAAOC,CAAAA,EAAQ,QAAA,EAAY,CAACA,CAAAA,CAAI,IAAA,EAAK,CACvC,MAAM,IAAI,KAAA,CAAM,CAAA,mDAAA,EAAsD,IAAA,CAAK,SAAA,CAAUA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAA,CAE9FxB,CAAAA,CAASwB,EACX,CAAA,MAAST,CAAAA,CAAK,CACZ,IAAMC,EAAMD,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAI,OAAA,CAAU,OAAOA,CAAG,CAAA,CAC3D,MAAM,IAAI,MAAM,CAAA,CAAA,EAAIO,CAAK,CAAA,sCAAA,EAAyCN,CAAG,EAAE,CACzE,CAGF,GAAI,OAAOK,EAAW,YAAA,EAAiB,QAAA,CACrC,GAAI,CACF,IAAMG,CAAAA,CAAM7B,CAAAA,CAAQ0B,CAAAA,CAAW,YAAY,EAAE,QAAA,CAASE,CAAG,CAAA,CACzD,GAAI,CAACC,CAAAA,EAAO,OAAOA,CAAAA,EAAQ,QAAA,EAAY,MAAM,OAAA,CAAQA,CAAG,CAAA,CACtD,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,IAAA,CAAK,SAAA,CAAUA,CAAG,CAAC,CAAA,CAAA,CAAG,CAAA,CAEvFvB,CAAAA,CAAOuB,EACT,CAAA,MAAST,CAAAA,CAAK,CACZ,IAAMC,EAAMD,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAI,OAAA,CAAU,OAAOA,CAAG,CAAA,CAC3D,MAAM,IAAI,MAAM,CAAA,CAAA,EAAIO,CAAK,CAAA,wCAAA,EAA2CN,CAAG,CAAA,CAAE,CAC3E,CAGF,GAAI,OAAOK,CAAAA,CAAW,SAAA,EAAc,QAAA,CAClC,GAAI,CACF,IAAMG,CAAAA,CAAM7B,CAAAA,CAAQ0B,CAAAA,CAAW,SAAS,CAAA,CAAE,QAAA,CAASE,CAAG,CAAA,CAEtDrB,EAAQsB,CAAAA,EAAO,IAAA,CAAO,MAAA,CAAOA,CAAG,EAAI,KAAA,EACtC,CAAA,MAAST,CAAAA,CAAK,CACZ,IAAMC,CAAAA,CAAMD,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAI,QAAU,MAAA,CAAOA,CAAG,CAAA,CAC3D,MAAM,IAAI,KAAA,CAAM,CAAA,CAAA,EAAIO,CAAK,CAAA,qCAAA,EAAwCN,CAAG,CAAA,CAAE,CACxE,CAGF,OAAOd,IAAU,MAAA,CACb,CAAE,MAAA,CAAAF,CAAAA,CAAQ,KAAAC,CAAAA,CAAM,KAAA,CAAAC,CAAM,CAAA,CACtB,CAAE,MAAA,CAAAF,CAAAA,CAAQ,IAAA,CAAAC,CAAK,CACrB,CCzDA,IAAMwB,CAAAA,CAAa,MAAA,CAEnB,SAASC,CAAAA,CAAY7B,CAAAA,CAAqB,CACxC,IAAM8B,EAAO,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO9B,CAAG,CAAA,CACnC+B,CAAAA,CAAO,UAAA,CAA0F,MAAA,CACnGC,EACJ,GAAID,CAAAA,CACFC,CAAAA,CAASD,CAAAA,CAAI,KAAKD,CAAI,CAAA,CAAE,QAAA,CAAS,QAAQ,UAChC,OAAO,IAAA,EAAS,UAAA,CAAY,CACrC,IAAIG,CAAAA,CAAS,EAAA,CACb,IAAA,IAAWC,CAAAA,IAAQJ,EAAMG,CAAAA,EAAU,MAAA,CAAO,YAAA,CAAaC,CAAI,EAC3DF,CAAAA,CAAS,IAAA,CAAKC,CAAM,EACtB,MACE,MAAM,IAAI,KAAA,CAAM,6CAA6C,EAE/D,OAAOD,CAAAA,CAAO,OAAA,CAAQ,KAAA,CAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,CAAO,GAAG,EAAE,OAAA,CAAQ,MAAA,CAAQ,EAAE,CAC1E,CAiBO,SAASG,CAAAA,CAAaC,CAAAA,CAA2B,CACtD,OAAO,CAAA,EAAGR,CAAU,CAAA,EAAGC,CAAAA,CAAY,KAAK,SAAA,CAAUO,CAAG,CAAC,CAAC,EACzD,CCtFO,SAASC,CAAAA,CAAqBC,CAAAA,CAA2C,CAC9E,OACE,CAAC,CAACA,CAAAA,EACF,OAAOA,CAAAA,EAAS,QAAA,EACfA,CAAAA,CAAiC,OAAS,iBAAA,EAC3C,KAAA,CAAM,OAAA,CAASA,CAAAA,CAAiC,IAAI,CAAA,EAClDA,CAAAA,CAAiC,IAAA,CAAmB,MAAA,CAAS,CAEnE,CAEO,SAASC,CAAAA,CAAUD,CAAAA,CAAgC,CACxD,GAAI,CAACA,CAAAA,EAAQ,OAAOA,GAAS,QAAA,CAAU,OAAO,MAAA,CAC9C,IAAME,EAAIF,CAAAA,CACV,GAAIE,CAAAA,CAAE,IAAA,GAAS,OAAS,OAAOA,CAAAA,CAAE,QAAA,EAAa,QAAA,CAAU,OAAO,MAAA,CAC/D,GAAI,OAAOA,CAAAA,CAAE,WAAc,QAAA,CAAU,OAAO,KAAA,CAC5C,GAAIA,EAAE,SAAA,EAAa,OAAOA,CAAAA,CAAE,SAAA,EAAc,SAAU,CAClD,IAAMC,CAAAA,CAAID,CAAAA,CAAE,UACZ,OAAO,OAAOC,CAAAA,CAAE,IAAA,EAAS,UAAY,OAAOA,CAAAA,CAAE,KAAA,EAAU,QAC1D,CACA,OAAO,MACT,CAWA,SAASC,EAAqBC,CAAAA,CAAwE,CACpG,GAAI,OAAOA,CAAAA,EAAS,QAAA,CAAU,CAC5B,IAAMC,EAAKD,CAAAA,CAAK,OAAA,CAAQ,GAAG,CAAA,CAC3B,GAAIC,CAAAA,CAAK,CAAA,CACP,MAAM,IAAI,MAAM,CAAA,iEAAA,EAAoED,CAAI,CAAA,CAAA,CAAG,CAAA,CAE7F,OAAO,CAAE,MAAA,CAAQA,CAAAA,CAAK,KAAA,CAAM,EAAGC,CAAE,CAAA,CAAE,IAAA,EAAK,CAAG,KAAMD,CAAAA,CAAK,KAAA,CAAMC,CAAAA,CAAK,CAAC,EAAE,IAAA,EAAO,CAC7E,CACA,GAAID,CAAAA,EAAQ,OAAOA,CAAAA,EAAS,QAAA,EAAY,OAAOA,CAAAA,CAAK,MAAA,EAAW,QAAA,EAAY,OAAOA,EAAK,IAAA,EAAS,QAAA,CAC9F,OAAOA,CAAAA,CAET,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,IAAA,CAAK,UAAUA,CAAI,CAAC,CAAA,CAAE,CACvF,CAGA,SAASE,CAAAA,CAAQ3C,CAAAA,CAA8B4C,CAAAA,CAAcC,EAAsB,CACjF,IAAMC,CAAAA,CAAQF,CAAAA,CAAK,MAAM,GAAG,CAAA,CACxBG,CAAAA,CAA+B/C,CAAAA,CACnC,IAAA,IAASgD,CAAAA,CAAI,CAAA,CAAGA,CAAAA,CAAIF,EAAM,MAAA,CAAS,CAAA,CAAGE,CAAAA,EAAAA,CAAK,CACzC,IAAMC,CAAAA,CAAIH,CAAAA,CAAME,CAAC,CAAA,CAAA,CACbD,EAAIE,CAAC,CAAA,EAAK,IAAA,EAAQ,OAAOF,EAAIE,CAAC,CAAA,EAAM,QAAA,IAAUF,CAAAA,CAAIE,CAAC,CAAA,CAAI,EAAC,CAAA,CAC5DF,CAAAA,CAAMA,EAAIE,CAAC,EACb,CACAF,CAAAA,CAAID,EAAMA,CAAAA,CAAM,MAAA,CAAS,CAAC,CAAC,EAAID,EACjC,CAEO,SAASK,CAAAA,CACdd,EACArC,CAAAA,CACAoD,CAAAA,CACa,CACb,IAAMC,EAAQhB,CAAAA,CAAK,IAAA,CAAK,GAAA,CAAII,CAAoB,EAChD,OAAO,MAAO9B,CAAAA,EAAU,CACtB,IAAM2C,CAAAA,CACJ3C,CAAAA,EAAS,OAAOA,CAAAA,EAAU,UAAY,CAAC,KAAA,CAAM,OAAA,CAAQA,CAAK,EACtD,CAAE,GAAGA,CAAM,CAAA,CACX,EAAC,CAIDR,CAAAA,CAAgC,EAAC,CAMjCsB,EAA+B,CACnC,YAAA,CAAA6B,CAAAA,CACA,IAAA,CAAAnD,EACA,GAAIiD,CAAAA,CAAS,CAAE,MAAA,CAAAA,CAAO,CAAA,CAAI,EAC5B,CAAA,CAEIG,EACAC,CAAAA,CAEJ,IAAA,IAAWC,CAAAA,IAAQJ,CAAAA,CACjB,GAAI,CACF,IAAM3B,CAAAA,CAAM7B,CAAAA,CAAQ4D,EAAK,IAAI,CAAA,CAAE,QAAA,CAAShC,CAAG,EAE3C,GAAIgC,CAAAA,CAAK,MAAA,GAAW,QAAA,CAElBF,EAAmB7B,CAAAA,EAAO,IAAA,CAAO,MAAA,CAAOA,CAAG,EAAI,SAAA,CAAA,KAAA,GACtC+B,CAAAA,CAAK,MAAA,GAAW,OAAA,CAEzBD,EAAkB9B,CAAAA,EAAO,IAAA,CAAO,MAAA,CAAOA,CAAG,EAAI,KAAA,CAAA,CAAA,KAAA,GACrC+B,CAAAA,CAAK,MAAA,CAAO,UAAA,CAAW,OAAO,CAAA,CAEvCb,CAAAA,CAAQzC,CAAAA,CAAMsD,CAAAA,CAAK,OAAO,KAAA,CAAM,CAAc,CAAA,CAAG/B,CAAG,OAEpD,OAAO,CACL,MAAA,CAAQ,SAAA,CACR,KAAM,EAAC,CACP,KAAA,CAAO,CAAA,CAAA,EAAI1B,CAAQ,CAAA,kBAAA,EAAqByD,CAAAA,CAAK,MAAM,CAAA,mDAAA,CACrD,CAEJ,CAAA,MAASxC,CAAAA,CAAK,CACZ,IAAMC,CAAAA,CAAMD,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAI,QAAU,MAAA,CAAOA,CAAG,CAAA,CAC3D,OAAO,CACL,MAAA,CAAQ,SAAA,CACR,IAAA,CAAM,GACN,KAAA,CAAO,CAAA,CAAA,EAAIjB,CAAQ,CAAA,WAAA,EAAcyD,EAAK,MAAM,CAAA,UAAA,EAAavC,CAAG,CAAA,CAC9D,CACF,CAGF,OAAIqC,CAAAA,GAAqB,MAAA,CAChB,CACL,MAAA,CAAQ,SAAA,CACR,IAAA,CAAM,GACN,KAAA,CAAO,CAAA,CAAA,EAAIvD,CAAQ,CAAA,yFAAA,CACrB,EAEKwD,CAAAA,CACH,CAAE,MAAA,CAAQD,CAAAA,CAAkB,KAAApD,CAAAA,CAAM,KAAA,CAAOqD,CAAgB,CAAA,CACzD,CAAE,MAAA,CAAQD,CAAAA,CAAkB,IAAA,CAAApD,CAAK,CACvC,CACF,CAMO,SAASuD,CAAAA,CACdrB,EACArC,CAAAA,CACA2D,CAAAA,CACAP,CAAAA,CACa,CAIb,GAAM,CAAE,IAAA,CAAMQ,CAAAA,CAAI,GAAGC,CAAQ,CAAA,CAAIxB,CAAAA,CAC3BF,CAAAA,CAAM,CACV,GAAG0B,CAAAA,CACH,SAAA,CAAW,OAAOA,CAAAA,CAAQ,WAAc,QAAA,CACpC3B,CAAAA,CAAa2B,CAAAA,CAAQ,SAAS,EAC9BA,CAAAA,CAAQ,SACd,CAAA,CAEA,aAAclD,CAAAA,EAAU,CACtB,IAAMmD,CAAAA,CACJnD,GAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,CAAC,MAAM,OAAA,CAAQA,CAAK,CAAA,CACtD,CAAE,GAAGA,CAAM,CAAA,CACX,EAAC,CACHyC,IAAQU,CAAAA,CAAU,MAAA,CAASV,CAAAA,CAAAA,CAE/B,GAAI,CACF,IAAMrD,CAAAA,CAAM,MAAM4D,CAAAA,CAAOxB,EAAK2B,CAAS,CAAA,CACvC,GAAI,CAACzB,EAAK,gBAAA,CAAkB,OAAOtC,CAAAA,CACnC,GAAI,CACF,OAAOuB,CAAAA,CAAwBe,CAAAA,CAAK,gBAAA,CAAkBtC,EAAKC,CAAQ,CACrE,CAAA,MAASiB,CAAAA,CAAK,CACZ,IAAMC,CAAAA,CAAMD,CAAAA,YAAe,KAAA,CAAQA,EAAI,OAAA,CAAU,MAAA,CAAOA,CAAG,CAAA,CAC3D,OAAO,CAAE,MAAA,CAAQ,SAAA,CAAW,IAAA,CAAM,EAAC,CAAG,KAAA,CAAOC,CAAI,CACnD,CACF,CAAA,MAASD,CAAAA,CAAK,CACZ,IAAMC,CAAAA,CAAMD,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAI,QAAU,MAAA,CAAOA,CAAG,CAAA,CAC3D,OAAO,CACL,MAAA,CAAQ,SAAA,CACR,IAAA,CAAM,CAAE,MAAO,CAAA,4BAAA,EAA+BjB,CAAQ,CAAA,gBAAA,EAAmBkB,CAAG,EAAG,CACjF,CACF,CACF,CACF,CAMO,SAAS6C,CAAAA,EAAwC,CACtD,aAAcpD,CAAAA,GAKL,CAAE,MAAA,CAAQ,SAAA,CAAW,KAH1BA,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,CAAC,KAAA,CAAM,OAAA,CAAQA,CAAK,CAAA,CACrDA,EACD,EAC2B,CAAA,CAErC,CAUO,SAASqD,CAAAA,CACdhE,CAAAA,CACAiE,CAAAA,CACAC,CAAAA,CACa,CACb,IAAM5D,CAAAA,CAAW,KAAA,CAAM,OAAA,CAAQ2D,GAAY,aAAa,CAAA,CAAIA,CAAAA,EAAY,aAAA,CAAgB,OAClFE,CAAAA,CAAmB,KAAA,CAAM,OAAA,CAAQF,CAAAA,EAAY,iBAAiB,CAAA,CAChEA,CAAAA,EAAY,iBAAA,CACZ,MAAA,CACEb,EAASa,CAAAA,EAAY,MAAA,EAAU,MAAA,CAC/B5B,CAAAA,CAAgC4B,GAAY,OAAA,CAE9CG,CAAAA,CACJ,OAAIhC,CAAAA,CAAqBC,CAAI,CAAA,CAE3B+B,CAAAA,CAAOjB,CAAAA,CAA4Bd,CAAAA,CAAMrC,EAAUoD,CAAM,CAAA,CAChDd,CAAAA,CAAUD,CAAI,EACvB+B,CAAAA,CAAOV,CAAAA,CAAqBrB,CAAAA,CAAMrC,CAAAA,CAAUkE,EAAQ,MAAA,CAAQd,CAAM,CAAA,CAElEgB,CAAAA,CAAOL,GAAyB,CAG3B5C,CAAAA,CACLV,CAAAA,CAAwB2D,CAAAA,CAAM9D,CAAQ,CAAA,CACtC6D,CAAAA,CACAnE,CACF,CACF,CAUO,SAASqE,CAAAA,CACdC,CAAAA,CACAJ,CAAAA,CAC6B,CAC7B,IAAMK,CAAAA,CAAwC,EAAC,CAC/C,OAAW,CAACvE,CAAAA,CAAUiE,CAAU,CAAA,GAAK,OAAO,OAAA,CAAQK,CAAAA,CAAK,KAAA,EAAS,EAAE,CAAA,CAClEC,CAAAA,CAASvE,CAAQ,CAAA,CAAIgE,EAAmBhE,CAAAA,CAAUiE,CAAAA,CAAYC,CAAO,CAAA,CAEvE,OAAOK,CACT","file":"index.js","sourcesContent":["/**\n * step-machine-public — jsonata loader\n *\n * Synchronous jsonata wrapper. Mirrors the loader pattern in\n * src/card-compute/index.ts — uses createRequire to load the vendored\n * synchronous CommonJS build.\n *\n * Runtime portability:\n * - Node ESM: createRequire works.\n * - Browser/cloud: package this lib for that runtime; the consumer ships\n * jsonata-sync.cjs alongside (tsup post-build does this automatically).\n */\n\nimport { createRequire } from 'module';\n\nconst _require = createRequire(import.meta.url);\n\nexport type JsonataExpression = {\n evaluate: (data: unknown) => unknown;\n};\n\nexport const jsonata: (expr: string) => JsonataExpression = _require('./jsonata-sync.cjs');\n","/**\n * step-machine-public — result utilities\n *\n * Pure helpers that:\n * - Normalize handler return shapes into NormalizedHandlerResult.\n * - Filter `data` to the keys declared in `produces_data`.\n * - Wrap a handler with output filtering / input validation.\n *\n * No transport, no I/O — only object reshaping.\n */\n\nimport type { NormalizedHandlerResult, StepHandler } from './types.js';\nimport { jsonata } from './jsonata-loader.js';\n\n// ============================================================================\n// normalizeHandlerResult — accept legacy or strict shape\n// ============================================================================\n\nexport function normalizeHandlerResult(\n raw: unknown,\n stepName: string,\n): NormalizedHandlerResult {\n if (!raw || typeof raw !== 'object') {\n throw new Error(`[step-machine-public] Step \"${stepName}\" returned a non-object result.`);\n }\n\n const obj = raw as Record<string, unknown>;\n const result = (obj.result ?? obj.status) as unknown;\n\n // Strict envelope: { result, data, error? }\n if (typeof result === 'string' && result.trim().length > 0) {\n const data: Record<string, unknown> =\n obj.data && typeof obj.data === 'object' && !Array.isArray(obj.data)\n ? { ...(obj.data as Record<string, unknown>) }\n : {};\n const error = typeof obj.error === 'string' ? (obj.error as string) : undefined;\n if (error && !('error' in data)) {\n data.error = error;\n }\n return { result, data, ...(error ? { error } : {}) };\n }\n\n // Bare object — treat the whole thing as data, intent = success.\n return { result: 'success', data: { ...obj } };\n}\n\n// ============================================================================\n// filterProducedData — narrow data to declared produces_data keys\n// ============================================================================\n\nexport function filterProducedData(\n data: Record<string, unknown>,\n produces: string[] | undefined,\n): Record<string, unknown> {\n if (!produces || produces.length === 0) return data;\n const filtered: Record<string, unknown> = {};\n for (const key of produces) {\n if (Object.prototype.hasOwnProperty.call(data, key)) {\n filtered[key] = data[key];\n }\n }\n return filtered;\n}\n\n// ============================================================================\n// wrapWithOutputFiltering — compose normalization + produces_data filtering\n// ============================================================================\n\nexport function wrapWithOutputFiltering(\n handler: StepHandler,\n produces: string[] | undefined,\n): StepHandler {\n return async (input, context) => {\n const raw = await handler(input, context);\n const normalized = normalizeHandlerResult(raw, context?.stepName ?? 'unknown');\n return {\n result: normalized.result,\n data: filterProducedData(normalized.data, produces),\n ...(normalized.error ? { error: normalized.error } : {}),\n };\n };\n}\n\n// ============================================================================\n// runInputValidations — evaluate validation expressions\n// ============================================================================\n\n/**\n * Evaluate each validation as a JSONata expression returning truthy.\n *\n * Returns `null` on success, or a normalized failure result on the first\n * failed/throwing validation.\n */\nexport function runInputValidations(\n input: Record<string, unknown>,\n validations: string[] | undefined,\n stepName: string,\n): NormalizedHandlerResult | null {\n if (!validations || validations.length === 0) return null;\n for (const expr of validations) {\n try {\n const ok = jsonata(expr).evaluate(input);\n if (!ok) {\n return {\n result: 'failure',\n data: { error: `[${stepName}] input validation failed: ${expr}` },\n };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: 'failure',\n data: { error: `[${stepName}] input validation error on \"${expr}\": ${msg}` },\n };\n }\n }\n return null;\n}\n\n// ============================================================================\n// wrapWithInputValidations — short-circuit if any validation fails\n// ============================================================================\n\nexport function wrapWithInputValidations(\n handler: StepHandler,\n validations: string[] | undefined,\n stepName: string,\n): StepHandler {\n if (!validations || validations.length === 0) return handler;\n return async (input, context) => {\n const failure = runInputValidations(input, validations, stepName);\n if (failure) return failure;\n return handler(input, context);\n };\n}\n","/**\n * cli/common/jsonata-loader — synchronous jsonata wrapper.\n *\n * Mirrors the loader pattern used by card-compute. Uses createRequire so the\n * vendored CommonJS sync build can be loaded from ESM. The canonical source\n * file is `src/card-compute/jsonata-sync.cjs`; the tsup post-build hook copies\n * it next to every dist bundle that references it.\n */\n\nimport { createRequire } from 'module';\n\nconst _require = createRequire(import.meta.url);\n\nexport type JsonataExpression = {\n evaluate: (data: unknown) => unknown;\n};\n\n// Source path resolves via the file's location at src/cli/common/.\n// Dist path resolves via the post-build copy that places jsonata-sync.cjs\n// alongside the bundled output (handled by tsup's copyJsonataSyncToDistDirs).\nfunction _loadJsonata(): (expr: string) => JsonataExpression {\n // Try sibling first (dist layout). If that fails, fall back to the canonical\n // source location (used when running TypeScript directly under vitest/tsx).\n try {\n return _require('./jsonata-sync.cjs');\n } catch {\n return _require('../../card-compute/jsonata-sync.cjs');\n }\n}\n\nexport const jsonata: (expr: string) => JsonataExpression = _loadJsonata();\n","/**\n * cli/common/args-massaging — JSONata-based mapping from logical args to\n * transport-specific shape.\n *\n * `argsMassaging` is a property of `ExecutionRef`, so honoring it is the job\n * of every adapter (Node spawn, HTTP, Azure Function, etc.). This helper is\n * the shared pure-JSONata implementation reused by all adapters.\n *\n * Adapters call this as the first step inside their `invokeRefSync` /\n * `dispatchExecution` implementation, then perform their transport using\n * `cmdArgs` / `body` / `url`.\n */\n\nimport { jsonata } from './jsonata-loader.js';\nimport type { ArgsMassaging, OutputTransforms } from './execution-interface.js';\nimport type { NormalizedHandlerResult } from '../../step-machine-public/types.js';\n\nexport interface MassagedArgs {\n /** Resolved argv tail for local transports. */\n cmdArgs?: string[];\n /** Resolved request body for http transports (or stdin payload for local). */\n body?: unknown;\n /** Resolved final URL string for http transports. */\n url?: string;\n}\n\n/**\n * Evaluate `argsMassaging` against the supplied context.\n *\n * Throws with a label-tagged message if any expression fails. Adapters\n * should catch and convert to a normalized failure result.\n */\nexport function resolveArgsMassaging(\n argsMassaging: ArgsMassaging | undefined,\n context: Record<string, unknown>,\n label: string,\n): MassagedArgs {\n if (!argsMassaging || typeof argsMassaging !== 'object') return {};\n\n const out: MassagedArgs = {};\n\n if (Array.isArray(argsMassaging.cmdTemplate)) {\n const resolved: string[] = [];\n for (const expr of argsMassaging.cmdTemplate) {\n try {\n resolved.push(String(jsonata(expr).evaluate(context)));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.cmdTemplate failed on \"${expr}\": ${msg}`,\n );\n }\n }\n out.cmdArgs = resolved;\n }\n\n if (typeof argsMassaging.bodyTemplate === 'string') {\n try {\n out.body = jsonata(argsMassaging.bodyTemplate).evaluate(context);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.bodyTemplate failed: ${msg}`,\n );\n }\n }\n\n if (typeof argsMassaging.urlTemplate === 'string') {\n try {\n out.url = String(jsonata(argsMassaging.urlTemplate).evaluate(context));\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(\n `[${label}] argsMassaging.urlTemplate failed: ${msg}`,\n );\n }\n }\n\n return out;\n}\n\n/**\n * Apply `outputTransforms` to a raw invoke result.\n *\n * Context for all expressions: `{ output }` where `output` is the raw\n * { result, data, error? } envelope from invokeRefSync.\n *\n * Returns a new NormalizedHandlerResult with overrides applied.\n * Throws with a label-tagged message if any expression fails.\n */\nexport function resolveOutputTransforms(\n transforms: OutputTransforms | undefined,\n raw: NormalizedHandlerResult,\n label: string,\n): NormalizedHandlerResult {\n if (!transforms || typeof transforms !== 'object') return raw;\n\n const ctx = { output: raw };\n let result = raw.result;\n let data = raw.data;\n let error = raw.error;\n\n if (typeof transforms.resultExpr === 'string') {\n try {\n const val = jsonata(transforms.resultExpr).evaluate(ctx);\n if (typeof val !== 'string' || !val.trim()) {\n throw new Error(`resultExpr did not produce a non-empty string (got ${JSON.stringify(val)})`);\n }\n result = val;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.resultExpr failed: ${msg}`);\n }\n }\n\n if (typeof transforms.dataTemplate === 'string') {\n try {\n const val = jsonata(transforms.dataTemplate).evaluate(ctx);\n if (!val || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`dataTemplate did not produce an object (got ${JSON.stringify(val)})`);\n }\n data = val as Record<string, unknown>;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.dataTemplate failed: ${msg}`);\n }\n }\n\n if (typeof transforms.errorExpr === 'string') {\n try {\n const val = jsonata(transforms.errorExpr).evaluate(ctx);\n // $undefined() evaluates to undefined — clears the error field\n error = val != null ? String(val) : undefined;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`[${label}] outputTransforms.errorExpr failed: ${msg}`);\n }\n }\n\n return error !== undefined\n ? { result, data, error }\n : { result, data };\n}\n","/**\n * storage-interface.ts\n *\n * Three minimal storage primitives that together cover all persistence needs\n * of the board-live-cards system. Any backend (Node fs, CosmosDB, Azure Blob,\n * browser localStorage, in-memory test double) implements these three interfaces.\n *\n * The pure-logic stores in board-live-cards-all-stores.ts depend only on these\n * interfaces — never on Node built-ins.\n *\n * Blob — raw string content at a logical, backend-neutral key\n * Journal — append-only log with cursor-based reads\n * KV — key-value store with list/delete\n *\n * Mapping to existing storage adapters:\n *\n * CardStorageAdapter\n * inventory (cardId → { blobRef, checksum, fileMetadata? }) → KV\n * card JSON files → Blob\n * source output files → Blob\n *\n * JournalStorageAdapter → Journal (board-journal.jsonl)\n *\n * ExecutionRequestStore → KV (keyed by journalId, via createFsKvStorage)\n *\n * StateSnapshotStorageAdapter\n * board-graph.json (packed single JSON, written atomically) → Blob\n * per-card sidecars (cards/<id>/runtime, fetched-sources-manifest) → KV\n */\n\n// ============================================================================\n// Blob — raw content at an opaque key\n//\n// The key is backend-specific (file path, blob name, storage key).\n// Text helpers are always available. Binary helpers are optional so existing\n// backends can adopt incrementally.\n// ============================================================================\n\nexport interface BlobStat {\n key: string;\n size: number;\n updatedAt?: string;\n contentType?: string;\n}\n\nexport interface BlobStorage {\n /** Returns raw content string, or null if the blob does not exist. */\n read(key: string): string | null;\n\n /** Write content at key. Implementations should be atomic (write-rename). */\n write(key: string, content: string): void;\n\n /** Returns true if a blob exists at key. */\n exists(key: string): boolean;\n\n /** Delete the blob at key. No-op if it does not exist. */\n remove(key: string): void;\n\n /** Optional binary read for file-like artifacts. */\n readBytes?(key: string): Uint8Array | null;\n\n /** Optional binary write for file-like artifacts. */\n writeBytes?(key: string, content: Uint8Array): void;\n\n /** Optional key listing by prefix. */\n listKeys?(prefix?: string): string[];\n\n /** Optional metadata lookup. */\n stat?(key: string): BlobStat | null;\n}\n\n// ============================================================================\n// KindValueRef — backend-neutral typed reference\n//\n// A ref describes WHERE content lives without carrying the bytes.\n// Serialized on the CLI wire as: b64:<base64url({\"kind\":\"...\",\"value\":\"...\"})>\n// kind = 'fs-path': value is an absolute file path\n// Additional kinds (e.g. 'cosmos') are added in public-storage-adapter.ts as new backends are supported.\n// ============================================================================\n\nexport interface KindValueRef {\n readonly kind: string;\n readonly value: string;\n}\n\nconst REF_PREFIX = 'b64:';\n\nfunction toBase64Url(raw: string): string {\n const utf8 = new TextEncoder().encode(raw);\n const buf = (globalThis as { Buffer?: { from(data: Uint8Array): { toString(enc: string): string } } }).Buffer;\n let base64: string;\n if (buf) {\n base64 = buf.from(utf8).toString('base64');\n } else if (typeof btoa === 'function') {\n let binary = '';\n for (const byte of utf8) binary += String.fromCharCode(byte);\n base64 = btoa(binary);\n } else {\n throw new Error('No base64 encoder available in this runtime');\n }\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/g, '');\n}\n\nfunction fromBase64Url(input: string): string {\n const base64 = input.replace(/-/g, '+').replace(/_/g, '/')\n + '='.repeat((4 - (input.length % 4)) % 4);\n const buf = (globalThis as { Buffer?: { from(data: string, enc: string): { toString(enc: string): string } } }).Buffer;\n if (buf) return buf.from(base64, 'base64').toString('utf8');\n if (typeof atob === 'function') {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);\n return new TextDecoder().decode(bytes);\n }\n throw new Error('No base64 decoder available in this runtime');\n}\n\n/** Serialize a KindValueRef to the wire format: b64:<base64url(json)> */\nexport function serializeRef(ref: KindValueRef): string {\n return `${REF_PREFIX}${toBase64Url(JSON.stringify(ref))}`;\n}\n\n/** Parse a wire-format ref string (b64:<base64url(json)>) into a KindValueRef. */\nexport function parseRef(s: string): KindValueRef {\n if (!s.startsWith(REF_PREFIX)) throw new Error(`Invalid ref format (expected ${REF_PREFIX}<base64url(json)>): ${s}`);\n let parsed: unknown;\n try {\n parsed = JSON.parse(fromBase64Url(s.slice(REF_PREFIX.length)));\n } catch {\n throw new Error(`Invalid ref format (malformed base64url/json): ${s}`);\n }\n if (!parsed || typeof parsed !== 'object') {\n throw new Error(`Invalid ref format (expected object payload): ${s}`);\n }\n const candidate = parsed as { kind?: unknown; value?: unknown };\n if (typeof candidate.kind !== 'string' || typeof candidate.value !== 'string') {\n throw new Error(`Invalid ref format (payload must contain string kind/value): ${s}`);\n }\n return { kind: candidate.kind, value: candidate.value };\n}\n\n// ============================================================================\n// Journal — append-only log, cursor-based reads\n//\n// Each entry has a string id (UUID or monotonic token) and an opaque payload.\n// Cursors are entry ids — readAfter returns entries strictly after that id.\n// A null/empty cursor means \"read from the beginning\".\n// ============================================================================\n\nexport interface JournalEntry {\n id: string;\n payload: unknown;\n}\n\nexport interface JournalReadResult {\n entries: JournalEntry[];\n /** The id of the last entry returned, suitable for use as the next cursor. */\n newCursor: string | null;\n}\n\nexport interface JournalStorage {\n /** Append an entry. The storage layer assigns the id. */\n append(payload: unknown): JournalEntry;\n\n /** Read ALL entries (for index rebuilds, full replay). */\n readAll(): JournalEntry[];\n\n /**\n * Read entries appended after the given cursor id.\n * If cursor is null/empty, returns all entries from the beginning.\n */\n readAfter(cursor: string | null): JournalReadResult;\n}\n\n// ============================================================================\n// KV — key-value store with list and delete\n//\n// Values are opaque unknown — callers own serialisation.\n// Keys are scoped by the adapter factory (e.g. a boardDir prefix is closed\n// over in the adapter, not passed per-call).\n// ============================================================================\n\nexport interface KVStorage {\n /** Returns the stored value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /**\n * List all keys, optionally filtered to those starting with prefix.\n * Order is implementation-defined.\n */\n listKeys(prefix?: string): string[];\n}\n\n// ============================================================================\n// JSONStorage — KV store with JSON-aware merge operations\n//\n// Backed by KVStorage under the hood. Adds deepMerge and shallowMerge so\n// callers never need to read-modify-write manually for partial updates.\n// ============================================================================\n\nexport interface JSONStorage {\n /** Returns the stored JSON value, or null if the key does not exist. */\n read(key: string): unknown | null;\n\n /**\n * Read a nested value inside the stored object using a dot-notation path.\n * e.g. get('myKey', 'a.b.c') returns the value at { a: { b: { c: ... } } }.\n * Returns null if the key does not exist or the path cannot be traversed.\n */\n get(key: string, jsonPath: string): unknown | null;\n\n /** Write value at key. Overwrites any existing value. */\n write(key: string, value: unknown): void;\n\n /** Delete the key. No-op if it does not exist. */\n delete(key: string): void;\n\n /** List all keys, optionally filtered by prefix. */\n listKeys(prefix?: string): string[];\n\n /**\n * Shallow-merge patch into the existing object at key.\n * Equivalent to: write(key, { ...read(key), ...patch })\n * Creates the key if it does not exist.\n */\n shallowMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Deep-merge patch into the existing object at key.\n * Recursively merges nested plain objects; arrays and primitives are replaced.\n * Creates the key if it does not exist.\n */\n deepMerge(key: string, patch: Record<string, unknown>): void;\n\n /**\n * Set a nested value inside the stored object using a dot-notation path.\n * e.g. patch('myKey', 'a.b.c', 42) sets { a: { b: { c: 42 } } } into the stored object.\n * Intermediate objects are created if absent. Arrays are not traversed — use integer\n * segments to index into them (e.g. 'items.0.name').\n * Creates the top-level key if it does not exist.\n */\n patch(key: string, jsonPath: string, value: unknown): void;\n}\n\n// ============================================================================\n// StorageProvider — aggregate of all three primitives\n//\n// Adapter factories receive a StorageProvider and close over any scope (e.g.\n// boardDir) themselves. This is the single injection point for swapping\n// backends (Node fs → CosmosDB, browser localStorage, test doubles, etc.).\n// ============================================================================\n\nexport interface StorageProvider {\n blob: BlobStorage;\n journal: JournalStorage;\n kv: KVStorage;\n}\n\n// ============================================================================\n// AtomicRelayLock — non-blocking try-acquire lock with relay-on-busy semantics\n//\n// This interface serves TWO tightly coupled purposes which are intentionally\n// unified into a single primitive:\n//\n// 1. ATOMICITY — ensures that a read-mutate-save cycle is executed by at\n// most one actor at a time, preventing concurrent actors from racing on\n// stale state and writing conflicting snapshots.\n//\n// 2. RELAY SIGNAL — when tryAcquire() returns null, the caller knows the\n// cycle is already in progress. Because the holder always reads fresh\n// state upon entry, it will pick up every change appended by the skipping\n// caller before the lock was attempted. The caller can therefore safely\n// exit — its work will be completed by the holder. This is the\n// \"relay baton\" pattern: the lock being held IS the in-progress signal.\n//\n// These two purposes are not an accidental overload — they are the same\n// invariant expressed at different scopes. Any backend implementation\n// (FS lockfile, Cosmos document lease, Azure entity lock, in-memory flag)\n// that satisfies \"at most one holder at a time\" automatically satisfies both.\n//\n// Contract:\n// - tryAcquire() is non-blocking. It never waits.\n// - Returns a release function on success, or null if already held.\n// - The release function must be called exactly once (use try/finally).\n// - Behaviour after calling release() more than once is undefined.\n// ============================================================================\n\nexport interface AtomicRelayLock {\n /**\n * Attempt to acquire the lock without blocking.\n * Returns a `release` function if successful, or `null` if the lock is\n * already held by another actor (relay: that actor will complete the work).\n */\n tryAcquire(): (() => void) | null;\n}\n\n/**\n * Execute `work` under an `AtomicRelayLock`.\n *\n * - If the lock is busy, returns false immediately (relay: the holder will\n * complete the work on behalf of this caller).\n * - If acquired, runs `work` exclusively, releases the lock, then calls\n * `continuation` if provided — allowing the caller to schedule the next\n * cycle (e.g. spawn a detached process) after the lock is free.\n * - Returns true if work ran.\n */\nexport async function withRelayLock(\n lock: AtomicRelayLock,\n work: () => Promise<void>,\n continuation?: () => void,\n): Promise<boolean> {\n const release = lock.tryAcquire();\n if (!release) return false; // relay: holder is already doing the work\n try {\n await work();\n } finally {\n release(); // release before continuation so it can immediately re-acquire\n }\n continuation?.();\n return true;\n}\n","/**\n * step-machine-public — handler factory\n *\n * Builds engine-facing StepHandlers from declarative HandlerSpec entries.\n * Pure: no Node imports, no transport. Refs are dispatched through the\n * caller-supplied `InvokeFn`, which is the single boundary between this lib\n * and any transport (Node spawn, HTTP, Azure Function, etc.).\n *\n * Layering:\n *\n * step-machine (pure FSM) — runs handlers, never builds them.\n * step-machine-public (this lib) — declarative spec → StepHandler map.\n * adapter (e.g. node-spawn-invoker) — InvokeFn implementation per transport.\n * step-machine-cli (thin shell) — wires adapter + flow loader + run.\n */\n\nimport { jsonata } from './jsonata-loader.js';\nimport { wrapWithInputValidations, wrapWithOutputFiltering } from './result-utils.js';\nimport { resolveOutputTransforms } from '../cli/common/args-massaging.js';\nimport { serializeRef } from '../cli/common/storage-interface.js';\nimport type {\n ComputeJsonataSpec,\n HandlerSpec,\n InvokeRefFn,\n NormalizedHandlerResult,\n RefSpec,\n StepConfigForFactory,\n StepHandler,\n} from './types.js';\n\n// ============================================================================\n// Discriminators\n// ============================================================================\n\nexport function isComputeJsonataSpec(spec: unknown): spec is ComputeJsonataSpec {\n return (\n !!spec &&\n typeof spec === 'object' &&\n (spec as Record<string, unknown>).type === 'compute-jsonata' &&\n Array.isArray((spec as Record<string, unknown>).expr) &&\n ((spec as Record<string, unknown>).expr as unknown[]).length > 0\n );\n}\n\nexport function isRefSpec(spec: unknown): spec is RefSpec {\n if (!spec || typeof spec !== 'object') return false;\n const s = spec as Record<string, unknown>;\n if (s.type !== 'ref' || typeof s.howToRun !== 'string') return false;\n if (typeof s.whatToRun === 'string') return true;\n if (s.whatToRun && typeof s.whatToRun === 'object') {\n const w = s.whatToRun as Record<string, unknown>;\n return typeof w.kind === 'string' && typeof w.value === 'string';\n }\n return false;\n}\n\n// ============================================================================\n// Compute-jsonata handler\n// ============================================================================\n\ninterface NormalizedComputeStep {\n bindTo: string;\n expr: string;\n}\n\nfunction normalizeComputeStep(item: string | { bindTo: string; expr: string }): NormalizedComputeStep {\n if (typeof item === 'string') {\n const eq = item.indexOf('=');\n if (eq < 1) {\n throw new Error(`[step-machine-public] Invalid compute expression (missing \"=\"): \"${item}\"`);\n }\n return { bindTo: item.slice(0, eq).trim(), expr: item.slice(eq + 1).trim() };\n }\n if (item && typeof item === 'object' && typeof item.bindTo === 'string' && typeof item.expr === 'string') {\n return item;\n }\n throw new Error(`[step-machine-public] Invalid compute step: ${JSON.stringify(item)}`);\n}\n\n/** Mutate nested dict via dot-path key. */\nfunction deepSet(obj: Record<string, unknown>, path: string, value: unknown): void {\n const parts = path.split('.');\n let cur: Record<string, unknown> = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i];\n if (cur[k] == null || typeof cur[k] !== 'object') cur[k] = {};\n cur = cur[k] as Record<string, unknown>;\n }\n cur[parts[parts.length - 1]] = value;\n}\n\nexport function createComputeJsonataHandler(\n spec: ComputeJsonataSpec,\n stepName: string,\n config?: Record<string, unknown>,\n): StepHandler {\n const steps = spec.expr.map(normalizeComputeStep);\n return async (input) => {\n const expects_data: Record<string, unknown> =\n input && typeof input === 'object' && !Array.isArray(input)\n ? { ...input }\n : {};\n\n // `data` accumulates computed outputs; it is placed in ctx by reference\n // so subsequent expressions can read `data.x` after earlier steps set it.\n const data: Record<string, unknown> = {};\n\n // Context shape:\n // expects_data — named namespace for declared step inputs (from flow state)\n // data — accumulating output namespace (required, mutated by reference)\n // config — optional step-level config\n const ctx: Record<string, unknown> = {\n expects_data,\n data, // same reference — mutations visible in later steps\n ...(config ? { config } : {}),\n };\n\n let transitionResult: string | undefined;\n let transitionError: string | undefined;\n\n for (const step of steps) {\n try {\n const val = jsonata(step.expr).evaluate(ctx);\n\n if (step.bindTo === 'result') {\n // Transition outcome\n transitionResult = val != null ? String(val) : 'success';\n } else if (step.bindTo === 'error') {\n // Transition error detail\n transitionError = val != null ? String(val) : undefined;\n } else if (step.bindTo.startsWith('data.')) {\n // Namespaced output — mutates the shared data reference\n deepSet(data, step.bindTo.slice('data.'.length), val);\n } else {\n return {\n result: 'failure',\n data: {},\n error: `[${stepName}] invalid bindTo \"${step.bindTo}\": must be \"result\", \"error\", or start with \"data.\"`,\n };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: 'failure',\n data: {},\n error: `[${stepName}] compute \"${step.bindTo}\" failed: ${msg}`,\n };\n }\n }\n\n if (transitionResult === undefined) {\n return {\n result: 'failure',\n data: {},\n error: `[${stepName}] compute-jsonata: no \"result\" binding declared — add '- result = \"success\"' to expr`,\n };\n }\n return transitionError\n ? { result: transitionResult, data, error: transitionError }\n : { result: transitionResult, data };\n };\n}\n\n// ============================================================================\n// Ref handler — dispatches via InvokeFn\n// ============================================================================\n\nexport function createRefStepHandler(\n spec: RefSpec,\n stepName: string,\n invoke: InvokeRefFn,\n config?: Record<string, unknown>,\n): StepHandler {\n // The handler spec itself is a superset of ExecutionRef. Strip the discriminator\n // before passing to the adapter so it sees a plain ExecutionRef.\n // Normalize whatToRun from object form { kind, value } → b64 string.\n const { type: _t, ...refOnly } = spec;\n const ref = {\n ...refOnly,\n whatToRun: typeof refOnly.whatToRun === 'object'\n ? serializeRef(refOnly.whatToRun)\n : refOnly.whatToRun,\n };\n\n return async (input) => {\n const stepInput: Record<string, unknown> =\n input && typeof input === 'object' && !Array.isArray(input)\n ? { ...input }\n : {};\n if (config) stepInput.config = config;\n\n try {\n const raw = await invoke(ref, stepInput);\n if (!spec.outputTransforms) return raw;\n try {\n return resolveOutputTransforms(spec.outputTransforms, raw, stepName);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return { result: 'failure', data: {}, error: msg };\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n result: 'failure',\n data: { error: `[step-machine-public] step \"${stepName}\" invoke threw: ${msg}` },\n };\n }\n };\n}\n\n// ============================================================================\n// Passthrough handler\n// ============================================================================\n\nexport function createPassthroughHandler(): StepHandler {\n return async (input) => {\n const data: Record<string, unknown> =\n input && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n return { result: 'success', data };\n };\n}\n\n// ============================================================================\n// resolveStepHandler — pick + decorate the right handler for a step\n// ============================================================================\n\nexport interface ResolveStepHandlerOptions {\n invoke: InvokeRefFn;\n}\n\nexport function resolveStepHandler(\n stepName: string,\n stepConfig: StepConfigForFactory | undefined,\n options: ResolveStepHandlerOptions,\n): StepHandler {\n const produces = Array.isArray(stepConfig?.produces_data) ? stepConfig?.produces_data : undefined;\n const inputValidations = Array.isArray(stepConfig?.input_validations)\n ? stepConfig?.input_validations\n : undefined;\n const config = stepConfig?.config ?? undefined;\n const spec: HandlerSpec | undefined = stepConfig?.handler;\n\n let base: StepHandler;\n if (isComputeJsonataSpec(spec)) {\n // compute-jsonata: validations are baked in via the wrapper as well; both work.\n base = createComputeJsonataHandler(spec, stepName, config);\n } else if (isRefSpec(spec)) {\n base = createRefStepHandler(spec, stepName, options.invoke, config);\n } else {\n base = createPassthroughHandler();\n }\n\n return wrapWithInputValidations(\n wrapWithOutputFiltering(base, produces),\n inputValidations,\n stepName,\n );\n}\n\n// ============================================================================\n// buildStepHandlersForFlow — produce the Record<stepName, StepHandler> map\n// ============================================================================\n\nexport interface BuildStepHandlersOptions {\n invoke: InvokeRefFn;\n}\n\nexport function buildStepHandlersForFlow(\n flow: { steps?: Record<string, StepConfigForFactory> },\n options: BuildStepHandlersOptions,\n): Record<string, StepHandler> {\n const handlers: Record<string, StepHandler> = {};\n for (const [stepName, stepConfig] of Object.entries(flow.steps ?? {})) {\n handlers[stepName] = resolveStepHandler(stepName, stepConfig, options);\n }\n return handlers;\n}\n\n// Re-export for adapter convenience.\nexport type { NormalizedHandlerResult };\n"]}
|