@blokjs/runner 0.4.0 → 0.6.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/dist/Blok.js +32 -3
- package/dist/Blok.js.map +1 -1
- package/dist/Configuration.d.ts +41 -5
- package/dist/Configuration.js +215 -92
- package/dist/Configuration.js.map +1 -1
- package/dist/ForEachNode.d.ts +59 -0
- package/dist/ForEachNode.js +522 -0
- package/dist/ForEachNode.js.map +1 -0
- package/dist/LoopMaxIterationsError.d.ts +11 -0
- package/dist/LoopMaxIterationsError.js +18 -0
- package/dist/LoopMaxIterationsError.js.map +1 -0
- package/dist/LoopNode.d.ts +36 -0
- package/dist/LoopNode.js +182 -0
- package/dist/LoopNode.js.map +1 -0
- package/dist/Runner.d.ts +11 -1
- package/dist/Runner.js +9 -2
- package/dist/Runner.js.map +1 -1
- package/dist/RunnerSteps.js +419 -112
- package/dist/RunnerSteps.js.map +1 -1
- package/dist/RuntimeAdapterNode.d.ts +2 -1
- package/dist/RuntimeAdapterNode.js +2 -2
- package/dist/RuntimeAdapterNode.js.map +1 -1
- package/dist/RuntimeRegistry.d.ts +23 -2
- package/dist/RuntimeRegistry.js +31 -2
- package/dist/RuntimeRegistry.js.map +1 -1
- package/dist/SubworkflowNode.d.ts +106 -0
- package/dist/SubworkflowNode.js +261 -3
- package/dist/SubworkflowNode.js.map +1 -1
- package/dist/SwitchNode.d.ts +37 -0
- package/dist/SwitchNode.js +153 -0
- package/dist/SwitchNode.js.map +1 -0
- package/dist/TriggerBase.d.ts +50 -0
- package/dist/TriggerBase.js +262 -4
- package/dist/TriggerBase.js.map +1 -1
- package/dist/TryCatchNode.d.ts +32 -0
- package/dist/TryCatchNode.js +207 -0
- package/dist/TryCatchNode.js.map +1 -0
- package/dist/adapters/grpc/GrpcCodec.js +2 -2
- package/dist/adapters/grpc/GrpcRuntimeAdapter.d.ts +6 -4
- package/dist/adapters/grpc/GrpcRuntimeAdapter.js +6 -4
- package/dist/adapters/grpc/GrpcRuntimeAdapter.js.map +1 -1
- package/dist/adapters/grpc/types.d.ts +7 -5
- package/dist/adapters/grpc/types.js.map +1 -1
- package/dist/adapters/transport.d.ts +12 -41
- package/dist/adapters/transport.js +21 -70
- package/dist/adapters/transport.js.map +1 -1
- package/dist/cache/NodeResultCache.js +7 -0
- package/dist/cache/NodeResultCache.js.map +1 -1
- package/dist/concurrency/NatsKvConcurrencyBackend.js +18 -5
- package/dist/concurrency/NatsKvConcurrencyBackend.js.map +1 -1
- package/dist/concurrency/RedisConcurrencyBackend.d.ts +64 -0
- package/dist/concurrency/RedisConcurrencyBackend.js +374 -0
- package/dist/concurrency/RedisConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/createConcurrencyBackend.d.ts +1 -0
- package/dist/concurrency/createConcurrencyBackend.js +5 -1
- package/dist/concurrency/createConcurrencyBackend.js.map +1 -1
- package/dist/defineNode.d.ts +8 -0
- package/dist/defineNode.js +25 -5
- package/dist/defineNode.js.map +1 -1
- package/dist/graphql/GraphQLSchemaGenerator.js +1 -1
- package/dist/graphql/GraphQLSchemaGenerator.js.map +1 -1
- package/dist/index.d.ts +10 -6
- package/dist/index.js +13 -9
- package/dist/index.js.map +1 -1
- package/dist/marketplace/RuntimeCatalog.d.ts +6 -0
- package/dist/marketplace/RuntimeCatalog.js.map +1 -1
- package/dist/marketplace/RuntimeDiscovery.d.ts +2 -2
- package/dist/marketplace/RuntimeDiscovery.js +18 -6
- package/dist/marketplace/RuntimeDiscovery.js.map +1 -1
- package/dist/monitoring/ConcurrencyMetrics.d.ts +26 -0
- package/dist/monitoring/ConcurrencyMetrics.js +36 -4
- package/dist/monitoring/ConcurrencyMetrics.js.map +1 -1
- package/dist/monitoring/ForEachWaitMetrics.d.ts +22 -0
- package/dist/monitoring/ForEachWaitMetrics.js +36 -0
- package/dist/monitoring/ForEachWaitMetrics.js.map +1 -0
- package/dist/openapi/OpenAPIGenerator.js +7 -2
- package/dist/openapi/OpenAPIGenerator.js.map +1 -1
- package/dist/runtime/PrimitiveStack.d.ts +64 -0
- package/dist/runtime/PrimitiveStack.js +92 -0
- package/dist/runtime/PrimitiveStack.js.map +1 -0
- package/dist/scheduling/DebounceBackend.d.ts +108 -0
- package/dist/scheduling/DebounceBackend.js +23 -0
- package/dist/scheduling/DebounceBackend.js.map +1 -0
- package/dist/scheduling/DebounceCoordinator.d.ts +65 -12
- package/dist/scheduling/DebounceCoordinator.js +234 -13
- package/dist/scheduling/DebounceCoordinator.js.map +1 -1
- package/dist/scheduling/DeferredRunScheduler.d.ts +28 -0
- package/dist/scheduling/DeferredRunScheduler.js +105 -3
- package/dist/scheduling/DeferredRunScheduler.js.map +1 -1
- package/dist/scheduling/NatsKvDebounceBackend.d.ts +53 -0
- package/dist/scheduling/NatsKvDebounceBackend.js +334 -0
- package/dist/scheduling/NatsKvDebounceBackend.js.map +1 -0
- package/dist/scheduling/RedisDebounceBackend.d.ts +49 -0
- package/dist/scheduling/RedisDebounceBackend.js +356 -0
- package/dist/scheduling/RedisDebounceBackend.js.map +1 -0
- package/dist/scheduling/createDebounceBackend.d.ts +25 -0
- package/dist/scheduling/createDebounceBackend.js +39 -0
- package/dist/scheduling/createDebounceBackend.js.map +1 -0
- package/dist/security/AuditLogger.js +1 -1
- package/dist/security/AuditLogger.js.map +1 -1
- package/dist/security/AuthMiddleware.d.ts +19 -20
- package/dist/security/AuthMiddleware.js +35 -20
- package/dist/security/AuthMiddleware.js.map +1 -1
- package/dist/security/OAuthProvider.js +2 -2
- package/dist/security/OAuthProvider.js.map +1 -1
- package/dist/security/SecretManager.js +14 -13
- package/dist/security/SecretManager.js.map +1 -1
- package/dist/security/index.d.ts +3 -1
- package/dist/security/index.js +3 -1
- package/dist/security/index.js.map +1 -1
- package/dist/testing/TestHarness.d.ts +27 -12
- package/dist/testing/TestHarness.js +19 -3
- package/dist/testing/TestHarness.js.map +1 -1
- package/dist/testing/WorkflowTestRunner.js +0 -7
- package/dist/testing/WorkflowTestRunner.js.map +1 -1
- package/dist/tracing/InMemoryRunStore.d.ts +14 -1
- package/dist/tracing/InMemoryRunStore.js +95 -6
- package/dist/tracing/InMemoryRunStore.js.map +1 -1
- package/dist/tracing/PostgresRunStore.d.ts +28 -2
- package/dist/tracing/PostgresRunStore.js +276 -3
- package/dist/tracing/PostgresRunStore.js.map +1 -1
- package/dist/tracing/RoutingDiagnostics.d.ts +55 -0
- package/dist/tracing/RoutingDiagnostics.js +50 -0
- package/dist/tracing/RoutingDiagnostics.js.map +1 -0
- package/dist/tracing/RunStore.d.ts +82 -1
- package/dist/tracing/RunTracker.d.ts +7 -1
- package/dist/tracing/RunTracker.js +23 -0
- package/dist/tracing/RunTracker.js.map +1 -1
- package/dist/tracing/SqliteRunStore.d.ts +57 -2
- package/dist/tracing/SqliteRunStore.js +408 -48
- package/dist/tracing/SqliteRunStore.js.map +1 -1
- package/dist/tracing/TraceRouter.js +380 -18
- package/dist/tracing/TraceRouter.js.map +1 -1
- package/dist/tracing/createStore.js +14 -3
- package/dist/tracing/createStore.js.map +1 -1
- package/dist/tracing/metadataFilter.d.ts +63 -0
- package/dist/tracing/metadataFilter.js +224 -0
- package/dist/tracing/metadataFilter.js.map +1 -0
- package/dist/tracing/types.d.ts +331 -7
- package/dist/utils/envAllowlist.d.ts +35 -0
- package/dist/utils/envAllowlist.js +113 -0
- package/dist/utils/envAllowlist.js.map +1 -0
- package/dist/version/RuntimeVersionValidator.d.ts +38 -0
- package/dist/version/RuntimeVersionValidator.js +121 -0
- package/dist/version/RuntimeVersionValidator.js.map +1 -0
- package/dist/visualization/WorkflowVisualizer.js +4 -4
- package/dist/visualization/WorkflowVisualizer.js.map +1 -1
- package/dist/workflow/PersistenceHelper.d.ts +18 -10
- package/dist/workflow/PersistenceHelper.js +35 -9
- package/dist/workflow/PersistenceHelper.js.map +1 -1
- package/dist/workflow/WorkflowNormalizer.d.ts +19 -1
- package/dist/workflow/WorkflowNormalizer.js +469 -19
- package/dist/workflow/WorkflowNormalizer.js.map +1 -1
- package/dist/workflow/WorkflowRegistry.d.ts +122 -0
- package/dist/workflow/WorkflowRegistry.js +121 -0
- package/dist/workflow/WorkflowRegistry.js.map +1 -1
- package/dist/workflow/sampleBody.d.ts +54 -0
- package/dist/workflow/sampleBody.js +320 -0
- package/dist/workflow/sampleBody.js.map +1 -0
- package/package.json +3 -8
- package/dist/adapters/HttpRuntimeAdapter.d.ts +0 -79
- package/dist/adapters/HttpRuntimeAdapter.js +0 -233
- package/dist/adapters/HttpRuntimeAdapter.js.map +0 -1
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sample-body inference for the Studio empty-state curl snippet.
|
|
3
|
+
*
|
|
4
|
+
* Generates a JSON payload shape that a workflow's HTTP trigger
|
|
5
|
+
* would accept, so the "no runs yet" curl example on the workflow
|
|
6
|
+
* detail page can show an example body that actually exercises the
|
|
7
|
+
* workflow — instead of the previous `-d '{}'` which immediately
|
|
8
|
+
* crashed every workflow that read from `ctx.request.body`.
|
|
9
|
+
*
|
|
10
|
+
* Two layers (B + A in the design discussion):
|
|
11
|
+
*
|
|
12
|
+
* B. Static analysis. Walk every step's inputs + control-flow
|
|
13
|
+
* expressions, collect every `ctx.request.body.<path>` and
|
|
14
|
+
* `$.req.body.<path>` reference, and build a nested object
|
|
15
|
+
* mirroring those paths. Array shapes are inferred from
|
|
16
|
+
* `forEach.in` references — if a path feeds a forEach, it's
|
|
17
|
+
* an array, and references to `ctx.state.<asVar>.<sub>` inside
|
|
18
|
+
* the body translate back into element-shape fields.
|
|
19
|
+
*
|
|
20
|
+
* A. Author override. If the workflow declares
|
|
21
|
+
* `trigger.http.examples.body: {...}`, that value wins
|
|
22
|
+
* verbatim and the static inference is skipped.
|
|
23
|
+
*
|
|
24
|
+
* Inference is best-effort and intentionally permissive — the
|
|
25
|
+
* placeholder values are "string" everywhere, since the goal is to
|
|
26
|
+
* produce a payload that satisfies the workflow's *shape*, not its
|
|
27
|
+
* semantics. A workflow author who cares about value semantics
|
|
28
|
+
* declares an explicit example.
|
|
29
|
+
*/
|
|
30
|
+
function isPlainObject(value) {
|
|
31
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Read author-declared examples from the workflow's trigger config.
|
|
35
|
+
* Returns the raw body value (whatever the author wrote) when
|
|
36
|
+
* `trigger.http.examples.body` is set.
|
|
37
|
+
*/
|
|
38
|
+
function readAuthorOverride(workflow) {
|
|
39
|
+
if (!isPlainObject(workflow))
|
|
40
|
+
return undefined;
|
|
41
|
+
const trigger = workflow.trigger;
|
|
42
|
+
if (!isPlainObject(trigger))
|
|
43
|
+
return undefined;
|
|
44
|
+
const http = trigger.http;
|
|
45
|
+
if (!isPlainObject(http))
|
|
46
|
+
return undefined;
|
|
47
|
+
const examples = http.examples;
|
|
48
|
+
if (!isPlainObject(examples))
|
|
49
|
+
return undefined;
|
|
50
|
+
return examples.body;
|
|
51
|
+
}
|
|
52
|
+
const BODY_REF_RE = /(?:ctx\.req(?:uest)?\.body|\$\.req\.body)\.([A-Za-z_][\w.]*)/g;
|
|
53
|
+
const STATE_REF_RE = /(?:ctx\.state\.|\$\.state\.)([A-Za-z_]\w*)(?:\.([\w.]+))?/g;
|
|
54
|
+
/**
|
|
55
|
+
* Extract dotted paths from a single string value. Handles both the
|
|
56
|
+
* `js/ctx.request.body.X.Y` form (used by JS expressions) and the
|
|
57
|
+
* `$.req.body.X.Y` form (the v2 DSL). Same regex matches both.
|
|
58
|
+
*
|
|
59
|
+
* Also resolves `ctx.state.<asVar>.X.Y` references against the
|
|
60
|
+
* current scope's `as` bindings — these come from inside a `forEach`
|
|
61
|
+
* or `loop` body and mean "field X.Y on the source array's elements."
|
|
62
|
+
*/
|
|
63
|
+
function extractRefs(value, scope) {
|
|
64
|
+
const out = [];
|
|
65
|
+
for (const m of value.matchAll(BODY_REF_RE)) {
|
|
66
|
+
const raw = m[1];
|
|
67
|
+
if (!raw)
|
|
68
|
+
continue;
|
|
69
|
+
out.push(raw.split(".").map((key) => ({ key, array: false })));
|
|
70
|
+
}
|
|
71
|
+
for (const m of value.matchAll(STATE_REF_RE)) {
|
|
72
|
+
const asVar = m[1];
|
|
73
|
+
const subPath = m[2];
|
|
74
|
+
if (!asVar)
|
|
75
|
+
continue;
|
|
76
|
+
const sourcePath = scope.get(asVar);
|
|
77
|
+
if (!sourcePath)
|
|
78
|
+
continue;
|
|
79
|
+
const tail = subPath ? subPath.split(".").map((key) => ({ key, array: false })) : [];
|
|
80
|
+
out.push([...sourcePath, ...tail]);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Recursively scan ANY value for body references. Strings get the
|
|
86
|
+
* regex treatment. Objects and arrays are walked. Anything else is
|
|
87
|
+
* a no-op.
|
|
88
|
+
*
|
|
89
|
+
* When `markArray` is true, every top-level path collected from this
|
|
90
|
+
* value is flagged as referring to an array (used for `forEach.in`).
|
|
91
|
+
*/
|
|
92
|
+
function scanValueForRefs(value, scope, out, markArray) {
|
|
93
|
+
if (typeof value === "string") {
|
|
94
|
+
const refs = extractRefs(value, scope);
|
|
95
|
+
for (const ref of refs) {
|
|
96
|
+
if (markArray && ref.length > 0) {
|
|
97
|
+
// Clone + mark the LAST segment as the array. e.g. if `in`
|
|
98
|
+
// was `ctx.request.body.subscribers`, we want the
|
|
99
|
+
// `subscribers` segment marked as array — its children
|
|
100
|
+
// (added later from the forEach body) descend into the
|
|
101
|
+
// element shape.
|
|
102
|
+
const tail = ref[ref.length - 1];
|
|
103
|
+
if (tail) {
|
|
104
|
+
const cloned = ref.map((s, i) => (i === ref.length - 1 ? { key: s.key, array: true } : s));
|
|
105
|
+
out.push(cloned);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
out.push(ref);
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (Array.isArray(value)) {
|
|
114
|
+
for (const v of value)
|
|
115
|
+
scanValueForRefs(v, scope, out, markArray);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (isPlainObject(value)) {
|
|
119
|
+
for (const v of Object.values(value))
|
|
120
|
+
scanValueForRefs(v, scope, out, markArray);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Look at a `forEach.in` value and return the body-path it references,
|
|
125
|
+
* so we can register that path as the source array for the `as`
|
|
126
|
+
* variable. Returns undefined if the expression doesn't resolve to a
|
|
127
|
+
* single body path (e.g. an inline literal array, a state-derived
|
|
128
|
+
* value, or a complex expression we can't statically resolve).
|
|
129
|
+
*/
|
|
130
|
+
function extractSinglePath(value, scope) {
|
|
131
|
+
if (typeof value !== "string")
|
|
132
|
+
return undefined;
|
|
133
|
+
const refs = extractRefs(value, scope);
|
|
134
|
+
if (refs.length !== 1)
|
|
135
|
+
return undefined;
|
|
136
|
+
return refs[0];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Walk a list of v2 steps + accumulate every body-path reference.
|
|
140
|
+
* Handles every v2 control-flow kind by recursing into the relevant
|
|
141
|
+
* sub-pipelines with an updated scope.
|
|
142
|
+
*/
|
|
143
|
+
function collectPaths(steps, scope, out) {
|
|
144
|
+
if (!Array.isArray(steps))
|
|
145
|
+
return;
|
|
146
|
+
for (const raw of steps) {
|
|
147
|
+
if (!isPlainObject(raw))
|
|
148
|
+
continue;
|
|
149
|
+
// Regular step inputs.
|
|
150
|
+
if (raw.inputs !== undefined) {
|
|
151
|
+
scanValueForRefs(raw.inputs, scope, out, false);
|
|
152
|
+
}
|
|
153
|
+
// Branch (condition + then/else).
|
|
154
|
+
if (isPlainObject(raw.branch)) {
|
|
155
|
+
const b = raw.branch;
|
|
156
|
+
if (typeof b.when === "string")
|
|
157
|
+
scanValueForRefs(b.when, scope, out, false);
|
|
158
|
+
collectPaths(b.then, scope, out);
|
|
159
|
+
collectPaths(b.else, scope, out);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// ForEach (in + as + do).
|
|
163
|
+
if (isPlainObject(raw.forEach)) {
|
|
164
|
+
const f = raw.forEach;
|
|
165
|
+
// The `in` expression — paths there are arrays.
|
|
166
|
+
scanValueForRefs(f.in, scope, out, true);
|
|
167
|
+
// Compute the source path for the `as` element scope. When the
|
|
168
|
+
// `in` expression resolves to a single body path, future
|
|
169
|
+
// `ctx.state.<asVar>.X` references inside the body get
|
|
170
|
+
// rewritten back into `<sourceArrayPath>[].X`.
|
|
171
|
+
const sourcePath = extractSinglePath(f.in, scope);
|
|
172
|
+
const innerScope = new Map(scope);
|
|
173
|
+
if (typeof f.as === "string" && sourcePath) {
|
|
174
|
+
// Mark the source path's tail as an array so descendants
|
|
175
|
+
// land inside the element shape.
|
|
176
|
+
const arrayPath = sourcePath.map((s, i) => ({
|
|
177
|
+
key: s.key,
|
|
178
|
+
array: i === sourcePath.length - 1 ? true : s.array,
|
|
179
|
+
}));
|
|
180
|
+
innerScope.set(f.as, arrayPath);
|
|
181
|
+
}
|
|
182
|
+
collectPaths(f.do, innerScope, out);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// Loop (while + do).
|
|
186
|
+
if (isPlainObject(raw.loop)) {
|
|
187
|
+
const l = raw.loop;
|
|
188
|
+
if (typeof l.while === "string")
|
|
189
|
+
scanValueForRefs(l.while, scope, out, false);
|
|
190
|
+
collectPaths(l.do, scope, out);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
// Switch (on + cases + default).
|
|
194
|
+
if (isPlainObject(raw.switch)) {
|
|
195
|
+
const s = raw.switch;
|
|
196
|
+
scanValueForRefs(s.on, scope, out, false);
|
|
197
|
+
if (Array.isArray(s.cases)) {
|
|
198
|
+
for (const c of s.cases) {
|
|
199
|
+
if (!isPlainObject(c))
|
|
200
|
+
continue;
|
|
201
|
+
scanValueForRefs(c.when, scope, out, false);
|
|
202
|
+
collectPaths(c.do, scope, out);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
collectPaths(s.default, scope, out);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
// TryCatch (try + catch + finally). Last kind in the loop body,
|
|
209
|
+
// so no `continue` needed.
|
|
210
|
+
if (isPlainObject(raw.tryCatch)) {
|
|
211
|
+
const tc = raw.tryCatch;
|
|
212
|
+
collectPaths(tc.try, scope, out);
|
|
213
|
+
collectPaths(tc.catch, scope, out);
|
|
214
|
+
collectPaths(tc.finally, scope, out);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Build a nested JSON value from the collected path segments. Each
|
|
220
|
+
* path adds one branch to the tree. Array segments become `[{...}]`
|
|
221
|
+
* containers; scalar leaves become the literal string `"string"`.
|
|
222
|
+
*
|
|
223
|
+
* Merging is conservative — a path that ends at a leaf where an
|
|
224
|
+
* object already exists doesn't overwrite the object (a leaf is
|
|
225
|
+
* "we know this exists" not "this is a primitive"); a path that
|
|
226
|
+
* descends through a key currently set to `"string"` upgrades it
|
|
227
|
+
* to an object.
|
|
228
|
+
*/
|
|
229
|
+
function buildTreeFromPaths(paths) {
|
|
230
|
+
const root = {};
|
|
231
|
+
for (const path of paths) {
|
|
232
|
+
if (path.length === 0)
|
|
233
|
+
continue;
|
|
234
|
+
setPath(root, path);
|
|
235
|
+
}
|
|
236
|
+
return root;
|
|
237
|
+
}
|
|
238
|
+
function setPath(root, path) {
|
|
239
|
+
// Cursor that "node" walks. At each step it either steps into an
|
|
240
|
+
// object's key or into an array element.
|
|
241
|
+
let node = root;
|
|
242
|
+
for (let i = 0; i < path.length; i++) {
|
|
243
|
+
const seg = path[i];
|
|
244
|
+
if (!seg)
|
|
245
|
+
continue;
|
|
246
|
+
const isLast = i === path.length - 1;
|
|
247
|
+
const existing = node[seg.key];
|
|
248
|
+
if (seg.array) {
|
|
249
|
+
// The value at this key must be an array; descend into its
|
|
250
|
+
// (single) element so further segments add to the element's
|
|
251
|
+
// shape.
|
|
252
|
+
let arr;
|
|
253
|
+
if (Array.isArray(existing)) {
|
|
254
|
+
arr = existing;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
arr = [];
|
|
258
|
+
node[seg.key] = arr;
|
|
259
|
+
}
|
|
260
|
+
if (arr.length === 0)
|
|
261
|
+
arr.push({});
|
|
262
|
+
let elem = arr[0];
|
|
263
|
+
if (!isPlainObject(elem)) {
|
|
264
|
+
elem = {};
|
|
265
|
+
arr[0] = elem;
|
|
266
|
+
}
|
|
267
|
+
if (isLast) {
|
|
268
|
+
// `subscribers` referenced as the WHOLE array — no further
|
|
269
|
+
// segment to add. Leave the element as `{}`.
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
node = elem;
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
if (isLast) {
|
|
276
|
+
if (existing === undefined) {
|
|
277
|
+
node[seg.key] = "string";
|
|
278
|
+
}
|
|
279
|
+
// Already an object/array → leave it; "string" → leave it.
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
// Non-terminal scalar key — descend into the (possibly new) object.
|
|
283
|
+
if (existing === undefined || existing === "string") {
|
|
284
|
+
node[seg.key] = {};
|
|
285
|
+
}
|
|
286
|
+
const next = node[seg.key];
|
|
287
|
+
if (!isPlainObject(next)) {
|
|
288
|
+
// Existing value is an array or other shape we can't descend
|
|
289
|
+
// into via a scalar key — bail out for this path.
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
node = next;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Infer a sample HTTP body for a workflow, or return the author's
|
|
297
|
+
* declared example. Returns `null` only when the workflow value is
|
|
298
|
+
* not a recognisable object — every other shape gets at least an
|
|
299
|
+
* `empty` result with `body: {}`.
|
|
300
|
+
*
|
|
301
|
+
* @param workflow The raw workflow JSON (the same value the
|
|
302
|
+
* `WorkflowRegistry` stores). Accepts `unknown` because the API
|
|
303
|
+
* surface that calls this — `TraceRouter` — keeps `definition`
|
|
304
|
+
* typed loosely.
|
|
305
|
+
*/
|
|
306
|
+
export function inferSampleBody(workflow) {
|
|
307
|
+
if (!isPlainObject(workflow))
|
|
308
|
+
return null;
|
|
309
|
+
const override = readAuthorOverride(workflow);
|
|
310
|
+
if (override !== undefined) {
|
|
311
|
+
return { body: override, source: "author" };
|
|
312
|
+
}
|
|
313
|
+
const paths = [];
|
|
314
|
+
collectPaths(workflow.steps, new Map(), paths);
|
|
315
|
+
if (paths.length === 0) {
|
|
316
|
+
return { body: {}, source: "empty" };
|
|
317
|
+
}
|
|
318
|
+
return { body: buildTreeFromPaths(paths), source: "inferred" };
|
|
319
|
+
}
|
|
320
|
+
//# sourceMappingURL=sampleBody.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampleBody.js","sourceRoot":"","sources":["../../src/workflow/sampleBody.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blokjs/runner",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0"
|
|
@@ -18,11 +18,6 @@
|
|
|
18
18
|
"sync:proto:fromroot": "mkdir -p src/adapters/grpc/proto/blok/runtime/v1 && cp ../../proto/blok/runtime/v1/runtime.proto src/adapters/grpc/proto/blok/runtime/v1/runtime.proto",
|
|
19
19
|
"test:dev": "vitest",
|
|
20
20
|
"test": "vitest run",
|
|
21
|
-
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
22
|
-
"test:integration:dev": "vitest --config vitest.integration.config.ts",
|
|
23
|
-
"test:integration:coverage": "vitest run --config vitest.integration.config.ts --coverage",
|
|
24
|
-
"test:parity": "vitest run --config vitest.integration.config.ts __tests__/integration/parity",
|
|
25
|
-
"test:all": "vitest run && vitest run --config vitest.integration.config.ts",
|
|
26
21
|
"typecheck": "tsc --noEmit --incremental"
|
|
27
22
|
},
|
|
28
23
|
"devDependencies": {
|
|
@@ -38,8 +33,8 @@
|
|
|
38
33
|
"vitest": "^4.0.18"
|
|
39
34
|
},
|
|
40
35
|
"dependencies": {
|
|
41
|
-
"@blokjs/helper": "
|
|
42
|
-
"@blokjs/shared": "
|
|
36
|
+
"@blokjs/helper": "workspace:*",
|
|
37
|
+
"@blokjs/shared": "workspace:*",
|
|
43
38
|
"@grpc/grpc-js": "^1.12.0",
|
|
44
39
|
"@grpc/proto-loader": "^0.7.13",
|
|
45
40
|
"@opentelemetry/api": "^1.9.0",
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type { Context } from "@blokjs/shared";
|
|
2
|
-
import type RunnerNode from "../RunnerNode";
|
|
3
|
-
import type { ExecutionResult, RuntimeAdapter, RuntimeKind } from "./RuntimeAdapter";
|
|
4
|
-
/**
|
|
5
|
-
* Configuration options for HttpRuntimeAdapter
|
|
6
|
-
*/
|
|
7
|
-
export interface HttpRuntimeAdapterOptions {
|
|
8
|
-
/** Request timeout in milliseconds (default: 30000) */
|
|
9
|
-
timeoutMs?: number;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* HttpRuntimeAdapter executes nodes in pre-existing SDK containers via HTTP.
|
|
13
|
-
*
|
|
14
|
-
* Unlike DockerRuntimeAdapter, this adapter does NOT manage container lifecycle.
|
|
15
|
-
* It connects to already-running containers (managed externally by Docker Compose,
|
|
16
|
-
* Kubernetes, or any other orchestrator).
|
|
17
|
-
*
|
|
18
|
-
* All SDK containers implement the same HTTP contract:
|
|
19
|
-
* - POST /execute — Execute a node with the provided context
|
|
20
|
-
* - GET /health — Return container health status
|
|
21
|
-
*
|
|
22
|
-
* Environment variables per language:
|
|
23
|
-
* RUNTIME_GO_HOST / RUNTIME_GO_PORT
|
|
24
|
-
* RUNTIME_RUST_HOST / RUNTIME_RUST_PORT
|
|
25
|
-
* RUNTIME_JAVA_HOST / RUNTIME_JAVA_PORT
|
|
26
|
-
* RUNTIME_CSHARP_HOST / RUNTIME_CSHARP_PORT
|
|
27
|
-
* RUNTIME_PHP_HOST / RUNTIME_PHP_PORT
|
|
28
|
-
* RUNTIME_RUBY_HOST / RUNTIME_RUBY_PORT
|
|
29
|
-
* RUNTIME_PYTHON3_HOST / RUNTIME_PYTHON3_PORT
|
|
30
|
-
*/
|
|
31
|
-
export declare class HttpRuntimeAdapter implements RuntimeAdapter {
|
|
32
|
-
readonly kind: RuntimeKind;
|
|
33
|
-
readonly transport: "http";
|
|
34
|
-
private baseUrl;
|
|
35
|
-
private timeoutMs;
|
|
36
|
-
constructor(kind: RuntimeKind, host: string, port: number, options?: HttpRuntimeAdapterOptions);
|
|
37
|
-
/**
|
|
38
|
-
* Execute a node in the SDK container via HTTP POST /execute
|
|
39
|
-
*/
|
|
40
|
-
execute(node: RunnerNode, ctx: Context): Promise<ExecutionResult>;
|
|
41
|
-
/**
|
|
42
|
-
* Create the ExecutionRequest payload for the SDK container.
|
|
43
|
-
*
|
|
44
|
-
* Sends two shapes in the same envelope so the migration to the new
|
|
45
|
-
* canonical wire format is backward-compatible:
|
|
46
|
-
*
|
|
47
|
-
* 1. **Legacy keys** — `node.config` + `context.{request,response,vars,env}`.
|
|
48
|
-
* Existing SDK HTTP servers (Rust, Python, Go HTTP, others) read
|
|
49
|
-
* these keys today and keep working unchanged.
|
|
50
|
-
*
|
|
51
|
-
* 2. **New canonical keys** — `step` / `inputs` / `trigger` / `state` /
|
|
52
|
-
* `workflow`. Same field names + structure as the gRPC proto so SDK
|
|
53
|
-
* authors who adopt the new shape get a uniform mental model across
|
|
54
|
-
* transports. The "inputs unwrapped at the wire layer" property
|
|
55
|
-
* (FIXES.md #3) holds for both shapes.
|
|
56
|
-
*
|
|
57
|
-
* Data flow priority for the legacy `request.body`:
|
|
58
|
-
* 1. If the node has resolved inputs (from the blueprint Mapper), use
|
|
59
|
-
* those as `request.body` so workflows that define explicit inputs
|
|
60
|
-
* like `"chain": "js/ctx.response.data.chain"` keep working.
|
|
61
|
-
* 2. Otherwise, fall back to `ctx.response.data` (previous step output)
|
|
62
|
-
* enabling zero-config chaining for SDK nodes that read body fields.
|
|
63
|
-
*
|
|
64
|
-
* The new `trigger.body` always reflects the actual trigger body
|
|
65
|
-
* (`ctx.request?.body`) — separated from inputs at the wire layer.
|
|
66
|
-
*
|
|
67
|
-
* Deprecation timeline: legacy keys will be removed in the next minor
|
|
68
|
-
* version once SDK HTTP servers have all adopted the new shape.
|
|
69
|
-
*/
|
|
70
|
-
private createExecutionRequest;
|
|
71
|
-
/**
|
|
72
|
-
* Check if the SDK container is healthy via GET /health
|
|
73
|
-
*/
|
|
74
|
-
checkHealth(): Promise<boolean>;
|
|
75
|
-
/**
|
|
76
|
-
* Get the base URL for this adapter
|
|
77
|
-
*/
|
|
78
|
-
getBaseUrl(): string;
|
|
79
|
-
}
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HttpRuntimeAdapter executes nodes in pre-existing SDK containers via HTTP.
|
|
3
|
-
*
|
|
4
|
-
* Unlike DockerRuntimeAdapter, this adapter does NOT manage container lifecycle.
|
|
5
|
-
* It connects to already-running containers (managed externally by Docker Compose,
|
|
6
|
-
* Kubernetes, or any other orchestrator).
|
|
7
|
-
*
|
|
8
|
-
* All SDK containers implement the same HTTP contract:
|
|
9
|
-
* - POST /execute — Execute a node with the provided context
|
|
10
|
-
* - GET /health — Return container health status
|
|
11
|
-
*
|
|
12
|
-
* Environment variables per language:
|
|
13
|
-
* RUNTIME_GO_HOST / RUNTIME_GO_PORT
|
|
14
|
-
* RUNTIME_RUST_HOST / RUNTIME_RUST_PORT
|
|
15
|
-
* RUNTIME_JAVA_HOST / RUNTIME_JAVA_PORT
|
|
16
|
-
* RUNTIME_CSHARP_HOST / RUNTIME_CSHARP_PORT
|
|
17
|
-
* RUNTIME_PHP_HOST / RUNTIME_PHP_PORT
|
|
18
|
-
* RUNTIME_RUBY_HOST / RUNTIME_RUBY_PORT
|
|
19
|
-
* RUNTIME_PYTHON3_HOST / RUNTIME_PYTHON3_PORT
|
|
20
|
-
*/
|
|
21
|
-
export class HttpRuntimeAdapter {
|
|
22
|
-
kind;
|
|
23
|
-
transport = "http";
|
|
24
|
-
baseUrl;
|
|
25
|
-
timeoutMs;
|
|
26
|
-
constructor(kind, host, port, options) {
|
|
27
|
-
this.kind = kind;
|
|
28
|
-
this.baseUrl = `http://${host}:${port}`;
|
|
29
|
-
this.timeoutMs = options?.timeoutMs ?? 30000;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Execute a node in the SDK container via HTTP POST /execute
|
|
33
|
-
*/
|
|
34
|
-
async execute(node, ctx) {
|
|
35
|
-
const startTime = performance.now();
|
|
36
|
-
try {
|
|
37
|
-
const request = this.createExecutionRequest(node, ctx);
|
|
38
|
-
const response = await fetch(`${this.baseUrl}/execute`, {
|
|
39
|
-
method: "POST",
|
|
40
|
-
headers: { "Content-Type": "application/json" },
|
|
41
|
-
body: JSON.stringify(request),
|
|
42
|
-
signal: AbortSignal.timeout(this.timeoutMs),
|
|
43
|
-
});
|
|
44
|
-
if (!response.ok) {
|
|
45
|
-
// Read the error response body — SDK containers return structured error details
|
|
46
|
-
// that would otherwise be lost (e.g. validation messages, stack traces)
|
|
47
|
-
let errorDetail = "";
|
|
48
|
-
try {
|
|
49
|
-
const errorBody = (await response.json());
|
|
50
|
-
const errors = errorBody?.errors;
|
|
51
|
-
errorDetail = errors?.message || JSON.stringify(errors) || "";
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
try {
|
|
55
|
-
errorDetail = await response.text();
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
/* body not readable */
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
throw new Error(`HTTP runtime '${this.kind}' at ${this.baseUrl} returned HTTP ${response.status}: ${response.statusText}${errorDetail ? ` — ${errorDetail}` : ""}`);
|
|
62
|
-
}
|
|
63
|
-
const result = (await response.json());
|
|
64
|
-
const duration_ms = performance.now() - startTime;
|
|
65
|
-
return {
|
|
66
|
-
success: result.success ?? true,
|
|
67
|
-
data: result.data,
|
|
68
|
-
errors: result.errors || null,
|
|
69
|
-
logs: result.logs,
|
|
70
|
-
metrics: {
|
|
71
|
-
duration_ms,
|
|
72
|
-
...(result.metrics || {}),
|
|
73
|
-
},
|
|
74
|
-
vars: result.vars,
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
const duration_ms = performance.now() - startTime;
|
|
79
|
-
return {
|
|
80
|
-
success: false,
|
|
81
|
-
data: null,
|
|
82
|
-
errors: {
|
|
83
|
-
message: error.message,
|
|
84
|
-
stack: error.stack,
|
|
85
|
-
name: error.name,
|
|
86
|
-
},
|
|
87
|
-
metrics: {
|
|
88
|
-
duration_ms,
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Create the ExecutionRequest payload for the SDK container.
|
|
95
|
-
*
|
|
96
|
-
* Sends two shapes in the same envelope so the migration to the new
|
|
97
|
-
* canonical wire format is backward-compatible:
|
|
98
|
-
*
|
|
99
|
-
* 1. **Legacy keys** — `node.config` + `context.{request,response,vars,env}`.
|
|
100
|
-
* Existing SDK HTTP servers (Rust, Python, Go HTTP, others) read
|
|
101
|
-
* these keys today and keep working unchanged.
|
|
102
|
-
*
|
|
103
|
-
* 2. **New canonical keys** — `step` / `inputs` / `trigger` / `state` /
|
|
104
|
-
* `workflow`. Same field names + structure as the gRPC proto so SDK
|
|
105
|
-
* authors who adopt the new shape get a uniform mental model across
|
|
106
|
-
* transports. The "inputs unwrapped at the wire layer" property
|
|
107
|
-
* (FIXES.md #3) holds for both shapes.
|
|
108
|
-
*
|
|
109
|
-
* Data flow priority for the legacy `request.body`:
|
|
110
|
-
* 1. If the node has resolved inputs (from the blueprint Mapper), use
|
|
111
|
-
* those as `request.body` so workflows that define explicit inputs
|
|
112
|
-
* like `"chain": "js/ctx.response.data.chain"` keep working.
|
|
113
|
-
* 2. Otherwise, fall back to `ctx.response.data` (previous step output)
|
|
114
|
-
* enabling zero-config chaining for SDK nodes that read body fields.
|
|
115
|
-
*
|
|
116
|
-
* The new `trigger.body` always reflects the actual trigger body
|
|
117
|
-
* (`ctx.request?.body`) — separated from inputs at the wire layer.
|
|
118
|
-
*
|
|
119
|
-
* Deprecation timeline: legacy keys will be removed in the next minor
|
|
120
|
-
* version once SDK HTTP servers have all adopted the new shape.
|
|
121
|
-
*/
|
|
122
|
-
createExecutionRequest(node, ctx) {
|
|
123
|
-
const nodeConfig = ctx.config
|
|
124
|
-
? ctx.config[node.name]
|
|
125
|
-
: {};
|
|
126
|
-
// Check if the Mapper has resolved inputs for this node
|
|
127
|
-
// The Mapper runs BEFORE run() in NodeBase.process(), so by now
|
|
128
|
-
// config[node.name].inputs has resolved values (not raw js/ expressions)
|
|
129
|
-
const resolvedInputs = nodeConfig?.inputs;
|
|
130
|
-
// Use resolved inputs if available, otherwise fall back to previous step data
|
|
131
|
-
const legacyRequestBody = resolvedInputs || (ctx.response?.data ?? {});
|
|
132
|
-
// Unwrap the {inputs: {...}} wrapper that comes from @blokjs/helper StepNode.
|
|
133
|
-
// SDK nodes expect config to contain the inputs directly (e.g. config.operation),
|
|
134
|
-
// not wrapped as config.inputs.operation.
|
|
135
|
-
const unwrappedConfig = resolvedInputs || nodeConfig?.inputs || nodeConfig || {};
|
|
136
|
-
const stepInfo = ctx._stepInfo;
|
|
137
|
-
const headers = ctx.request?.headers ?? {};
|
|
138
|
-
const params = ctx.request?.params ?? {};
|
|
139
|
-
const query = ctx.request?.query ?? {};
|
|
140
|
-
const cookies = ctx.request?.cookies ?? {};
|
|
141
|
-
const method = ctx.request?.method ?? "";
|
|
142
|
-
const url = ctx.request?.url ?? "";
|
|
143
|
-
const baseUrl = ctx.request?.baseUrl ?? "";
|
|
144
|
-
return {
|
|
145
|
-
// ===== Legacy keys (kept for one minor for backward compat) =====
|
|
146
|
-
node: {
|
|
147
|
-
name: node.node,
|
|
148
|
-
type: node.type,
|
|
149
|
-
version: "",
|
|
150
|
-
config: unwrappedConfig,
|
|
151
|
-
},
|
|
152
|
-
context: {
|
|
153
|
-
id: ctx.id,
|
|
154
|
-
workflow_name: ctx.workflow_name,
|
|
155
|
-
workflow_path: ctx.workflow_path,
|
|
156
|
-
request: {
|
|
157
|
-
body: legacyRequestBody,
|
|
158
|
-
headers,
|
|
159
|
-
params,
|
|
160
|
-
query,
|
|
161
|
-
method,
|
|
162
|
-
url,
|
|
163
|
-
cookies,
|
|
164
|
-
baseUrl,
|
|
165
|
-
},
|
|
166
|
-
response: {
|
|
167
|
-
data: null,
|
|
168
|
-
contentType: "application/json",
|
|
169
|
-
success: true,
|
|
170
|
-
error: null,
|
|
171
|
-
},
|
|
172
|
-
vars: ctx.vars ?? {},
|
|
173
|
-
env: ctx.env ?? {},
|
|
174
|
-
},
|
|
175
|
-
// ===== New canonical keys (mirror the gRPC proto v1 schema) =====
|
|
176
|
-
step: {
|
|
177
|
-
name: stepInfo?.name ?? node.name,
|
|
178
|
-
index: stepInfo?.index ?? 0,
|
|
179
|
-
total: stepInfo?.total ?? 1,
|
|
180
|
-
depth: stepInfo?.depth ?? 0,
|
|
181
|
-
},
|
|
182
|
-
inputs: unwrappedConfig,
|
|
183
|
-
trigger: {
|
|
184
|
-
body: ctx.request?.body ?? null,
|
|
185
|
-
headers,
|
|
186
|
-
params,
|
|
187
|
-
query,
|
|
188
|
-
cookies,
|
|
189
|
-
method,
|
|
190
|
-
url,
|
|
191
|
-
baseUrl,
|
|
192
|
-
triggerKind: "",
|
|
193
|
-
},
|
|
194
|
-
state: {
|
|
195
|
-
previousOutput: ctx.response?.data ?? null,
|
|
196
|
-
vars: ctx.vars ?? {},
|
|
197
|
-
env: ctx.env ?? {},
|
|
198
|
-
},
|
|
199
|
-
workflow: {
|
|
200
|
-
runId: ctx.id,
|
|
201
|
-
name: ctx.workflow_name ?? "",
|
|
202
|
-
path: ctx.workflow_path ?? "",
|
|
203
|
-
version: "",
|
|
204
|
-
},
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
/**
|
|
208
|
-
* Check if the SDK container is healthy via GET /health
|
|
209
|
-
*/
|
|
210
|
-
async checkHealth() {
|
|
211
|
-
try {
|
|
212
|
-
const response = await fetch(`${this.baseUrl}/health`, {
|
|
213
|
-
method: "GET",
|
|
214
|
-
signal: AbortSignal.timeout(5000),
|
|
215
|
-
});
|
|
216
|
-
if (response.ok) {
|
|
217
|
-
const data = (await response.json());
|
|
218
|
-
return data.status === "healthy" || data.status === "ok";
|
|
219
|
-
}
|
|
220
|
-
return false;
|
|
221
|
-
}
|
|
222
|
-
catch {
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Get the base URL for this adapter
|
|
228
|
-
*/
|
|
229
|
-
getBaseUrl() {
|
|
230
|
-
return this.baseUrl;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
//# sourceMappingURL=HttpRuntimeAdapter.js.map
|