@ankhorage/flow 0.0.0-stage → 0.4.1

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.
Files changed (109) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +17 -2
  4. package/dist/ai.d.ts +7 -0
  5. package/dist/ai.d.ts.map +1 -0
  6. package/dist/ai.js +7 -0
  7. package/dist/ai.js.map +1 -0
  8. package/dist/features/execution/application/executeFlowAsync.d.ts +4 -0
  9. package/dist/features/execution/application/executeFlowAsync.d.ts.map +1 -0
  10. package/dist/features/execution/application/executeFlowAsync.js +211 -0
  11. package/dist/features/execution/application/executeFlowAsync.js.map +1 -0
  12. package/dist/features/execution/domain/assertFlowGraphSchemasSupported.d.ts +5 -0
  13. package/dist/features/execution/domain/assertFlowGraphSchemasSupported.d.ts.map +1 -0
  14. package/dist/features/execution/domain/assertFlowGraphSchemasSupported.js +11 -0
  15. package/dist/features/execution/domain/assertFlowGraphSchemasSupported.js.map +1 -0
  16. package/dist/features/execution/domain/compileFlowGraph.d.ts +5 -0
  17. package/dist/features/execution/domain/compileFlowGraph.d.ts.map +1 -0
  18. package/dist/features/execution/domain/compileFlowGraph.js +76 -0
  19. package/dist/features/execution/domain/compileFlowGraph.js.map +1 -0
  20. package/dist/features/execution/domain/createDefaultNodeRegistry.d.ts +4 -0
  21. package/dist/features/execution/domain/createDefaultNodeRegistry.d.ts.map +1 -0
  22. package/dist/features/execution/domain/createDefaultNodeRegistry.js +15 -0
  23. package/dist/features/execution/domain/createDefaultNodeRegistry.js.map +1 -0
  24. package/dist/features/execution/domain/validateFlowDataSchema.d.ts +6 -0
  25. package/dist/features/execution/domain/validateFlowDataSchema.d.ts.map +1 -0
  26. package/dist/features/execution/domain/validateFlowDataSchema.js +144 -0
  27. package/dist/features/execution/domain/validateFlowDataSchema.js.map +1 -0
  28. package/dist/features/mcp/McpToolError.d.ts +6 -0
  29. package/dist/features/mcp/McpToolError.d.ts.map +1 -0
  30. package/dist/features/mcp/McpToolError.js +10 -0
  31. package/dist/features/mcp/McpToolError.js.map +1 -0
  32. package/dist/features/mcp/createMcpRemoteTransport.d.ts +8 -0
  33. package/dist/features/mcp/createMcpRemoteTransport.d.ts.map +1 -0
  34. package/dist/features/mcp/createMcpRemoteTransport.js +23 -0
  35. package/dist/features/mcp/createMcpRemoteTransport.js.map +1 -0
  36. package/dist/features/mcp/createMcpToolRegistry.d.ts +10 -0
  37. package/dist/features/mcp/createMcpToolRegistry.d.ts.map +1 -0
  38. package/dist/features/mcp/createMcpToolRegistry.js +185 -0
  39. package/dist/features/mcp/createMcpToolRegistry.js.map +1 -0
  40. package/dist/features/mcp/loadMcpSdkAsync.d.ts +12 -0
  41. package/dist/features/mcp/loadMcpSdkAsync.d.ts.map +1 -0
  42. package/dist/features/mcp/loadMcpSdkAsync.js +20 -0
  43. package/dist/features/mcp/loadMcpSdkAsync.js.map +1 -0
  44. package/dist/features/mcp/prepareMcpProviders.d.ts +4 -0
  45. package/dist/features/mcp/prepareMcpProviders.d.ts.map +1 -0
  46. package/dist/features/mcp/prepareMcpProviders.js +97 -0
  47. package/dist/features/mcp/prepareMcpProviders.js.map +1 -0
  48. package/dist/features/mcp/validateMcpSchema.d.ts +6 -0
  49. package/dist/features/mcp/validateMcpSchema.d.ts.map +1 -0
  50. package/dist/features/mcp/validateMcpSchema.js +220 -0
  51. package/dist/features/mcp/validateMcpSchema.js.map +1 -0
  52. package/dist/features/security/FlowSecurityError.d.ts +6 -0
  53. package/dist/features/security/FlowSecurityError.d.ts.map +1 -0
  54. package/dist/features/security/FlowSecurityError.js +10 -0
  55. package/dist/features/security/FlowSecurityError.js.map +1 -0
  56. package/dist/features/security/application/createFlowSecurityPort.d.ts +12 -0
  57. package/dist/features/security/application/createFlowSecurityPort.d.ts.map +1 -0
  58. package/dist/features/security/application/createFlowSecurityPort.js +208 -0
  59. package/dist/features/security/application/createFlowSecurityPort.js.map +1 -0
  60. package/dist/features/security/domain/validateFlowSecurityTarget.d.ts +4 -0
  61. package/dist/features/security/domain/validateFlowSecurityTarget.d.ts.map +1 -0
  62. package/dist/features/security/domain/validateFlowSecurityTarget.js +57 -0
  63. package/dist/features/security/domain/validateFlowSecurityTarget.js.map +1 -0
  64. package/dist/index.d.ts +9 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +7 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/mcp.d.ts +4 -0
  69. package/dist/mcp.d.ts.map +1 -0
  70. package/dist/mcp.js +3 -0
  71. package/dist/mcp.js.map +1 -0
  72. package/dist/social.d.ts +7 -0
  73. package/dist/social.d.ts.map +1 -0
  74. package/dist/social.js +7 -0
  75. package/dist/social.js.map +1 -0
  76. package/dist/types/execution.d.ts +33 -0
  77. package/dist/types/execution.d.ts.map +1 -0
  78. package/dist/types/execution.js +2 -0
  79. package/dist/types/execution.js.map +1 -0
  80. package/dist/types/mcp.d.ts +61 -0
  81. package/dist/types/mcp.d.ts.map +1 -0
  82. package/dist/types/mcp.js +2 -0
  83. package/dist/types/mcp.js.map +1 -0
  84. package/dist/types/security.d.ts +123 -0
  85. package/dist/types/security.d.ts.map +1 -0
  86. package/dist/types/security.js +2 -0
  87. package/dist/types/security.js.map +1 -0
  88. package/package.json +86 -4
  89. package/src/ai.ts +6 -0
  90. package/src/features/execution/application/executeFlowAsync.ts +338 -0
  91. package/src/features/execution/domain/assertFlowGraphSchemasSupported.ts +17 -0
  92. package/src/features/execution/domain/compileFlowGraph.ts +97 -0
  93. package/src/features/execution/domain/createDefaultNodeRegistry.ts +26 -0
  94. package/src/features/execution/domain/validateFlowDataSchema.ts +218 -0
  95. package/src/features/mcp/McpToolError.ts +10 -0
  96. package/src/features/mcp/createMcpRemoteTransport.ts +34 -0
  97. package/src/features/mcp/createMcpToolRegistry.ts +324 -0
  98. package/src/features/mcp/loadMcpSdkAsync.ts +32 -0
  99. package/src/features/mcp/prepareMcpProviders.ts +135 -0
  100. package/src/features/mcp/validateMcpSchema.ts +269 -0
  101. package/src/features/security/FlowSecurityError.ts +17 -0
  102. package/src/features/security/application/createFlowSecurityPort.ts +339 -0
  103. package/src/features/security/domain/validateFlowSecurityTarget.ts +73 -0
  104. package/src/index.ts +35 -0
  105. package/src/mcp.ts +11 -0
  106. package/src/social.ts +6 -0
  107. package/src/types/execution.ts +41 -0
  108. package/src/types/mcp.ts +70 -0
  109. package/src/types/security.ts +148 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,33 @@
1
+ # @ankhorage/flow
2
+
3
+ ## 0.4.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 8e96c13: Load the optional MCP SDK only when MCP discovery or approved execution opens a provider connection.
8
+
9
+ ## 0.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - f7431ac: Add a provider-neutral Flow security port with scoped authorization, full-identity approval gates,
14
+ host-persisted atomic claim and consumption, audit events, rate limits, SSRF-safe targets, and
15
+ server-only secret resolution. Remote MCP execution now requires this explicit security boundary
16
+ and a host-owned transport that controls every resolved peer connection.
17
+
18
+ ## 0.3.0
19
+
20
+ ### Minor Changes
21
+
22
+ - 9bd21b1: Add an optional, fail-closed MCP tool discovery entrypoint with explicit provider and tool scopes.
23
+
24
+ ## 0.2.0
25
+
26
+ ### Minor Changes
27
+
28
+ - 24a9d4d: Bootstrap the standalone Flow package with public provider subpaths and packed-consumer validation.
29
+ - 1ba3dca: Add deterministic headless graph compilation, safe built-in operations, and single-process execution.
30
+
31
+ ### Patch Changes
32
+
33
+ - 5b3e567: Declare the published workflow contracts dependency used by Flow's public consumer boundary.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ankhorage
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,18 @@
1
- # Temporary Holding Version
1
+ <!-- markdownlint-disable MD013 MD033 -->
2
+ <!-- This file is generated by Paradox. Do not edit manually. -->
2
3
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
4
+ # @ankhorage/flow
5
+
6
+ ![license: MIT](././paradox/badges/license.svg) ![npm: v0.4.1](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: configured](././paradox/badges/tests.svg) ![paradox: canonical](././paradox/badges/docs.svg)
7
+
8
+ Standalone workflow engine foundation for Ankhorage.
9
+
10
+ ## Generated documentation
11
+
12
+ - [Interactive documentation app](././paradox/index.html)
13
+ - [Public API reference](././paradox/exports.md)
14
+ - [Component registry](././paradox/components.md)
15
+ - [Architecture overview](././paradox/diagrams/architecture-overview.mmd)
16
+ - [Module relationships](././paradox/diagrams/module-relationships.mmd)
17
+ - [Export graph](././paradox/diagrams/export-graph.mmd)
18
+ - [compileFlowGraph sequence](././paradox/diagrams/sequences/compile-flow-graph.mmd)
package/dist/ai.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /***
2
+ * Reserved public subpath for future AI-provider adapters.
3
+ *
4
+ * This bootstrap intentionally provides no AI execution, configuration, or dependencies.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=ai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,CAAC"}
package/dist/ai.js ADDED
@@ -0,0 +1,7 @@
1
+ /***
2
+ * Reserved public subpath for future AI-provider adapters.
3
+ *
4
+ * This bootstrap intentionally provides no AI execution, configuration, or dependencies.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=ai.js.map
package/dist/ai.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai.js","sourceRoot":"","sources":["../src/ai.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,CAAC","sourcesContent":["/***\n * Reserved public subpath for future AI-provider adapters.\n *\n * This bootstrap intentionally provides no AI execution, configuration, or dependencies.\n */\nexport {};\n"]}
@@ -0,0 +1,4 @@
1
+ import type { FlowClock, FlowCompiledGraph, FlowExecutionResult, FlowNodeRegistry, FlowRunRequest } from '../../../types/execution.js';
2
+ /*** Execute a compiled graph in deterministic order within one process. */
3
+ export declare const executeFlowAsync: (graph: FlowCompiledGraph, registry: FlowNodeRegistry, request: FlowRunRequest, clock?: FlowClock) => Promise<FlowExecutionResult>;
4
+ //# sourceMappingURL=executeFlowAsync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executeFlowAsync.d.ts","sourceRoot":"","sources":["../../../../src/features/execution/application/executeFlowAsync.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,SAAS,EACT,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACf,MAAM,6BAA6B,CAAC;AAIrC,2EAA2E;AAC3E,eAAO,MAAM,gBAAgB,GAC3B,OAAO,iBAAiB,EACxB,UAAU,gBAAgB,EAC1B,SAAS,cAAc,EACvB,QAAO,SAAqC,KAC3C,OAAO,CAAC,mBAAmB,CAiB7B,CAAC"}
@@ -0,0 +1,211 @@
1
+ import { assertFlowGraphSchemasSupported } from '../domain/assertFlowGraphSchemasSupported.js';
2
+ import { validateFlowDataSchema } from '../domain/validateFlowDataSchema.js';
3
+ /*** Execute a compiled graph in deterministic order within one process. */
4
+ export const executeFlowAsync = async (graph, registry, request, clock = { now: () => new Date() }) => {
5
+ const trigger = graph.definition.triggers.find(({ id }) => id === request.triggerId);
6
+ if (trigger?.kind !== 'manual')
7
+ throw new Error('FLOW_TRIGGER_NOT_MANUAL');
8
+ assertFlowGraphSchemasSupported(graph.definition.nodes, request.schemaRegistry);
9
+ const startedAt = clock.now().toISOString();
10
+ const state = await executeNodesAsync(graph, registry, request, clock);
11
+ return {
12
+ run: createRun(graph, request, state.steps, startedAt, clock.now().toISOString(), state.status ?? 'succeeded', state.error),
13
+ };
14
+ };
15
+ /*** Iterate compiled nodes in deterministic order until completion or cancellation. */
16
+ const executeNodesAsync = async (graph, registry, request, clock) => {
17
+ const state = {
18
+ activatedNodeIds: new Set(graph.topologicalNodeIds.filter((nodeId) => !graph.definition.edges.some((edge) => edge.target.nodeId === nodeId))),
19
+ inputs: {},
20
+ steps: [],
21
+ };
22
+ for (const nodeId of graph.topologicalNodeIds) {
23
+ if (request.signal?.aborted)
24
+ return { ...state, status: 'cancelled' };
25
+ const node = graph.definition.nodes.find((candidate) => candidate.id === nodeId);
26
+ if (!node)
27
+ throw new Error(`FLOW_GRAPH_UNKNOWN_NODE:${nodeId}`);
28
+ const result = await executeAvailableNodeAsync(node, state, registry, request, clock);
29
+ if (!result)
30
+ continue;
31
+ state.steps.push(result.step);
32
+ if (result.step.status === 'cancelled')
33
+ return { ...state, status: 'cancelled' };
34
+ propagateOutput(graph.edgesBySourceNodeId[node.id] ?? [], result.output, result.step.status === 'failed' ? 'failure' : 'success', state);
35
+ }
36
+ const failedStep = state.steps.find((step) => step.status === 'failed');
37
+ return { ...state, status: failedStep ? 'failed' : 'succeeded', error: failedStep?.error };
38
+ };
39
+ /*** Execute one node only when all of its required inputs were propagated. */
40
+ const executeAvailableNodeAsync = async (node, state, registry, request, clock) => {
41
+ if (!state.activatedNodeIds.has(node.id))
42
+ return undefined;
43
+ const input = state.inputs[node.id] ?? request.input ?? {};
44
+ if (!hasRequiredInput(node, input))
45
+ return undefined;
46
+ return executeNodeAsync(node, input, registry, request.signal, clock, request.schemaRegistry);
47
+ };
48
+ /*** Determine whether every required input port has a propagated value. */
49
+ const hasRequiredInput = (node, input) => node.ports
50
+ .filter((port) => port.direction === 'input' && port.required)
51
+ .every((port) => input[port.id] !== undefined);
52
+ /*** Execute one node and convert failures to redaction-safe contract errors. */
53
+ const executeNodeAsync = async (node, input, registry, signal, clock, schemas) => {
54
+ const startedAt = clock.now().toISOString();
55
+ try {
56
+ assertPortSchemas(node, input, 'input', schemas);
57
+ const operationId = `${node.capability.providerId}:${node.capability.capabilityId}`;
58
+ const operation = Object.entries(registry).find(([id]) => id === operationId)?.[1];
59
+ if (!operation)
60
+ throw new Error(`FLOW_OPERATION_UNREGISTERED:${operationId}`);
61
+ const output = (await operation.executeAsync({
62
+ config: node.config,
63
+ input,
64
+ node,
65
+ signal: signal ?? new AbortController().signal,
66
+ })).output ?? {};
67
+ if (signal?.aborted)
68
+ return { output: {}, step: createCancelledStep(node, input, startedAt, clock) };
69
+ assertOutputPorts(node, output);
70
+ assertPortSchemas(node, output, 'output', schemas);
71
+ return { output, step: createSucceededStep(node, input, output, startedAt, clock) };
72
+ }
73
+ catch (reason) {
74
+ const error = asFlowError(reason);
75
+ return {
76
+ output: {},
77
+ step: {
78
+ id: `${node.id}:1`,
79
+ nodeId: node.id,
80
+ status: 'failed',
81
+ attempt: 1,
82
+ startedAt,
83
+ completedAt: clock.now().toISOString(),
84
+ input,
85
+ error,
86
+ },
87
+ };
88
+ }
89
+ };
90
+ /*** Create an immutable successful step snapshot. */
91
+ const createSucceededStep = (node, input, output, startedAt, clock) => ({
92
+ id: `${node.id}:1`,
93
+ nodeId: node.id,
94
+ status: 'succeeded',
95
+ attempt: 1,
96
+ startedAt,
97
+ completedAt: clock.now().toISOString(),
98
+ input,
99
+ output,
100
+ });
101
+ /*** Create a terminal snapshot when cancellation occurs during asynchronous node execution. */
102
+ const createCancelledStep = (node, input, startedAt, clock) => ({
103
+ id: `${node.id}:1`,
104
+ nodeId: node.id,
105
+ status: 'cancelled',
106
+ attempt: 1,
107
+ startedAt,
108
+ completedAt: clock.now().toISOString(),
109
+ input,
110
+ });
111
+ /*** Reject operation outputs that do not correspond to declared output ports. */
112
+ const assertOutputPorts = (node, output) => {
113
+ const outputIds = new Set(node.ports.filter((port) => port.direction === 'output').map(({ id }) => id));
114
+ if (Object.keys(output).some((portId) => !outputIds.has(portId)))
115
+ throw new Error(`FLOW_OUTPUT_UNDECLARED_PORT:${node.id}`);
116
+ const missingRequired = node.ports.some((port) => port.direction === 'output' && port.required && output[port.id] === undefined);
117
+ if (missingRequired)
118
+ throw new Error(`FLOW_OUTPUT_REQUIRED_PORT_MISSING:${node.id}`);
119
+ };
120
+ /*** Validate inline port values against their declared portable schemas. */
121
+ const assertPortSchemas = (node, values, direction, schemas) => {
122
+ for (const port of node.ports.filter((candidate) => candidate.direction === direction)) {
123
+ const value = values[port.id];
124
+ const schema = port.data?.schema ?? (port.data?.schemaRef ? { ref: port.data.schemaRef } : undefined);
125
+ if (value?.kind === 'inline' && schema && !validateFlowDataSchema(value.value, schema, schemas))
126
+ throw new Error(`FLOW_PORT_SCHEMA_MISMATCH:${node.id}:${port.id}`);
127
+ }
128
+ };
129
+ /*** Propagate outputs only over edges whose declared condition matches the output value. */
130
+ const propagateOutput = (edges, output, outcome, state) => {
131
+ for (const edge of edges) {
132
+ const value = output[edge.source.portId];
133
+ if (!matchesEdge(edge, value, outcome))
134
+ continue;
135
+ state.activatedNodeIds.add(edge.target.nodeId);
136
+ if (value)
137
+ state.inputs[edge.target.nodeId] = {
138
+ ...state.inputs[edge.target.nodeId],
139
+ [edge.target.portId]: value,
140
+ };
141
+ }
142
+ };
143
+ /*** Evaluate an edge condition without executing arbitrary expressions. */
144
+ const matchesEdge = (edge, value, outcome) => {
145
+ const condition = edge.condition ?? { kind: 'always' };
146
+ if (condition.kind === 'always')
147
+ return outcome === 'success';
148
+ if (condition.kind === 'outcome')
149
+ return condition.outcome === outcome;
150
+ if (value?.kind !== 'inline')
151
+ return false;
152
+ const selected = resolvePointer(value.value, condition.path);
153
+ return selected !== undefined && structurallyEqual(selected, condition.equals);
154
+ };
155
+ /*** Resolve an RFC 6901 pointer against serializable inline data. */
156
+ const resolvePointer = (value, pointer) => {
157
+ if (pointer === '')
158
+ return value;
159
+ if (!pointer.startsWith('/'))
160
+ return undefined;
161
+ return pointer
162
+ .slice(1)
163
+ .split('/')
164
+ .reduce((current, segment) => {
165
+ if (current === undefined || current === null || typeof current !== 'object')
166
+ return undefined;
167
+ const key = segment.replaceAll('~1', '/').replaceAll('~0', '~');
168
+ if (isDataArray(current))
169
+ return current.find((_item, index) => index === Number(key));
170
+ return isDataRecord(current)
171
+ ? Object.entries(current).find(([candidateKey]) => candidateKey === key)?.[1]
172
+ : undefined;
173
+ }, value);
174
+ };
175
+ /*** Compare JSON-compatible values with object-key-order independence. */
176
+ const structurallyEqual = (left, right) => JSON.stringify(normalizeValue(left)) === JSON.stringify(normalizeValue(right));
177
+ /*** Canonicalize object member ordering for structural equality. */
178
+ const normalizeValue = (value) => {
179
+ if (Array.isArray(value))
180
+ return value.map(normalizeValue);
181
+ if (value !== null && typeof value === 'object')
182
+ return Object.fromEntries(Object.entries(value)
183
+ .sort(([left], [right]) => left.localeCompare(right))
184
+ .map(([key, item]) => [key, normalizeValue(item)]));
185
+ return value;
186
+ };
187
+ /*** Narrow a serializable non-array object to an indexable data record. */
188
+ const isDataRecord = (value) => !Array.isArray(value);
189
+ /*** Narrow a serializable array without losing its element type. */
190
+ const isDataArray = (value) => Array.isArray(value);
191
+ /*** Translate host failures to structured contract errors without exposing arbitrary objects. */
192
+ const asFlowError = (reason) => ({
193
+ code: reason instanceof Error && /^FLOW_[A-Z0-9_]+(?::|$)/.test(reason.message)
194
+ ? (reason.message.split(':')[0] ?? 'FLOW_OPERATION_FAILED')
195
+ : 'FLOW_OPERATION_FAILED',
196
+ message: 'The operation failed.',
197
+ retryable: false,
198
+ });
199
+ /*** Build the immutable run result emitted by the single-process executor. */
200
+ const createRun = (graph, request, steps, startedAt, completedAt, status, error) => ({
201
+ id: request.runId,
202
+ flow: { id: graph.definition.id, version: graph.definition.version },
203
+ status,
204
+ trigger: { triggerId: request.triggerId, kind: 'manual' },
205
+ createdAt: startedAt,
206
+ startedAt,
207
+ completedAt,
208
+ steps,
209
+ error,
210
+ });
211
+ //# sourceMappingURL=executeFlowAsync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executeFlowAsync.js","sourceRoot":"","sources":["../../../../src/features/execution/application/executeFlowAsync.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,+BAA+B,EAAE,MAAM,8CAA8C,CAAC;AAC/F,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,KAAwB,EACxB,QAA0B,EAC1B,OAAuB,EACvB,QAAmB,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,EACd,EAAE;IAChC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACrF,IAAI,OAAO,EAAE,IAAI,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC3E,+BAA+B,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;IAChF,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACvE,OAAO;QACL,GAAG,EAAE,SAAS,CACZ,KAAK,EACL,OAAO,EACP,KAAK,CAAC,KAAK,EACX,SAAS,EACT,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,EACzB,KAAK,CAAC,MAAM,IAAI,WAAW,EAC3B,KAAK,CAAC,KAAK,CACZ;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,uFAAuF;AACvF,MAAM,iBAAiB,GAAG,KAAK,EAC7B,KAAwB,EACxB,QAA0B,EAC1B,OAAuB,EACvB,KAAgB,EACS,EAAE;IAC3B,MAAM,KAAK,GAAmB;QAC5B,gBAAgB,EAAE,IAAI,GAAG,CACvB,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAC7B,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAClF,CACF;QACD,MAAM,EAAE,EAAE;QACV,KAAK,EAAE,EAAE;KACV,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;QAC9C,IAAI,OAAO,CAAC,MAAM,EAAE,OAAO;YAAE,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACtE,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;QACjF,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,MAAM,EAAE,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACtF,IAAI,CAAC,MAAM;YAAE,SAAS;QACtB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,WAAW;YAAE,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QACjF,eAAe,CACb,KAAK,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,EACxC,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EACvD,KAAK,CACN,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;IACxE,OAAO,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAC7F,CAAC,CAAC;AAUF,8EAA8E;AAC9E,MAAM,yBAAyB,GAAG,KAAK,EACrC,IAAc,EACd,KAAqB,EACrB,QAA0B,EAC1B,OAAuB,EACvB,KAAgB,EAIhB,EAAE;IACF,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;IAC3D,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACrD,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;AAChG,CAAC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,gBAAgB,GAAG,CACvB,IAAc,EACd,KAAgD,EACvC,EAAE,CACX,IAAI,CAAC,KAAK;KACP,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC;KAC7D,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC;AAEnD,gFAAgF;AAChF,MAAM,gBAAgB,GAAG,KAAK,EAC5B,IAAc,EACd,KAAgD,EAChD,QAA0B,EAC1B,MAA+B,EAC/B,KAAgB,EAChB,OAAyC,EAIxC,EAAE;IACH,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,IAAI,CAAC;QACH,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC;QACpF,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACnF,IAAI,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,WAAW,EAAE,CAAC,CAAC;QAC9E,MAAM,MAAM,GACV,CACE,MAAM,SAAS,CAAC,YAAY,CAAC;YAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK;YACL,IAAI;YACJ,MAAM,EAAE,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,MAAM;SAC/C,CAAC,CACH,CAAC,MAAM,IAAI,EAAE,CAAC;QACjB,IAAI,MAAM,EAAE,OAAO;YACjB,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;QAClF,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;IACtF,CAAC;IAAC,OAAO,MAAM,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO;YACL,MAAM,EAAE,EAAE;YACV,IAAI,EAAE;gBACJ,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI;gBAClB,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,CAAC;gBACV,SAAS;gBACT,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;gBACtC,KAAK;gBACL,KAAK;aACN;SACF,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,qDAAqD;AACrD,MAAM,mBAAmB,GAAG,CAC1B,IAAc,EACd,KAAgD,EAChD,MAAiD,EACjD,SAAiB,EACjB,KAAgB,EACE,EAAE,CAAC,CAAC;IACtB,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI;IAClB,MAAM,EAAE,IAAI,CAAC,EAAE;IACf,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,CAAC;IACV,SAAS;IACT,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtC,KAAK;IACL,MAAM;CACP,CAAC,CAAC;AAEH,+FAA+F;AAC/F,MAAM,mBAAmB,GAAG,CAC1B,IAAc,EACd,KAAgD,EAChD,SAAiB,EACjB,KAAgB,EACE,EAAE,CAAC,CAAC;IACtB,EAAE,EAAE,GAAG,IAAI,CAAC,EAAE,IAAI;IAClB,MAAM,EAAE,IAAI,CAAC,EAAE;IACf,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,CAAC;IACV,SAAS;IACT,WAAW,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtC,KAAK;CACN,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,iBAAiB,GAAG,CACxB,IAAc,EACd,MAAiD,EAC3C,EAAE;IACR,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAC7E,CAAC;IACF,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC9D,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CACrC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,SAAS,CACxF,CAAC;IACF,IAAI,eAAe;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;AACvF,CAAC,CAAC;AAEF,4EAA4E;AAC5E,MAAM,iBAAiB,GAAG,CACxB,IAAc,EACd,MAAiD,EACjD,SAA6B,EAC7B,OAAyC,EACnC,EAAE;IACR,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,SAAS,KAAK,SAAS,CAAC,EAAE,CAAC;QACvF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,MAAM,GACV,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACzF,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC;YAC7F,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IACvE,CAAC;AACH,CAAC,CAAC;AAEF,4FAA4F;AAC5F,MAAM,eAAe,GAAG,CACtB,KAA0B,EAC1B,MAAiD,EACjD,OAA8B,EAC9B,KAAqB,EACf,EAAE;IACR,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC;YAAE,SAAS;QACjD,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC/C,IAAI,KAAK;YACP,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG;gBACjC,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;gBACnC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK;aAC5B,CAAC;IACN,CAAC;AACH,CAAC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,WAAW,GAAG,CAClB,IAAc,EACd,KAA8B,EAC9B,OAA8B,EACrB,EAAE;IACX,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,IAAI,EAAE,QAAiB,EAAE,CAAC;IAChE,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,OAAO,KAAK,SAAS,CAAC;IAC9D,IAAI,SAAS,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC,OAAO,KAAK,OAAO,CAAC;IACvE,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3C,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7D,OAAO,QAAQ,KAAK,SAAS,IAAI,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;AACjF,CAAC,CAAC;AAEF,qEAAqE;AACrE,MAAM,cAAc,GAAG,CACrB,KAAwB,EACxB,OAAe,EACgB,EAAE;IACjC,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/C,OAAO,OAAO;SACX,KAAK,CAAC,CAAC,CAAC;SACR,KAAK,CAAC,GAAG,CAAC;SACV,MAAM,CAAgC,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;QAC1D,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;YAC1E,OAAO,SAAS,CAAC;QACnB,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChE,IAAI,WAAW,CAAC,OAAO,CAAC;YAAE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACvF,OAAO,YAAY,CAAC,OAAO,CAAC;YAC1B,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,CAAC,YAAY,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YAC7E,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC,EAAE,KAAK,CAAC,CAAC;AACd,CAAC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,iBAAiB,GAAG,CAAC,IAAuB,EAAE,KAAwB,EAAW,EAAE,CACvF,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;AAEjF,oEAAoE;AACpE,MAAM,cAAc,GAAG,CAAC,KAAwB,EAAqB,EAAE;IACrE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAC3D,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAC7C,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aAClB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;aACpD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CACrD,CAAC;IACJ,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,YAAY,GAAG,CAAC,KAAa,EAAwD,EAAE,CAC3F,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAExB,oEAAoE;AACpE,MAAM,WAAW,GAAG,CAAC,KAAa,EAAyC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAEnG,iGAAiG;AACjG,MAAM,WAAW,GAAG,CAAC,MAAe,EAAa,EAAE,CAAC,CAAC;IACnD,IAAI,EACF,MAAM,YAAY,KAAK,IAAI,yBAAyB,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;QACvE,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,uBAAuB,CAAC;QAC3D,CAAC,CAAC,uBAAuB;IAC7B,OAAO,EAAE,uBAAuB;IAChC,SAAS,EAAE,KAAK;CACjB,CAAC,CAAC;AAEH,8EAA8E;AAC9E,MAAM,SAAS,GAAG,CAChB,KAAwB,EACxB,OAAuB,EACvB,KAAkC,EAClC,SAAiB,EACjB,WAAmB,EACnB,MAAiC,EACjC,KAAiB,EACA,EAAE,CAAC,CAAC;IACrB,EAAE,EAAE,OAAO,CAAC,KAAK;IACjB,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE;IACpE,MAAM;IACN,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE;IACzD,SAAS,EAAE,SAAS;IACpB,SAAS;IACT,WAAW;IACX,KAAK;IACL,KAAK;CACN,CAAC,CAAC","sourcesContent":["import type { DataContractValue } from '@ankhorage/contracts/data';\nimport type {\n FlowDataRef,\n FlowEdge,\n FlowError,\n FlowNode,\n FlowPortId,\n FlowRunSnapshot,\n FlowStepSnapshot,\n} from '@ankhorage/contracts/flow';\n\nimport type {\n FlowClock,\n FlowCompiledGraph,\n FlowExecutionResult,\n FlowNodeRegistry,\n FlowRunRequest,\n} from '../../../types/execution.js';\nimport { assertFlowGraphSchemasSupported } from '../domain/assertFlowGraphSchemasSupported.js';\nimport { validateFlowDataSchema } from '../domain/validateFlowDataSchema.js';\n\n/*** Execute a compiled graph in deterministic order within one process. */\nexport const executeFlowAsync = async (\n graph: FlowCompiledGraph,\n registry: FlowNodeRegistry,\n request: FlowRunRequest,\n clock: FlowClock = { now: () => new Date() },\n): Promise<FlowExecutionResult> => {\n const trigger = graph.definition.triggers.find(({ id }) => id === request.triggerId);\n if (trigger?.kind !== 'manual') throw new Error('FLOW_TRIGGER_NOT_MANUAL');\n assertFlowGraphSchemasSupported(graph.definition.nodes, request.schemaRegistry);\n const startedAt = clock.now().toISOString();\n const state = await executeNodesAsync(graph, registry, request, clock);\n return {\n run: createRun(\n graph,\n request,\n state.steps,\n startedAt,\n clock.now().toISOString(),\n state.status ?? 'succeeded',\n state.error,\n ),\n };\n};\n\n/*** Iterate compiled nodes in deterministic order until completion or cancellation. */\nconst executeNodesAsync = async (\n graph: FlowCompiledGraph,\n registry: FlowNodeRegistry,\n request: FlowRunRequest,\n clock: FlowClock,\n): Promise<ExecutionState> => {\n const state: ExecutionState = {\n activatedNodeIds: new Set(\n graph.topologicalNodeIds.filter(\n (nodeId) => !graph.definition.edges.some((edge) => edge.target.nodeId === nodeId),\n ),\n ),\n inputs: {},\n steps: [],\n };\n for (const nodeId of graph.topologicalNodeIds) {\n if (request.signal?.aborted) return { ...state, status: 'cancelled' };\n const node = graph.definition.nodes.find((candidate) => candidate.id === nodeId);\n if (!node) throw new Error(`FLOW_GRAPH_UNKNOWN_NODE:${nodeId}`);\n const result = await executeAvailableNodeAsync(node, state, registry, request, clock);\n if (!result) continue;\n state.steps.push(result.step);\n if (result.step.status === 'cancelled') return { ...state, status: 'cancelled' };\n propagateOutput(\n graph.edgesBySourceNodeId[node.id] ?? [],\n result.output,\n result.step.status === 'failed' ? 'failure' : 'success',\n state,\n );\n }\n const failedStep = state.steps.find((step) => step.status === 'failed');\n return { ...state, status: failedStep ? 'failed' : 'succeeded', error: failedStep?.error };\n};\n\ninterface ExecutionState {\n readonly activatedNodeIds: Set<string>;\n readonly error?: FlowError;\n readonly inputs: Record<string, Record<FlowPortId, FlowDataRef>>;\n readonly status?: FlowRunSnapshot['status'];\n readonly steps: FlowStepSnapshot[];\n}\n\n/*** Execute one node only when all of its required inputs were propagated. */\nconst executeAvailableNodeAsync = async (\n node: FlowNode,\n state: ExecutionState,\n registry: FlowNodeRegistry,\n request: FlowRunRequest,\n clock: FlowClock,\n): Promise<\n | { readonly output: Readonly<Record<FlowPortId, FlowDataRef>>; readonly step: FlowStepSnapshot }\n | undefined\n> => {\n if (!state.activatedNodeIds.has(node.id)) return undefined;\n const input = state.inputs[node.id] ?? request.input ?? {};\n if (!hasRequiredInput(node, input)) return undefined;\n return executeNodeAsync(node, input, registry, request.signal, clock, request.schemaRegistry);\n};\n\n/*** Determine whether every required input port has a propagated value. */\nconst hasRequiredInput = (\n node: FlowNode,\n input: Readonly<Record<FlowPortId, FlowDataRef>>,\n): boolean =>\n node.ports\n .filter((port) => port.direction === 'input' && port.required)\n .every((port) => input[port.id] !== undefined);\n\n/*** Execute one node and convert failures to redaction-safe contract errors. */\nconst executeNodeAsync = async (\n node: FlowNode,\n input: Readonly<Record<FlowPortId, FlowDataRef>>,\n registry: FlowNodeRegistry,\n signal: AbortSignal | undefined,\n clock: FlowClock,\n schemas: FlowRunRequest['schemaRegistry'],\n): Promise<{\n readonly output: Readonly<Record<FlowPortId, FlowDataRef>>;\n readonly step: FlowStepSnapshot;\n}> => {\n const startedAt = clock.now().toISOString();\n try {\n assertPortSchemas(node, input, 'input', schemas);\n const operationId = `${node.capability.providerId}:${node.capability.capabilityId}`;\n const operation = Object.entries(registry).find(([id]) => id === operationId)?.[1];\n if (!operation) throw new Error(`FLOW_OPERATION_UNREGISTERED:${operationId}`);\n const output =\n (\n await operation.executeAsync({\n config: node.config,\n input,\n node,\n signal: signal ?? new AbortController().signal,\n })\n ).output ?? {};\n if (signal?.aborted)\n return { output: {}, step: createCancelledStep(node, input, startedAt, clock) };\n assertOutputPorts(node, output);\n assertPortSchemas(node, output, 'output', schemas);\n return { output, step: createSucceededStep(node, input, output, startedAt, clock) };\n } catch (reason) {\n const error = asFlowError(reason);\n return {\n output: {},\n step: {\n id: `${node.id}:1`,\n nodeId: node.id,\n status: 'failed',\n attempt: 1,\n startedAt,\n completedAt: clock.now().toISOString(),\n input,\n error,\n },\n };\n }\n};\n\n/*** Create an immutable successful step snapshot. */\nconst createSucceededStep = (\n node: FlowNode,\n input: Readonly<Record<FlowPortId, FlowDataRef>>,\n output: Readonly<Record<FlowPortId, FlowDataRef>>,\n startedAt: string,\n clock: FlowClock,\n): FlowStepSnapshot => ({\n id: `${node.id}:1`,\n nodeId: node.id,\n status: 'succeeded',\n attempt: 1,\n startedAt,\n completedAt: clock.now().toISOString(),\n input,\n output,\n});\n\n/*** Create a terminal snapshot when cancellation occurs during asynchronous node execution. */\nconst createCancelledStep = (\n node: FlowNode,\n input: Readonly<Record<FlowPortId, FlowDataRef>>,\n startedAt: string,\n clock: FlowClock,\n): FlowStepSnapshot => ({\n id: `${node.id}:1`,\n nodeId: node.id,\n status: 'cancelled',\n attempt: 1,\n startedAt,\n completedAt: clock.now().toISOString(),\n input,\n});\n\n/*** Reject operation outputs that do not correspond to declared output ports. */\nconst assertOutputPorts = (\n node: FlowNode,\n output: Readonly<Record<FlowPortId, FlowDataRef>>,\n): void => {\n const outputIds = new Set(\n node.ports.filter((port) => port.direction === 'output').map(({ id }) => id),\n );\n if (Object.keys(output).some((portId) => !outputIds.has(portId)))\n throw new Error(`FLOW_OUTPUT_UNDECLARED_PORT:${node.id}`);\n const missingRequired = node.ports.some(\n (port) => port.direction === 'output' && port.required && output[port.id] === undefined,\n );\n if (missingRequired) throw new Error(`FLOW_OUTPUT_REQUIRED_PORT_MISSING:${node.id}`);\n};\n\n/*** Validate inline port values against their declared portable schemas. */\nconst assertPortSchemas = (\n node: FlowNode,\n values: Readonly<Record<FlowPortId, FlowDataRef>>,\n direction: 'input' | 'output',\n schemas: FlowRunRequest['schemaRegistry'],\n): void => {\n for (const port of node.ports.filter((candidate) => candidate.direction === direction)) {\n const value = values[port.id];\n const schema =\n port.data?.schema ?? (port.data?.schemaRef ? { ref: port.data.schemaRef } : undefined);\n if (value?.kind === 'inline' && schema && !validateFlowDataSchema(value.value, schema, schemas))\n throw new Error(`FLOW_PORT_SCHEMA_MISMATCH:${node.id}:${port.id}`);\n }\n};\n\n/*** Propagate outputs only over edges whose declared condition matches the output value. */\nconst propagateOutput = (\n edges: readonly FlowEdge[],\n output: Readonly<Record<FlowPortId, FlowDataRef>>,\n outcome: 'failure' | 'success',\n state: ExecutionState,\n): void => {\n for (const edge of edges) {\n const value = output[edge.source.portId];\n if (!matchesEdge(edge, value, outcome)) continue;\n state.activatedNodeIds.add(edge.target.nodeId);\n if (value)\n state.inputs[edge.target.nodeId] = {\n ...state.inputs[edge.target.nodeId],\n [edge.target.portId]: value,\n };\n }\n};\n\n/*** Evaluate an edge condition without executing arbitrary expressions. */\nconst matchesEdge = (\n edge: FlowEdge,\n value: FlowDataRef | undefined,\n outcome: 'failure' | 'success',\n): boolean => {\n const condition = edge.condition ?? { kind: 'always' as const };\n if (condition.kind === 'always') return outcome === 'success';\n if (condition.kind === 'outcome') return condition.outcome === outcome;\n if (value?.kind !== 'inline') return false;\n const selected = resolvePointer(value.value, condition.path);\n return selected !== undefined && structurallyEqual(selected, condition.equals);\n};\n\n/*** Resolve an RFC 6901 pointer against serializable inline data. */\nconst resolvePointer = (\n value: DataContractValue,\n pointer: string,\n): DataContractValue | undefined => {\n if (pointer === '') return value;\n if (!pointer.startsWith('/')) return undefined;\n return pointer\n .slice(1)\n .split('/')\n .reduce<DataContractValue | undefined>((current, segment) => {\n if (current === undefined || current === null || typeof current !== 'object')\n return undefined;\n const key = segment.replaceAll('~1', '/').replaceAll('~0', '~');\n if (isDataArray(current)) return current.find((_item, index) => index === Number(key));\n return isDataRecord(current)\n ? Object.entries(current).find(([candidateKey]) => candidateKey === key)?.[1]\n : undefined;\n }, value);\n};\n\n/*** Compare JSON-compatible values with object-key-order independence. */\nconst structurallyEqual = (left: DataContractValue, right: DataContractValue): boolean =>\n JSON.stringify(normalizeValue(left)) === JSON.stringify(normalizeValue(right));\n\n/*** Canonicalize object member ordering for structural equality. */\nconst normalizeValue = (value: DataContractValue): DataContractValue => {\n if (Array.isArray(value)) return value.map(normalizeValue);\n if (value !== null && typeof value === 'object')\n return Object.fromEntries(\n Object.entries(value)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, item]) => [key, normalizeValue(item)]),\n );\n return value;\n};\n\n/*** Narrow a serializable non-array object to an indexable data record. */\nconst isDataRecord = (value: object): value is Readonly<Record<string, DataContractValue>> =>\n !Array.isArray(value);\n\n/*** Narrow a serializable array without losing its element type. */\nconst isDataArray = (value: object): value is readonly DataContractValue[] => Array.isArray(value);\n\n/*** Translate host failures to structured contract errors without exposing arbitrary objects. */\nconst asFlowError = (reason: unknown): FlowError => ({\n code:\n reason instanceof Error && /^FLOW_[A-Z0-9_]+(?::|$)/.test(reason.message)\n ? (reason.message.split(':')[0] ?? 'FLOW_OPERATION_FAILED')\n : 'FLOW_OPERATION_FAILED',\n message: 'The operation failed.',\n retryable: false,\n});\n\n/*** Build the immutable run result emitted by the single-process executor. */\nconst createRun = (\n graph: FlowCompiledGraph,\n request: FlowRunRequest,\n steps: readonly FlowStepSnapshot[],\n startedAt: string,\n completedAt: string,\n status: FlowRunSnapshot['status'],\n error?: FlowError,\n): FlowRunSnapshot => ({\n id: request.runId,\n flow: { id: graph.definition.id, version: graph.definition.version },\n status,\n trigger: { triggerId: request.triggerId, kind: 'manual' },\n createdAt: startedAt,\n startedAt,\n completedAt,\n steps,\n error,\n});\n"]}
@@ -0,0 +1,5 @@
1
+ import type { DataSchemaRegistry } from '@ankhorage/contracts/data';
2
+ import type { FlowNode } from '@ankhorage/contracts/flow';
3
+ /*** Validate every declared graph port schema before any operation can perform a side effect. */
4
+ export declare const assertFlowGraphSchemasSupported: (nodes: readonly FlowNode[], schemas: DataSchemaRegistry | undefined) => void;
5
+ //# sourceMappingURL=assertFlowGraphSchemasSupported.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertFlowGraphSchemasSupported.d.ts","sourceRoot":"","sources":["../../../../src/features/execution/domain/assertFlowGraphSchemasSupported.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAI1D,iGAAiG;AACjG,eAAO,MAAM,+BAA+B,GAC1C,OAAO,SAAS,QAAQ,EAAE,EAC1B,SAAS,kBAAkB,GAAG,SAAS,KACtC,IAOF,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { assertFlowDataSchemaSupported } from './validateFlowDataSchema.js';
2
+ /*** Validate every declared graph port schema before any operation can perform a side effect. */
3
+ export const assertFlowGraphSchemasSupported = (nodes, schemas) => {
4
+ for (const node of nodes)
5
+ for (const port of node.ports) {
6
+ const schema = port.data?.schema ?? (port.data?.schemaRef ? { ref: port.data.schemaRef } : undefined);
7
+ if (schema)
8
+ assertFlowDataSchemaSupported(schema, schemas);
9
+ }
10
+ };
11
+ //# sourceMappingURL=assertFlowGraphSchemasSupported.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertFlowGraphSchemasSupported.js","sourceRoot":"","sources":["../../../../src/features/execution/domain/assertFlowGraphSchemasSupported.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAE5E,iGAAiG;AACjG,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAC7C,KAA0B,EAC1B,OAAuC,EACjC,EAAE;IACR,KAAK,MAAM,IAAI,IAAI,KAAK;QACtB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,MAAM,MAAM,GACV,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;YACzF,IAAI,MAAM;gBAAE,6BAA6B,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7D,CAAC;AACL,CAAC,CAAC","sourcesContent":["import type { DataSchemaRegistry } from '@ankhorage/contracts/data';\nimport type { FlowNode } from '@ankhorage/contracts/flow';\n\nimport { assertFlowDataSchemaSupported } from './validateFlowDataSchema.js';\n\n/*** Validate every declared graph port schema before any operation can perform a side effect. */\nexport const assertFlowGraphSchemasSupported = (\n nodes: readonly FlowNode[],\n schemas: DataSchemaRegistry | undefined,\n): void => {\n for (const node of nodes)\n for (const port of node.ports) {\n const schema =\n port.data?.schema ?? (port.data?.schemaRef ? { ref: port.data.schemaRef } : undefined);\n if (schema) assertFlowDataSchemaSupported(schema, schemas);\n }\n};\n"]}
@@ -0,0 +1,5 @@
1
+ import type { FlowDefinition } from '@ankhorage/contracts/flow';
2
+ import type { FlowCompiledGraph, FlowNodeRegistry } from '../../../types/execution.js';
3
+ /*** Compile a valid acyclic graph into deterministic execution order. */
4
+ export declare const compileFlowGraph: (definition: FlowDefinition, registry: FlowNodeRegistry) => FlowCompiledGraph;
5
+ //# sourceMappingURL=compileFlowGraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compileFlowGraph.d.ts","sourceRoot":"","sources":["../../../../src/features/execution/domain/compileFlowGraph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAsB,MAAM,2BAA2B,CAAC;AAEpF,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEvF,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,GAC3B,YAAY,cAAc,EAC1B,UAAU,gBAAgB,KACzB,iBAYF,CAAC"}
@@ -0,0 +1,76 @@
1
+ /*** Compile a valid acyclic graph into deterministic execution order. */
2
+ export const compileFlowGraph = (definition, registry) => {
3
+ const nodesById = indexNodes(definition.nodes);
4
+ const edgesBySourceNodeId = indexEdges(definition.edges, nodesById);
5
+ for (const node of definition.nodes)
6
+ assertNodeIsExecutable(node, registry);
7
+ return {
8
+ definition,
9
+ edgesBySourceNodeId,
10
+ topologicalNodeIds: orderNodes(definition.nodes.map(({ id }) => id), definition.edges),
11
+ };
12
+ };
13
+ /*** Index nodes while rejecting duplicate graph identifiers. */
14
+ const indexNodes = (nodes) => {
15
+ const entries = nodes.map((node) => [node.id, node]);
16
+ if (new Set(entries.map(([id]) => id)).size !== entries.length)
17
+ throw new Error('FLOW_GRAPH_DUPLICATE_NODE_ID');
18
+ return Object.fromEntries(entries);
19
+ };
20
+ /*** Validate and group graph edges by their producing node. */
21
+ const indexEdges = (edges, nodesById) => {
22
+ if (new Set(edges.map(({ id }) => id)).size !== edges.length)
23
+ throw new Error('FLOW_GRAPH_DUPLICATE_EDGE_ID');
24
+ for (const edge of edges) {
25
+ const source = nodesById[edge.source.nodeId];
26
+ const target = nodesById[edge.target.nodeId];
27
+ if (!source || !target)
28
+ throw new Error(`FLOW_GRAPH_UNKNOWN_EDGE_NODE:${edge.id}`);
29
+ assertPort(source, edge.source.portId, 'output', edge.id);
30
+ assertPort(target, edge.target.portId, 'input', edge.id);
31
+ }
32
+ return edges.reduce((grouped, edge) => ({
33
+ ...grouped,
34
+ [edge.source.nodeId]: [...(grouped[edge.source.nodeId] ?? []), edge],
35
+ }), {});
36
+ };
37
+ /*** Ensure a graph port exists exactly once with the expected direction. */
38
+ const assertPort = (node, portId, direction, edgeId) => {
39
+ if (node.ports.filter((port) => port.id === portId && port.direction === direction).length !== 1)
40
+ throw new Error(`FLOW_GRAPH_INVALID_EDGE_PORT:${edgeId}`);
41
+ };
42
+ /*** Reject unknown operations and code capabilities before execution can begin. */
43
+ const assertNodeIsExecutable = (node, registry) => {
44
+ const { capabilityId, providerId } = node.capability;
45
+ const operationId = `${providerId}:${capabilityId}`;
46
+ if (capabilityId === 'code')
47
+ throw new Error('FLOW_CODE_EXECUTION_DISABLED');
48
+ if (!Object.hasOwn(registry, operationId))
49
+ throw new Error(`FLOW_OPERATION_UNREGISTERED:${operationId}`);
50
+ if (new Set(node.ports.map(({ direction, id }) => `${direction}:${id}`)).size !== node.ports.length)
51
+ throw new Error(`FLOW_GRAPH_DUPLICATE_PORT_ID:${node.id}`);
52
+ };
53
+ /*** Produce stable topological order and reject cycles without an explicit bounded-loop contract. */
54
+ const orderNodes = (nodeIds, edges) => {
55
+ const incomingCounts = new Map(nodeIds.map((nodeId) => [nodeId, 0]));
56
+ for (const edge of edges)
57
+ incomingCounts.set(edge.target.nodeId, (incomingCounts.get(edge.target.nodeId) ?? 0) + 1);
58
+ const pending = nodeIds.filter((nodeId) => incomingCounts.get(nodeId) === 0);
59
+ const ordered = [];
60
+ while (pending.length > 0) {
61
+ const nodeId = pending.shift();
62
+ if (!nodeId)
63
+ continue;
64
+ ordered.push(nodeId);
65
+ for (const edge of edges.filter((candidate) => candidate.source.nodeId === nodeId)) {
66
+ const nextCount = (incomingCounts.get(edge.target.nodeId) ?? 0) - 1;
67
+ incomingCounts.set(edge.target.nodeId, nextCount);
68
+ if (nextCount === 0)
69
+ pending.push(edge.target.nodeId);
70
+ }
71
+ }
72
+ if (ordered.length !== nodeIds.length)
73
+ throw new Error('FLOW_GRAPH_CYCLE');
74
+ return ordered;
75
+ };
76
+ //# sourceMappingURL=compileFlowGraph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compileFlowGraph.js","sourceRoot":"","sources":["../../../../src/features/execution/domain/compileFlowGraph.ts"],"names":[],"mappings":"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","sourcesContent":["import type { FlowDefinition, FlowEdge, FlowNode } from '@ankhorage/contracts/flow';\n\nimport type { FlowCompiledGraph, FlowNodeRegistry } from '../../../types/execution.js';\n\n/*** Compile a valid acyclic graph into deterministic execution order. */\nexport const compileFlowGraph = (\n definition: FlowDefinition,\n registry: FlowNodeRegistry,\n): FlowCompiledGraph => {\n const nodesById = indexNodes(definition.nodes);\n const edgesBySourceNodeId = indexEdges(definition.edges, nodesById);\n for (const node of definition.nodes) assertNodeIsExecutable(node, registry);\n return {\n definition,\n edgesBySourceNodeId,\n topologicalNodeIds: orderNodes(\n definition.nodes.map(({ id }) => id),\n definition.edges,\n ),\n };\n};\n\n/*** Index nodes while rejecting duplicate graph identifiers. */\nconst indexNodes = (nodes: readonly FlowNode[]): Readonly<Record<string, FlowNode>> => {\n const entries = nodes.map((node) => [node.id, node] as const);\n if (new Set(entries.map(([id]) => id)).size !== entries.length)\n throw new Error('FLOW_GRAPH_DUPLICATE_NODE_ID');\n return Object.fromEntries(entries);\n};\n\n/*** Validate and group graph edges by their producing node. */\nconst indexEdges = (\n edges: readonly FlowEdge[],\n nodesById: Readonly<Record<string, FlowNode>>,\n): Readonly<Record<string, readonly FlowEdge[]>> => {\n if (new Set(edges.map(({ id }) => id)).size !== edges.length)\n throw new Error('FLOW_GRAPH_DUPLICATE_EDGE_ID');\n for (const edge of edges) {\n const source = nodesById[edge.source.nodeId];\n const target = nodesById[edge.target.nodeId];\n if (!source || !target) throw new Error(`FLOW_GRAPH_UNKNOWN_EDGE_NODE:${edge.id}`);\n assertPort(source, edge.source.portId, 'output', edge.id);\n assertPort(target, edge.target.portId, 'input', edge.id);\n }\n return edges.reduce<Readonly<Record<string, readonly FlowEdge[]>>>(\n (grouped, edge) => ({\n ...grouped,\n [edge.source.nodeId]: [...(grouped[edge.source.nodeId] ?? []), edge],\n }),\n {},\n );\n};\n\n/*** Ensure a graph port exists exactly once with the expected direction. */\nconst assertPort = (\n node: FlowNode,\n portId: string,\n direction: 'input' | 'output',\n edgeId: string,\n): void => {\n if (node.ports.filter((port) => port.id === portId && port.direction === direction).length !== 1)\n throw new Error(`FLOW_GRAPH_INVALID_EDGE_PORT:${edgeId}`);\n};\n\n/*** Reject unknown operations and code capabilities before execution can begin. */\nconst assertNodeIsExecutable = (node: FlowNode, registry: FlowNodeRegistry): void => {\n const { capabilityId, providerId } = node.capability;\n const operationId = `${providerId}:${capabilityId}`;\n if (capabilityId === 'code') throw new Error('FLOW_CODE_EXECUTION_DISABLED');\n if (!Object.hasOwn(registry, operationId))\n throw new Error(`FLOW_OPERATION_UNREGISTERED:${operationId}`);\n if (\n new Set(node.ports.map(({ direction, id }) => `${direction}:${id}`)).size !== node.ports.length\n )\n throw new Error(`FLOW_GRAPH_DUPLICATE_PORT_ID:${node.id}`);\n};\n\n/*** Produce stable topological order and reject cycles without an explicit bounded-loop contract. */\nconst orderNodes = (nodeIds: readonly string[], edges: readonly FlowEdge[]): readonly string[] => {\n const incomingCounts = new Map(nodeIds.map((nodeId) => [nodeId, 0]));\n for (const edge of edges)\n incomingCounts.set(edge.target.nodeId, (incomingCounts.get(edge.target.nodeId) ?? 0) + 1);\n const pending = nodeIds.filter((nodeId) => incomingCounts.get(nodeId) === 0);\n const ordered: string[] = [];\n while (pending.length > 0) {\n const nodeId = pending.shift();\n if (!nodeId) continue;\n ordered.push(nodeId);\n for (const edge of edges.filter((candidate) => candidate.source.nodeId === nodeId)) {\n const nextCount = (incomingCounts.get(edge.target.nodeId) ?? 0) - 1;\n incomingCounts.set(edge.target.nodeId, nextCount);\n if (nextCount === 0) pending.push(edge.target.nodeId);\n }\n }\n if (ordered.length !== nodeIds.length) throw new Error('FLOW_GRAPH_CYCLE');\n return ordered;\n};\n"]}
@@ -0,0 +1,4 @@
1
+ import type { FlowNodeRegistry } from '../../../types/execution.js';
2
+ /*** Create the built-in operations that have no provider or host dependency. */
3
+ export declare const createDefaultNodeRegistry: () => FlowNodeRegistry;
4
+ //# sourceMappingURL=createDefaultNodeRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDefaultNodeRegistry.d.ts","sourceRoot":"","sources":["../../../../src/features/execution/domain/createDefaultNodeRegistry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAqB,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAEvF,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,QAAO,gBAI3C,CAAC"}
@@ -0,0 +1,15 @@
1
+ /*** Create the built-in operations that have no provider or host dependency. */
2
+ export const createDefaultNodeRegistry = () => ({
3
+ 'flow:condition': { executeAsync: () => Promise.resolve({}) },
4
+ 'flow:noop': { executeAsync: () => Promise.resolve({}) },
5
+ 'flow:transform': { executeAsync: transformAsync },
6
+ });
7
+ /*** Copy configured inline or artifact values to matching output ports without evaluating code. */
8
+ const transformAsync = ({ config, node }) => {
9
+ const outputIds = new Set(node.ports.filter((port) => port.direction === 'output').map(({ id }) => id));
10
+ const output = Object.fromEntries(Object.entries(config ?? {}).filter((entry) => outputIds.has(entry[0]) && isDataRef(entry[1])));
11
+ return Promise.resolve({ output });
12
+ };
13
+ /*** Narrow a configuration value to data that may safely leave a node. */
14
+ const isDataRef = (value) => value.kind !== 'secret';
15
+ //# sourceMappingURL=createDefaultNodeRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDefaultNodeRegistry.js","sourceRoot":"","sources":["../../../../src/features/execution/domain/createDefaultNodeRegistry.ts"],"names":[],"mappings":"AAIA,gFAAgF;AAChF,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAqB,EAAE,CAAC,CAAC;IAChE,gBAAgB,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;IAC7D,WAAW,EAAE,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;IACxD,gBAAgB,EAAE,EAAE,YAAY,EAAE,cAAc,EAAE;CACnD,CAAC,CAAC;AAEH,mGAAmG;AACnG,MAAM,cAAc,GAAsC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;IAC7E,MAAM,SAAS,GAAG,IAAI,GAAG,CACvB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAC7E,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAC/B,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CACjC,CAAC,KAAK,EAAkC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1F,CACF,CAAC;IACF,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,0EAA0E;AAC1E,MAAM,SAAS,GAAG,CAAC,KAA0B,EAAwB,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC","sourcesContent":["import type { FlowDataRef, FlowNodeConfigValue } from '@ankhorage/contracts/flow';\n\nimport type { FlowNodeOperation, FlowNodeRegistry } from '../../../types/execution.js';\n\n/*** Create the built-in operations that have no provider or host dependency. */\nexport const createDefaultNodeRegistry = (): FlowNodeRegistry => ({\n 'flow:condition': { executeAsync: () => Promise.resolve({}) },\n 'flow:noop': { executeAsync: () => Promise.resolve({}) },\n 'flow:transform': { executeAsync: transformAsync },\n});\n\n/*** Copy configured inline or artifact values to matching output ports without evaluating code. */\nconst transformAsync: FlowNodeOperation['executeAsync'] = ({ config, node }) => {\n const outputIds = new Set(\n node.ports.filter((port) => port.direction === 'output').map(({ id }) => id),\n );\n const output = Object.fromEntries(\n Object.entries(config ?? {}).filter(\n (entry): entry is [string, FlowDataRef] => outputIds.has(entry[0]) && isDataRef(entry[1]),\n ),\n );\n return Promise.resolve({ output });\n};\n\n/*** Narrow a configuration value to data that may safely leave a node. */\nconst isDataRef = (value: FlowNodeConfigValue): value is FlowDataRef => value.kind !== 'secret';\n"]}
@@ -0,0 +1,6 @@
1
+ import type { DataContractValue, DataSchema, DataSchemaRegistry } from '@ankhorage/contracts/data';
2
+ /*** Validate serializable data against the supported portable schema vocabulary. */
3
+ export declare const validateFlowDataSchema: (value: DataContractValue, schema: DataSchema, schemas: DataSchemaRegistry | undefined) => boolean;
4
+ /*** Reject unsupported, unresolved, cyclic, or excessively nested portable schemas before use. */
5
+ export declare const assertFlowDataSchemaSupported: (schema: DataSchema, schemas: DataSchemaRegistry | undefined) => void;
6
+ //# sourceMappingURL=validateFlowDataSchema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateFlowDataSchema.d.ts","sourceRoot":"","sources":["../../../../src/features/execution/domain/validateFlowDataSchema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAInG,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,GACjC,OAAO,iBAAiB,EACxB,QAAQ,UAAU,EAClB,SAAS,kBAAkB,GAAG,SAAS,KACtC,OAGF,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,6BAA6B,GACxC,QAAQ,UAAU,EAClB,SAAS,kBAAkB,GAAG,SAAS,KACtC,IAAsE,CAAC"}