@blokjs/runner 0.2.2 → 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 +59 -5
- package/dist/Configuration.js +366 -96
- 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/PayloadTooLargeError.d.ts +19 -0
- package/dist/PayloadTooLargeError.js +29 -0
- package/dist/PayloadTooLargeError.js.map +1 -0
- package/dist/RunCancelledError.d.ts +17 -0
- package/dist/RunCancelledError.js +25 -0
- package/dist/RunCancelledError.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 +648 -44
- 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 +181 -0
- package/dist/SubworkflowNode.js +479 -0
- package/dist/SubworkflowNode.js.map +1 -0
- 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 +178 -0
- package/dist/TriggerBase.js +1032 -5
- 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/WaitDispatchRequest.d.ts +38 -0
- package/dist/WaitDispatchRequest.js +13 -0
- package/dist/WaitDispatchRequest.js.map +1 -0
- package/dist/WaitNode.d.ts +23 -0
- package/dist/WaitNode.js +26 -0
- package/dist/WaitNode.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/ConcurrencyBackend.d.ts +61 -0
- package/dist/concurrency/ConcurrencyBackend.js +20 -0
- package/dist/concurrency/ConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/ConcurrencyLimitError.d.ts +37 -0
- package/dist/concurrency/ConcurrencyLimitError.js +16 -0
- package/dist/concurrency/ConcurrencyLimitError.js.map +1 -0
- package/dist/concurrency/NatsKvConcurrencyBackend.d.ts +64 -0
- package/dist/concurrency/NatsKvConcurrencyBackend.js +310 -0
- package/dist/concurrency/NatsKvConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/QueueExpiredError.d.ts +40 -0
- package/dist/concurrency/QueueExpiredError.js +15 -0
- package/dist/concurrency/QueueExpiredError.js.map +1 -0
- 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 +24 -0
- package/dist/concurrency/createConcurrencyBackend.js +38 -0
- package/dist/concurrency/createConcurrencyBackend.js.map +1 -0
- package/dist/concurrency/readConcurrencyConfig.d.ts +60 -0
- package/dist/concurrency/readConcurrencyConfig.js +60 -0
- package/dist/concurrency/readConcurrencyConfig.js.map +1 -0
- 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/idempotency/resolveIdempotencyKey.d.ts +20 -0
- package/dist/idempotency/resolveIdempotencyKey.js +37 -0
- package/dist/idempotency/resolveIdempotencyKey.js.map +1 -0
- package/dist/index.d.ts +30 -6
- package/dist/index.js +55 -6
- 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 +82 -0
- package/dist/monitoring/ConcurrencyMetrics.js +139 -0
- package/dist/monitoring/ConcurrencyMetrics.js.map +1 -0
- 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/monitoring/JanitorMetrics.d.ts +27 -0
- package/dist/monitoring/JanitorMetrics.js +48 -0
- package/dist/monitoring/JanitorMetrics.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 +141 -0
- package/dist/scheduling/DebounceCoordinator.js +362 -0
- package/dist/scheduling/DebounceCoordinator.js.map +1 -0
- package/dist/scheduling/DeferredDispatchSignal.d.ts +50 -0
- package/dist/scheduling/DeferredDispatchSignal.js +14 -0
- package/dist/scheduling/DeferredDispatchSignal.js.map +1 -0
- package/dist/scheduling/DeferredRunScheduler.d.ts +96 -0
- package/dist/scheduling/DeferredRunScheduler.js +256 -0
- package/dist/scheduling/DeferredRunScheduler.js.map +1 -0
- 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/scheduling/readSchedulingConfig.d.ts +24 -0
- package/dist/scheduling/readSchedulingConfig.js +52 -0
- package/dist/scheduling/readSchedulingConfig.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/timeouts/StepTimeoutError.d.ts +22 -0
- package/dist/timeouts/StepTimeoutError.js +31 -0
- package/dist/timeouts/StepTimeoutError.js.map +1 -0
- package/dist/tracing/InMemoryRunStore.d.ts +41 -1
- package/dist/tracing/InMemoryRunStore.js +239 -0
- package/dist/tracing/InMemoryRunStore.js.map +1 -1
- package/dist/tracing/Janitor.d.ts +70 -0
- package/dist/tracing/Janitor.js +150 -0
- package/dist/tracing/Janitor.js.map +1 -0
- package/dist/tracing/PostgresRunStore.d.ts +57 -1
- package/dist/tracing/PostgresRunStore.js +711 -6
- 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 +181 -1
- package/dist/tracing/RunTracker.d.ts +244 -9
- package/dist/tracing/RunTracker.js +594 -1
- package/dist/tracing/RunTracker.js.map +1 -1
- package/dist/tracing/SqliteRunStore.d.ts +79 -2
- package/dist/tracing/SqliteRunStore.js +775 -16
- package/dist/tracing/SqliteRunStore.js.map +1 -1
- package/dist/tracing/TraceRouter.d.ts +20 -2
- package/dist/tracing/TraceRouter.js +612 -6
- 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/sanitize.d.ts +11 -0
- package/dist/tracing/sanitize.js +29 -0
- package/dist/tracing/sanitize.js.map +1 -1
- package/dist/tracing/types.d.ts +672 -2
- package/dist/utils/createChildContext.d.ts +32 -0
- package/dist/utils/createChildContext.js +113 -0
- package/dist/utils/createChildContext.js.map +1 -0
- 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 +48 -42
- package/dist/workflow/WorkflowNormalizer.js +650 -18
- package/dist/workflow/WorkflowNormalizer.js.map +1 -1
- package/dist/workflow/WorkflowRegistry.d.ts +186 -0
- package/dist/workflow/WorkflowRegistry.js +202 -0
- package/dist/workflow/WorkflowRegistry.js.map +1 -0
- 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
package/dist/tracing/types.d.ts
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Lifecycle status of a workflow run.
|
|
3
|
+
*
|
|
4
|
+
* - `pending`: created but not yet started.
|
|
5
|
+
* - `running`: currently executing.
|
|
6
|
+
* - `completed`: finished successfully.
|
|
7
|
+
* - `failed`: a step threw or the run aborted with an error.
|
|
8
|
+
* - `cancelled`: stopped externally before completion.
|
|
9
|
+
* - `throttled` (Tier 2 #6): rejected at run-entry because the
|
|
10
|
+
* concurrency limit for the resolved `concurrencyKey` was reached.
|
|
11
|
+
* Distinct from `failed` — no step ran; nothing produced an error.
|
|
12
|
+
* - `delayed` (Tier 2 #5): scheduled to start at a future time. The
|
|
13
|
+
* run record exists; the dispatch is pending. Transitions to
|
|
14
|
+
* `running` when the timer fires.
|
|
15
|
+
* - `expired` (Tier 2 #5): TTL exceeded before dispatch. Auto-cancelled
|
|
16
|
+
* without execution. Distinct from `cancelled` (which is operator-
|
|
17
|
+
* initiated) and `failed` (which implies a step ran).
|
|
18
|
+
* - `debounced` (Tier 2 #7): coalesced into another run via the
|
|
19
|
+
* `debounce.key` mechanism. The "loser" of a leading-mode coalesce;
|
|
20
|
+
* in trailing mode this state is transient (run flips to `running`
|
|
21
|
+
* when the debounce timer fires).
|
|
22
|
+
* - `crashed` (Tier 2 quick-wins): the runner itself crashed (uncaught
|
|
23
|
+
* exception, OOM, signal). Distinct from `failed` (which implies a
|
|
24
|
+
* step's `process()` threw cleanly). Currently MANUAL — call
|
|
25
|
+
* `tracker.markRunCrashed(runId, {error})` from custom triggers /
|
|
26
|
+
* ops harnesses. Auto-flip on uncaught TriggerBase errors is a
|
|
27
|
+
* deferred follow-up.
|
|
28
|
+
* - `timedOut` (Tier 2 quick-wins): a step's final retry attempt
|
|
29
|
+
* exceeded its `maxDuration` cap. Distinct from `failed` so SLA
|
|
30
|
+
* dashboards can separate timeout-driven failures (network /
|
|
31
|
+
* capacity) from logic failures (bugs). Auto-flipped by
|
|
32
|
+
* `RunnerSteps` on final-attempt `StepTimeoutError`.
|
|
33
|
+
*/
|
|
34
|
+
export type WorkflowRunStatus = "pending" | "running" | "completed" | "failed" | "cancelled" | "throttled" | "delayed" | "expired" | "debounced" | "queued" | "crashed" | "timedOut";
|
|
2
35
|
/**
|
|
3
36
|
* Structured failure detail attached to a {@link WorkflowRun} or
|
|
4
37
|
* {@link NodeRun}. When the failure source threw a typed `BlokError`
|
|
@@ -60,6 +93,107 @@ export interface WorkflowRun {
|
|
|
60
93
|
* SQLite databases still work because the column is optional.
|
|
61
94
|
*/
|
|
62
95
|
environment?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Tier 1 · replay lineage. When this run was started via
|
|
98
|
+
* `POST /__blok/runs/:id/replay`, this carries the original run's id.
|
|
99
|
+
* Studio renders a "Replay of #..." breadcrumb that links back to the
|
|
100
|
+
* source run. Absent on first-class triggered runs.
|
|
101
|
+
*
|
|
102
|
+
* Plumbed end-to-end via the `X-Blok-Replay-Of` HTTP header that the
|
|
103
|
+
* replay endpoint sets on the dispatched request. TriggerBase reads
|
|
104
|
+
* the header and threads it into `tracker.startRun({ replayOf })`.
|
|
105
|
+
*/
|
|
106
|
+
replayOf?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Tier 2 · sub-workflow lineage. When this run was started by a
|
|
109
|
+
* `subworkflow:` step in another workflow, this carries the parent
|
|
110
|
+
* run's id. Studio renders a "called from #..." breadcrumb that
|
|
111
|
+
* links back to the parent run. Absent on first-class triggered runs.
|
|
112
|
+
*/
|
|
113
|
+
parentRunId?: string;
|
|
114
|
+
/**
|
|
115
|
+
* Tier 2 · sub-workflow lineage. The specific NodeRun within the
|
|
116
|
+
* parent run that invoked this sub-workflow — lets Studio jump to
|
|
117
|
+
* the exact sub-workflow step on the parent's run-detail page.
|
|
118
|
+
*/
|
|
119
|
+
parentNodeRunId?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Tier 2 #5 · scheduled dispatch time (ms since epoch). Set when the
|
|
122
|
+
* run is created with `delay` on the trigger config, OR when the
|
|
123
|
+
* debounce coordinator parks a coalescing run. Absent on immediate
|
|
124
|
+
* runs.
|
|
125
|
+
*/
|
|
126
|
+
scheduledAt?: number;
|
|
127
|
+
/**
|
|
128
|
+
* Tier 2 #5 · TTL deadline (ms since epoch). When `now > expiresAt`
|
|
129
|
+
* at dispatch time, the run is marked `expired` and skipped. Set
|
|
130
|
+
* from `trigger.ttl` plus the original submission timestamp. Absent
|
|
131
|
+
* when no TTL is configured.
|
|
132
|
+
*/
|
|
133
|
+
expiresAt?: number;
|
|
134
|
+
/**
|
|
135
|
+
* Tier 2 #7 · resolved debounce key (`debounce.key` after
|
|
136
|
+
* `js/...`-expression evaluation). Pings sharing this key + workflow
|
|
137
|
+
* name coalesce into the same `WorkflowRun`. Absent on non-debounced
|
|
138
|
+
* runs.
|
|
139
|
+
*/
|
|
140
|
+
debounceKey?: string;
|
|
141
|
+
/**
|
|
142
|
+
* Tier 2 #7 · debounce mode that produced this run. Surfaces in
|
|
143
|
+
* Studio's run detail so users can tell `leading` (immediate-fire)
|
|
144
|
+
* vs `trailing` (silence-then-fire) at a glance.
|
|
145
|
+
*/
|
|
146
|
+
debounceMode?: "leading" | "trailing";
|
|
147
|
+
/**
|
|
148
|
+
* Tier 2 #7 · number of pings absorbed by this run before dispatch.
|
|
149
|
+
* Starts at 1 (the first ping). Subsequent same-key pings increment
|
|
150
|
+
* this rather than creating new run records. Surfaces on Studio's
|
|
151
|
+
* run row as "Pings: N".
|
|
152
|
+
*/
|
|
153
|
+
pingCount?: number;
|
|
154
|
+
/**
|
|
155
|
+
* PR 4 · `wait.for(duration)` / `wait.until(date)` resume cursor.
|
|
156
|
+
*
|
|
157
|
+
* Set after each non-wait step completes. On
|
|
158
|
+
* `dispatchDeferred` re-entry from a wait step, the runner skips
|
|
159
|
+
* steps with `stepIndex <= lastCompletedStepIndex` to avoid
|
|
160
|
+
* re-running pre-wait steps. Undefined for runs that never
|
|
161
|
+
* encountered a wait step (preserves existing semantics).
|
|
162
|
+
*/
|
|
163
|
+
lastCompletedStepIndex?: number;
|
|
164
|
+
/**
|
|
165
|
+
* v0.6 prerequisite for wait-inside-primitives Phase 2.
|
|
166
|
+
*
|
|
167
|
+
* JSON-serialized snapshot of `ctx.state` taken immediately before
|
|
168
|
+
* `RunnerSteps` throws `WaitDispatchRequest`. On `dispatchDeferred`
|
|
169
|
+
* re-entry — including the cross-process recovery path where the
|
|
170
|
+
* scheduler re-builds a fresh ctx from the persisted dispatch row —
|
|
171
|
+
* `TriggerBase.run` rehydrates `ctx.state` (and its `ctx.vars`
|
|
172
|
+
* alias) from this column so subsequent steps see the same
|
|
173
|
+
* pre-wait state regardless of process restart.
|
|
174
|
+
*
|
|
175
|
+
* Without this column, only the in-process timer-fire path would
|
|
176
|
+
* preserve state (state still lives on the original ctx). The
|
|
177
|
+
* cross-process path would resume with empty `ctx.state`, breaking
|
|
178
|
+
* Phase 2's iteration-state-persistence promise (a forEach
|
|
179
|
+
* iteration whose body fired the wait would lose its index, the
|
|
180
|
+
* loop's accumulator, etc.).
|
|
181
|
+
*
|
|
182
|
+
* Capped by `BLOK_STATE_SNAPSHOT_MAX_BYTES` (default 1MB,
|
|
183
|
+
* matching `BLOK_DISPATCH_PAYLOAD_MAX_BYTES`) — when the
|
|
184
|
+
* serialized state exceeds the cap, the runner logs a warning and
|
|
185
|
+
* skips the snapshot (the wait still defers; resumption is
|
|
186
|
+
* best-effort). Authors can opt out entirely via
|
|
187
|
+
* `BLOK_STATE_SNAPSHOT_DISABLED=1`. Sensitive keys aren't filtered
|
|
188
|
+
* here — the snapshot only persists what the workflow has already
|
|
189
|
+
* computed into `state`, so apply your own redaction in nodes that
|
|
190
|
+
* write secrets there.
|
|
191
|
+
*
|
|
192
|
+
* Undefined for runs that never threw `WaitDispatchRequest`, which
|
|
193
|
+
* is the vast majority. Persisted column is `state_snapshot`
|
|
194
|
+
* (sqlite migration v11).
|
|
195
|
+
*/
|
|
196
|
+
stateSnapshot?: string;
|
|
63
197
|
}
|
|
64
198
|
export type NodeRunStatus = "pending" | "running" | "completed" | "failed" | "skipped";
|
|
65
199
|
export interface NodeRun {
|
|
@@ -113,12 +247,369 @@ export interface NodeRun {
|
|
|
113
247
|
/** Bytes received from the SDK in the response. */
|
|
114
248
|
response_bytes?: number;
|
|
115
249
|
};
|
|
250
|
+
/**
|
|
251
|
+
* Tier 1 idempotency cache lineage. Populated by `RunTracker.markNodeCached`
|
|
252
|
+
* when the step short-circuited via a cache hit instead of running. Studio
|
|
253
|
+
* renders a "CACHED" badge with a click-through to the source run/node.
|
|
254
|
+
* Absent on regular completed nodes.
|
|
255
|
+
*/
|
|
256
|
+
cached?: {
|
|
257
|
+
sourceRunId: string;
|
|
258
|
+
sourceNodeRunId: string;
|
|
259
|
+
cachedAt: number;
|
|
260
|
+
};
|
|
261
|
+
/**
|
|
262
|
+
* Tier 1 retry attempts. One entry per `NODE_ATTEMPT_FAILED` event the
|
|
263
|
+
* step emitted before either succeeding or exhausting `retry.maxAttempts`.
|
|
264
|
+
* Capped at 10 entries (`MAX_STORED_ATTEMPTS`) — extreme retry counts
|
|
265
|
+
* are bounded so a runaway loop can't bloat the run store.
|
|
266
|
+
*
|
|
267
|
+
* Studio renders this as a collapsible "Attempts (N)" disclosure on the
|
|
268
|
+
* step's panel. The final outcome lives on the node's status / error
|
|
269
|
+
* fields; this array carries only the failed attempts that came before.
|
|
270
|
+
*/
|
|
271
|
+
attempts?: Array<{
|
|
272
|
+
attempt: number;
|
|
273
|
+
error: RunErrorDetail;
|
|
274
|
+
timestamp: number;
|
|
275
|
+
}>;
|
|
276
|
+
/**
|
|
277
|
+
* Tier 2 #4 sub-workflow mode — only set for `nodeType === "subworkflow"`.
|
|
278
|
+
* - `true` (default) — synchronous: parent step blocks on child completion.
|
|
279
|
+
* - `false` — fire-and-forget: parent returns dispatch metadata immediately;
|
|
280
|
+
* child runs asynchronously via `setImmediate`. Studio renders a distinct
|
|
281
|
+
* `↳ async` badge in StepRail to differentiate from synchronous siblings.
|
|
282
|
+
*
|
|
283
|
+
* Captured at `tracker.startNode()` time so it survives the trace and is
|
|
284
|
+
* visible to Studio without recomputing from outputs heuristics.
|
|
285
|
+
*/
|
|
286
|
+
wait?: boolean;
|
|
287
|
+
/**
|
|
288
|
+
* G2 (v0.6) sub-workflow dispatch strategy — only set for
|
|
289
|
+
* `nodeType === "subworkflow"`. Mirrors the step config's `dispatch`
|
|
290
|
+
* field so Studio can distinguish in-process invocations from HTTP
|
|
291
|
+
* self-call dispatches at a glance.
|
|
292
|
+
*
|
|
293
|
+
* - `"in-process"` (default; also represented by `undefined` on legacy
|
|
294
|
+
* traces) — child runs in the same Node process via the in-process
|
|
295
|
+
* `Runner`.
|
|
296
|
+
* - `"http-self"` — child is dispatched as a fresh HTTP request to
|
|
297
|
+
* `BLOK_SELF_BASE_URL`, potentially landing on a different process
|
|
298
|
+
* in a horizontally-scaled deployment.
|
|
299
|
+
*
|
|
300
|
+
* Captured at `tracker.startNode()` time alongside `wait` so the rail
|
|
301
|
+
* badge can compose them (`↳ async` orange + `http` sky for an
|
|
302
|
+
* async http-self dispatch).
|
|
303
|
+
*/
|
|
304
|
+
dispatch?: "in-process" | "http-self";
|
|
305
|
+
/**
|
|
306
|
+
* PR 5 E3 — sub-workflow nesting depth surfaced for Studio.
|
|
307
|
+
*
|
|
308
|
+
* Set on subworkflow node runs. Top-level workflow's sub-workflow
|
|
309
|
+
* step has `subworkflowDepth = 1`; that child's sub-workflow step
|
|
310
|
+
* has `subworkflowDepth = 2`; etc. Bounded by
|
|
311
|
+
* `BLOK_MAX_SUBWORKFLOW_DEPTH` (default 10).
|
|
312
|
+
*
|
|
313
|
+
* Studio renders `↳ async (N)` / `↳ sub (N)` only when N >= 2 to
|
|
314
|
+
* keep top-level invocations un-cluttered.
|
|
315
|
+
*/
|
|
316
|
+
subworkflowDepth?: number;
|
|
317
|
+
/**
|
|
318
|
+
* v0.5 — origin middleware name when the trigger's
|
|
319
|
+
* `runMiddlewareChain` produced this NodeRun. The trigger sets a
|
|
320
|
+
* `_blokMiddlewareName` sentinel on ctx before dispatching each
|
|
321
|
+
* middleware; RunnerSteps reads it and propagates here so Studio's
|
|
322
|
+
* StepRail can surface a `mw:<name>` badge on the inner steps a
|
|
323
|
+
* middleware produced (otherwise indistinguishable from regular
|
|
324
|
+
* depth-1 nested steps).
|
|
325
|
+
*/
|
|
326
|
+
middleware?: string;
|
|
327
|
+
/**
|
|
328
|
+
* v0.5.3 — iteration index for steps inside a `forEach` or `loop`
|
|
329
|
+
* primitive. Set per-iteration by ForEachNode / LoopNode on the
|
|
330
|
+
* cloned child ctx (`_blokIterationIndex` sentinel); RunnerSteps
|
|
331
|
+
* reads it and propagates here. Studio's StepRail groups consecutive
|
|
332
|
+
* sibling rows that share an iterationIndex into a collapsible
|
|
333
|
+
* "iteration N" header so a 5-iteration forEach with 3 inner steps
|
|
334
|
+
* renders as 5 grouped sections instead of 15 flat rows with
|
|
335
|
+
* duplicate names. Undefined for top-level steps, for steps inside
|
|
336
|
+
* non-iteration primitives (`tryCatch`, `switch`), and for legacy
|
|
337
|
+
* traces written before v0.5.3.
|
|
338
|
+
*/
|
|
339
|
+
iterationIndex?: number;
|
|
340
|
+
/**
|
|
341
|
+
* v0.6 wait-inside-primitives — iteration cursor. Set on a primitive
|
|
342
|
+
* iterator's NodeRun (e.g. forEach, loop) by RunnerSteps when an
|
|
343
|
+
* INNER step throws `WaitDispatchRequest` mid-iteration. Read by
|
|
344
|
+
* `TriggerBase.run` on dispatchDeferred re-entry and stamped onto
|
|
345
|
+
* `ctx._blokIterationResume` so the primitive can pick it up.
|
|
346
|
+
* Persisted column is `iteration_context` (sqlite migration v12).
|
|
347
|
+
*
|
|
348
|
+
* Two encodings via a `mode` discriminator:
|
|
349
|
+
*
|
|
350
|
+
* - `mode: "sequential"` (or omitted for back-compat): the Phase 2
|
|
351
|
+
* sequential forEach + wait cursor (also reused by Phase 3 loop).
|
|
352
|
+
* Records the in-flight iteration index, the inner step index
|
|
353
|
+
* where the wait fired, and an in-order `completedResults`
|
|
354
|
+
* accumulator covering iterations `[0..iteration-1]`. ForEachNode
|
|
355
|
+
* and LoopNode read this on resume to skip the completed prefix.
|
|
356
|
+
*
|
|
357
|
+
* - `mode: "parallel"` (PR follow-up to Phase 3): the parallel
|
|
358
|
+
* forEach + wait cursor. Records which iteration's wait fired
|
|
359
|
+
* (`waitFiringIteration`), where inside its body
|
|
360
|
+
* (`innerStepIndex`), a SPARSE `completedResults` array (slot `i`
|
|
361
|
+
* populated iff iteration `i` finished before the wait fired —
|
|
362
|
+
* `null` for "ran but returned undefined", JSON-undefined hole
|
|
363
|
+
* for "not present"), and the explicit `cancelledIterations`
|
|
364
|
+
* list (in-flight + queued indices that need re-launch on
|
|
365
|
+
* resume). See `docs/c/devtools/parallel-foreach-wait-spec.mdx`
|
|
366
|
+
* for the full contract.
|
|
367
|
+
*
|
|
368
|
+
* Undefined on regular NodeRuns and on primitives that completed
|
|
369
|
+
* without ever throwing a wait.
|
|
370
|
+
*/
|
|
371
|
+
iterationContext?: IterationContext;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Discriminated union for the iteration cursor persisted into
|
|
375
|
+
* `node_runs.iteration_context`. See `NodeRun.iterationContext` for
|
|
376
|
+
* field-level semantics. The runtime selection lives in:
|
|
377
|
+
*
|
|
378
|
+
* - Write side: `core/runner/src/RunnerSteps.ts` wait-throw site
|
|
379
|
+
* (sequential) and `ForEachNode.run` parallel-branch error handler
|
|
380
|
+
* (parallel).
|
|
381
|
+
* - Read side: `TriggerBase.run` rehydrate stamps the cursor onto
|
|
382
|
+
* `ctx._blokIterationResume`; the primitive itself (ForEachNode,
|
|
383
|
+
* LoopNode) dispatches on `mode` to the right resume path.
|
|
384
|
+
*/
|
|
385
|
+
export type IterationContext = SequentialIterationContext | ParallelIterationContext | SwitchIterationContext;
|
|
386
|
+
/**
|
|
387
|
+
* Sequential forEach + wait OR loop + wait cursor. The pre-existing
|
|
388
|
+
* Phase 2/3 shape — `mode` is optional and defaults to "sequential" on
|
|
389
|
+
* read so cursors written before the discriminator landed (i.e., main
|
|
390
|
+
* before this PR) keep being interpreted correctly.
|
|
391
|
+
*/
|
|
392
|
+
export interface SequentialIterationContext {
|
|
393
|
+
mode?: "sequential";
|
|
394
|
+
/** Iteration index (0-based) the wait fired in. */
|
|
395
|
+
iteration: number;
|
|
396
|
+
/** Inner step index within iteration's body where the wait fired. */
|
|
397
|
+
innerStepIndex: number;
|
|
398
|
+
/** Accumulator for iterations [0..iteration-1]; pre-populates `results[]` on resume. */
|
|
399
|
+
completedResults: unknown[];
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* v0.6 Phase 4 — switch + wait cursor. Records which case arm matched
|
|
403
|
+
* (so on re-entry SwitchNode walks back into the same arm) plus the
|
|
404
|
+
* inner step within that arm where the wait fired.
|
|
405
|
+
*
|
|
406
|
+
* `caseIndex` semantics:
|
|
407
|
+
* - `>= 0` — index into the workflow's `cases[]` array.
|
|
408
|
+
* - `-1` — the `default` arm matched.
|
|
409
|
+
*
|
|
410
|
+
* `completedResults` is unused for switch (it doesn't iterate) but the
|
|
411
|
+
* field is kept on the IterationContext union for cross-schema parity.
|
|
412
|
+
* Always `[]` on switch.
|
|
413
|
+
*/
|
|
414
|
+
export interface SwitchIterationContext {
|
|
415
|
+
mode: "switch";
|
|
416
|
+
/** Resolved case index; `-1` denotes the `default` arm. */
|
|
417
|
+
caseIndex: number;
|
|
418
|
+
/** Inner step index within the matched arm where the wait fired. */
|
|
419
|
+
innerStepIndex: number;
|
|
420
|
+
/** Unused for switch; preserved at schema level for parity. Always `[]`. */
|
|
421
|
+
completedResults: never[];
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Parallel forEach + wait cursor. The headline contract: persist
|
|
425
|
+
* completed iteration results, retry incomplete ones on resume. See
|
|
426
|
+
* `docs/c/devtools/parallel-foreach-wait-spec.mdx` for the full design.
|
|
427
|
+
*/
|
|
428
|
+
export interface ParallelIterationContext {
|
|
429
|
+
mode: "parallel";
|
|
430
|
+
/** Index of the iteration whose inner step threw the wait. */
|
|
431
|
+
waitFiringIteration: number;
|
|
432
|
+
/** Inner step index within the wait-firing iteration's body. */
|
|
433
|
+
innerStepIndex: number;
|
|
434
|
+
/**
|
|
435
|
+
* Sparse array indexed by iteration number. Slot `i` is populated
|
|
436
|
+
* iff iteration `i` finished before the wait fired. `null` means
|
|
437
|
+
* "ran but returned undefined" (distinct from the JSON-undefined
|
|
438
|
+
* hole = "not present in cursor, re-launch on resume").
|
|
439
|
+
*/
|
|
440
|
+
completedResults: (unknown | null)[];
|
|
441
|
+
/**
|
|
442
|
+
* Iteration indices that were in-flight OR queued at wait-throw
|
|
443
|
+
* moment. ForEachNode re-launches these from inner step 0 on
|
|
444
|
+
* resume. The wait-firing iteration is NOT in this list — it
|
|
445
|
+
* resumes via `innerStepIndex`. Sorted ascending for trace-dump
|
|
446
|
+
* readability.
|
|
447
|
+
*/
|
|
448
|
+
cancelledIterations: number[];
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Stored result of a previously-successful step execution, keyed by
|
|
452
|
+
* `(workflowName, step.id, idempotencyKey)`. On cache hit, RunnerSteps
|
|
453
|
+
* skips `step.process()` and replays the cached `data` through the same
|
|
454
|
+
* `PersistenceHelper.applyStepOutput` rules — caching layers ABOVE
|
|
455
|
+
* persistence, never within it.
|
|
456
|
+
*/
|
|
457
|
+
export interface CachedStepResult {
|
|
458
|
+
/** The data the step originally returned. */
|
|
459
|
+
data: unknown;
|
|
460
|
+
/** ms since epoch when the entry was written. */
|
|
461
|
+
cachedAt: number;
|
|
462
|
+
/** ms since epoch when the entry expires; null = no expiry. */
|
|
463
|
+
expiresAt: number | null;
|
|
464
|
+
/** Run that originally produced this result. */
|
|
465
|
+
sourceRunId: string;
|
|
466
|
+
/** Node run that originally produced this result. */
|
|
467
|
+
sourceNodeRunId: string;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Outcome of an `acquireConcurrencySlot` attempt (Tier 2 #6).
|
|
471
|
+
*
|
|
472
|
+
* The store's gate decides whether the run is allowed to proceed by
|
|
473
|
+
* comparing the current in-flight count for the (workflow, key) pair
|
|
474
|
+
* against the requested limit.
|
|
475
|
+
*/
|
|
476
|
+
export interface ConcurrencySlotResult {
|
|
477
|
+
/** True when the slot was granted; false when the run should be throttled. */
|
|
478
|
+
acquired: boolean;
|
|
479
|
+
/**
|
|
480
|
+
* Number of in-flight runs (including the just-acquired one when
|
|
481
|
+
* `acquired === true`) sharing the same (workflowName, concurrencyKey).
|
|
482
|
+
* Useful for observability — Studio surfaces this on `RUN_THROTTLED`.
|
|
483
|
+
*/
|
|
484
|
+
currentInFlight: number;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* A persisted scheduled dispatch — one row per pending HTTP-trigger
|
|
488
|
+
* deferral. Written by `DeferredRunScheduler.schedule()` when a
|
|
489
|
+
* `persist` payload is provided; deleted on cancel or fire.
|
|
490
|
+
*
|
|
491
|
+
* Boot recovery (HttpTrigger.recoverDispatches) scans this table,
|
|
492
|
+
* marks past-due+TTL-expired rows as `"expired"`, and re-registers
|
|
493
|
+
* timers for live dispatches.
|
|
494
|
+
*/
|
|
495
|
+
export interface ScheduledDispatchRow {
|
|
496
|
+
runId: string;
|
|
497
|
+
workflowName: string;
|
|
498
|
+
/** `"http"` for v1; future triggers can opt in. */
|
|
499
|
+
triggerType: string;
|
|
500
|
+
/** ms since epoch when to dispatch. */
|
|
501
|
+
scheduledAt: number;
|
|
502
|
+
/** ms since epoch TTL deadline (undefined = no TTL). */
|
|
503
|
+
expiresAt?: number;
|
|
504
|
+
/** Mirrors the run record's status — `"delayed" | "queued" | "debounced"`. */
|
|
505
|
+
dispatchStatus: "delayed" | "queued" | "debounced";
|
|
506
|
+
/**
|
|
507
|
+
* JSON-serialized minimal Context subset, trigger-defined.
|
|
508
|
+
* For HTTP: `{method, path, headers, body, params, query, workflowPath}`
|
|
509
|
+
* with sensitive header keys stripped (authorization, cookie, x-api-key).
|
|
510
|
+
*/
|
|
511
|
+
payload: unknown;
|
|
512
|
+
/** ms since epoch when the row was first written. */
|
|
513
|
+
createdAt: number;
|
|
514
|
+
/**
|
|
515
|
+
* Tier C #2 — cross-process scheduler coordination. Set when a
|
|
516
|
+
* process claims this dispatch during boot recovery. Unset on
|
|
517
|
+
* unclaimed rows.
|
|
518
|
+
*
|
|
519
|
+
* Multi-process PG deployments use the claim to prevent the same
|
|
520
|
+
* dispatch from being fired by two processes that both ran
|
|
521
|
+
* `recoverDispatches()` against the shared table. Single-process
|
|
522
|
+
* and per-process sqlite deployments see no observable difference
|
|
523
|
+
* (the same process always wins the claim).
|
|
524
|
+
*/
|
|
525
|
+
claimedBy?: string;
|
|
526
|
+
/**
|
|
527
|
+
* Tier C #2 — last heartbeat timestamp (ms since epoch). The
|
|
528
|
+
* holder of `claimedBy` periodically refreshes `claimedAt` while
|
|
529
|
+
* the timer is registered. Stale claims (now > claimedAt + leaseMs)
|
|
530
|
+
* are eligible for takeover by another process — protects against
|
|
531
|
+
* crashed holders blocking recovery indefinitely.
|
|
532
|
+
*/
|
|
533
|
+
claimedAt?: number;
|
|
116
534
|
}
|
|
117
535
|
export type RunEventType = "RUN_STARTED" | "RUN_COMPLETED" | "RUN_FAILED" | "NODE_STARTED" | "NODE_COMPLETED" | "NODE_FAILED" | "NODE_SKIPPED" | "VARS_UPDATED" | "LOG_ENTRY"
|
|
118
536
|
/** §17 Phase 5: streaming `Progress` frame from the SDK. */
|
|
119
537
|
| "NODE_PROGRESS"
|
|
120
538
|
/** §17 Phase 5: streaming `PartialResult` frame from the SDK. */
|
|
121
|
-
| "NODE_PARTIAL_RESULT"
|
|
539
|
+
| "NODE_PARTIAL_RESULT"
|
|
540
|
+
/**
|
|
541
|
+
* Tier 1 idempotency cache hit: the step short-circuited via the
|
|
542
|
+
* idempotency cache instead of running. Payload carries
|
|
543
|
+
* `{ durationMs, source: { sourceRunId, sourceNodeRunId, cachedAt } }`.
|
|
544
|
+
* Studio renders a CACHED badge on the affected node.
|
|
545
|
+
*/
|
|
546
|
+
| "NODE_CACHED"
|
|
547
|
+
/**
|
|
548
|
+
* Tier 1 retry: a step attempt failed and another retry will follow.
|
|
549
|
+
* Payload carries `{ attempt, error }`. Final attempt failure (after
|
|
550
|
+
* exhausting `retry.maxAttempts`) emits `NODE_FAILED` instead.
|
|
551
|
+
*/
|
|
552
|
+
| "NODE_ATTEMPT_FAILED"
|
|
553
|
+
/**
|
|
554
|
+
* Tier 2 #6 concurrency gate denied a run before any step executed.
|
|
555
|
+
* Payload carries `{ concurrencyKey, concurrencyLimit, currentInFlight }`.
|
|
556
|
+
* The run's status flips to `"throttled"` (distinct from `"failed"` —
|
|
557
|
+
* no step ran). Studio surfaces a Throttled badge.
|
|
558
|
+
*/
|
|
559
|
+
| "RUN_THROTTLED"
|
|
560
|
+
/**
|
|
561
|
+
* Tier 2 #5 — run scheduled for later dispatch via `trigger.delay`.
|
|
562
|
+
* Payload `{scheduledAt, delayMs, expiresAt?}`. Status flips to
|
|
563
|
+
* `"delayed"`; transitions to `"running"` when the timer fires.
|
|
564
|
+
*/
|
|
565
|
+
| "RUN_DELAYED"
|
|
566
|
+
/**
|
|
567
|
+
* Tier 2 #5 — TTL exceeded; run auto-cancelled before dispatch.
|
|
568
|
+
* Payload `{expiresAt, expiredAt, lateBy}`. Status flips to `"expired"`.
|
|
569
|
+
*/
|
|
570
|
+
| "RUN_EXPIRED"
|
|
571
|
+
/**
|
|
572
|
+
* Tier 2 #7 — run coalesced into a debounce window. Payload
|
|
573
|
+
* `{debounceKey, mode, intoRunId?, pingCount?}`. Status flips to
|
|
574
|
+
* `"debounced"`. In leading mode this is terminal (the run never
|
|
575
|
+
* executes — execution went to a sibling). In trailing mode this is
|
|
576
|
+
* transient and the same run flips to `"running"` when the window
|
|
577
|
+
* closes.
|
|
578
|
+
*/
|
|
579
|
+
| "RUN_DEBOUNCED"
|
|
580
|
+
/**
|
|
581
|
+
* Tier 2 #6 follow-up — concurrency gate denied a run AND the trigger
|
|
582
|
+
* is configured with `onLimit: "queue"`. Instead of throwing, the run
|
|
583
|
+
* is deferred via `DeferredRunScheduler` and re-attempts acquisition
|
|
584
|
+
* after a 1s delay. Payload `{concurrencyKey, concurrencyLimit,
|
|
585
|
+
* currentInFlight, scheduledAt}`. Status flips to `"queued"`;
|
|
586
|
+
* transitions to `"running"` when the timer fires (and may flip back
|
|
587
|
+
* to `"queued"` on re-denial).
|
|
588
|
+
*/
|
|
589
|
+
| "RUN_QUEUED"
|
|
590
|
+
/**
|
|
591
|
+
* Tier 2 polish — operator cancelled a pending (delayed/debounced/
|
|
592
|
+
* queued) run via `POST /__blok/runs/:runId/cancel`. Payload
|
|
593
|
+
* `{durationMs, previousStatus}`. Status flips to `"cancelled"`.
|
|
594
|
+
* Currently only pre-execution states are cancellable; running runs
|
|
595
|
+
* require cooperative `AbortSignal` (deferred follow-up).
|
|
596
|
+
*/
|
|
597
|
+
| "RUN_CANCELLED"
|
|
598
|
+
/**
|
|
599
|
+
* Tier 2 quick-wins — run crashed (uncaught exception / OOM /
|
|
600
|
+
* signal). Payload `{durationMs, error}`. Distinct from `RUN_FAILED`
|
|
601
|
+
* (which implies a step's `process()` threw cleanly). Currently
|
|
602
|
+
* manual via `tracker.markRunCrashed(runId, {error})`.
|
|
603
|
+
*/
|
|
604
|
+
| "RUN_CRASHED"
|
|
605
|
+
/**
|
|
606
|
+
* Tier 2 quick-wins — a step's final retry attempt exceeded its
|
|
607
|
+
* `maxDuration` cap. Payload `{durationMs, stepId, maxDurationMs,
|
|
608
|
+
* attemptsExhausted}`. Auto-emitted by `RunnerSteps` when the
|
|
609
|
+
* timeout fires on the last attempt. Run status flips to
|
|
610
|
+
* `"timedOut"`.
|
|
611
|
+
*/
|
|
612
|
+
| "RUN_TIMED_OUT";
|
|
122
613
|
export interface RunEvent {
|
|
123
614
|
id: string;
|
|
124
615
|
type: RunEventType;
|
|
@@ -155,6 +646,26 @@ export interface WorkflowDetail extends WorkflowSummary {
|
|
|
155
646
|
definition?: unknown;
|
|
156
647
|
nodeNames: string[];
|
|
157
648
|
runtimes: string[];
|
|
649
|
+
/**
|
|
650
|
+
* Sample-body for the Studio empty-state curl. `source` lets the
|
|
651
|
+
* UI optionally distinguish author-declared examples from the
|
|
652
|
+
* synthesized ones (it doesn't today, but could in the future).
|
|
653
|
+
* Always populated for object-shaped workflows; `body` is `{}`
|
|
654
|
+
* when no body references were detected.
|
|
655
|
+
*/
|
|
656
|
+
examples?: {
|
|
657
|
+
body: unknown;
|
|
658
|
+
/**
|
|
659
|
+
* Provenance of the body. `author` = declared in the workflow's
|
|
660
|
+
* `trigger.http.examples.body`. `recorded` = captured from the
|
|
661
|
+
* first successful run when `recordSample: true` is set on the
|
|
662
|
+
* trigger. `inferred` = synthesized from static analysis of step
|
|
663
|
+
* inputs. `empty` = no body references + no recording + no
|
|
664
|
+
* author override (the literal `{}`). Studio surfaces this in
|
|
665
|
+
* the Runs-tab empty-state curl snippet label.
|
|
666
|
+
*/
|
|
667
|
+
source: "author" | "recorded" | "inferred" | "empty";
|
|
668
|
+
};
|
|
158
669
|
}
|
|
159
670
|
export interface PaginatedResult<T> {
|
|
160
671
|
data: T[];
|
|
@@ -170,6 +681,43 @@ export interface StartRunOptions {
|
|
|
170
681
|
nodeCount: number;
|
|
171
682
|
tags?: string[];
|
|
172
683
|
metadata?: Record<string, unknown>;
|
|
684
|
+
/**
|
|
685
|
+
* Tier 1 · replay lineage. When a run is started via the replay endpoint,
|
|
686
|
+
* this carries the original run's id so Studio can render a "Replay of #..."
|
|
687
|
+
* breadcrumb. Plumbed end-to-end via the `X-Blok-Replay-Of` HTTP header.
|
|
688
|
+
*/
|
|
689
|
+
replayOf?: string;
|
|
690
|
+
/**
|
|
691
|
+
* Tier 2 · sub-workflow lineage. Populated by `SubworkflowNode` when
|
|
692
|
+
* invoking a child workflow inline. Studio uses this to render a
|
|
693
|
+
* "called from #..." breadcrumb on the child's run detail.
|
|
694
|
+
*/
|
|
695
|
+
parentRunId?: string;
|
|
696
|
+
parentNodeRunId?: string;
|
|
697
|
+
/**
|
|
698
|
+
* Tier 2 #5 · scheduled dispatch time (ms since epoch). When set, the
|
|
699
|
+
* run is created with status `"delayed"` instead of `"running"`.
|
|
700
|
+
*/
|
|
701
|
+
scheduledAt?: number;
|
|
702
|
+
/**
|
|
703
|
+
* Tier 2 #5 · TTL deadline (ms since epoch). Persists onto the run
|
|
704
|
+
* for the dispatcher to consult.
|
|
705
|
+
*/
|
|
706
|
+
expiresAt?: number;
|
|
707
|
+
/**
|
|
708
|
+
* Tier 2 #7 · resolved debounce key. When set, pings sharing this
|
|
709
|
+
* key + workflow name coalesce.
|
|
710
|
+
*/
|
|
711
|
+
debounceKey?: string;
|
|
712
|
+
/**
|
|
713
|
+
* Tier 2 #7 · debounce mode that produced this run.
|
|
714
|
+
*/
|
|
715
|
+
debounceMode?: "leading" | "trailing";
|
|
716
|
+
/**
|
|
717
|
+
* Tier 2 #7 · initial ping count for the run (typically 1 — the
|
|
718
|
+
* first ping). Subsequent pings increment via direct store update.
|
|
719
|
+
*/
|
|
720
|
+
pingCount?: number;
|
|
173
721
|
}
|
|
174
722
|
export interface StartNodeOptions {
|
|
175
723
|
nodeName: string;
|
|
@@ -179,6 +727,42 @@ export interface StartNodeOptions {
|
|
|
179
727
|
parentNodeId?: string;
|
|
180
728
|
depth: number;
|
|
181
729
|
stepIndex: number;
|
|
730
|
+
/**
|
|
731
|
+
* Tier 2 #4 sub-workflow mode. Only meaningful when `nodeType === "subworkflow"`.
|
|
732
|
+
* Persisted onto `NodeRun.wait` so Studio can render `↳ async` vs `↳ sub`.
|
|
733
|
+
*/
|
|
734
|
+
wait?: boolean;
|
|
735
|
+
/**
|
|
736
|
+
* G2 (v0.6) sub-workflow dispatch strategy. Only meaningful when
|
|
737
|
+
* `nodeType === "subworkflow"`. Persisted onto `NodeRun.dispatch` so
|
|
738
|
+
* Studio can render an extra `http` badge alongside `↳ async`/`↳ sub`
|
|
739
|
+
* for HTTP self-call dispatches.
|
|
740
|
+
*/
|
|
741
|
+
dispatch?: "in-process" | "http-self";
|
|
742
|
+
/**
|
|
743
|
+
* PR 5 E3 — sub-workflow nesting depth. Only meaningful when
|
|
744
|
+
* `nodeType === "subworkflow"`. The runner computes
|
|
745
|
+
* `parentDepth + 1` from `ctx._subworkflowDepth` at start-time and
|
|
746
|
+
* passes here so Studio can render `↳ sub (N)` for N >= 2.
|
|
747
|
+
*/
|
|
748
|
+
subworkflowDepth?: number;
|
|
749
|
+
/**
|
|
750
|
+
* v0.5 — origin middleware name. Set when the parent ctx carries
|
|
751
|
+
* `_blokMiddlewareName` (HttpTrigger.runMiddlewareChain stash).
|
|
752
|
+
* Propagates onto `NodeRun.middleware` so Studio's StepRail can
|
|
753
|
+
* surface a `mw:<name>` badge.
|
|
754
|
+
*/
|
|
755
|
+
middleware?: string;
|
|
756
|
+
/**
|
|
757
|
+
* v0.5.3 — iteration index for steps inside a `forEach` or `loop`
|
|
758
|
+
* primitive. Set when the parent ctx carries `_blokIterationIndex`
|
|
759
|
+
* (ForEachNode + LoopNode stash on each per-iteration child ctx).
|
|
760
|
+
* Studio's StepRail uses this to group consecutive sibling rows
|
|
761
|
+
* into "iteration N" sections instead of showing them flat with
|
|
762
|
+
* duplicated step names. Undefined for top-level steps and for
|
|
763
|
+
* inner steps of non-iteration primitives (`tryCatch`, `switch`).
|
|
764
|
+
*/
|
|
765
|
+
iterationIndex?: number;
|
|
182
766
|
}
|
|
183
767
|
export type WidgetType = "stat-card" | "timeline" | "error-rate" | "duration-distribution" | "workflow-breakdown" | "node-performance" | "recent-runs" | "heatmap";
|
|
184
768
|
export interface DashboardWidget {
|
|
@@ -208,10 +792,96 @@ export interface Dashboard {
|
|
|
208
792
|
updatedAt: number;
|
|
209
793
|
widgets: DashboardWidget[];
|
|
210
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* E2 — server-side saved filter for the runs list. Mirrors the
|
|
797
|
+
* earlier localStorage shape (`apps/studio/src/lib/savedFilters.ts`)
|
|
798
|
+
* with `id` + timestamps added. Filter names are UNIQUE across the
|
|
799
|
+
* deployment — re-saving overwrites the existing row. Studio applies
|
|
800
|
+
* them by setting the run-list filter UI from the stored values.
|
|
801
|
+
*/
|
|
802
|
+
export interface SavedFilter {
|
|
803
|
+
id: string;
|
|
804
|
+
name: string;
|
|
805
|
+
/** Workflow run status (`""` for "all"). */
|
|
806
|
+
status: string;
|
|
807
|
+
/**
|
|
808
|
+
* Free-form tag input as the user typed it ("env:prod,team:billing").
|
|
809
|
+
* Server stores it verbatim; the run-list URL parser interprets it.
|
|
810
|
+
*/
|
|
811
|
+
tagsInput: string;
|
|
812
|
+
/**
|
|
813
|
+
* Free-form metadata input as the user typed it
|
|
814
|
+
* ("tier=premium,region__in=us,eu"). Same parsing contract as the
|
|
815
|
+
* runs-page URL — `MetadataFilter[]` once parsed.
|
|
816
|
+
*/
|
|
817
|
+
metadataInput: string;
|
|
818
|
+
createdAt: number;
|
|
819
|
+
updatedAt: number;
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* Sample-body recording (v0.6 follow-up to #100). When a workflow's
|
|
823
|
+
* HTTP trigger declares `recordSample: true`, the trigger captures
|
|
824
|
+
* the request body of the FIRST successful run and persists it
|
|
825
|
+
* here. Studio's `examples.body` resolution prefers a recorded
|
|
826
|
+
* sample over static inference but always defers to an author-
|
|
827
|
+
* declared `trigger.http.examples.body`.
|
|
828
|
+
*
|
|
829
|
+
* One row per workflow — re-recording is intentionally skipped
|
|
830
|
+
* after the first capture so storage stays bounded + the
|
|
831
|
+
* operator-visible example stays stable. Authors can re-trigger a
|
|
832
|
+
* recording by deleting the row (no Studio surface for this yet;
|
|
833
|
+
* call `tracker.deleteWorkflowSample(name)` from a script).
|
|
834
|
+
*/
|
|
835
|
+
export interface WorkflowSample {
|
|
836
|
+
workflowName: string;
|
|
837
|
+
body: unknown;
|
|
838
|
+
/** Run id whose request body was captured. */
|
|
839
|
+
sourceRunId: string;
|
|
840
|
+
/** Wall-clock when the sample was recorded. */
|
|
841
|
+
recordedAt: number;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* F2 (v0.5) — operators accepted on metadata filters. `eq` is the
|
|
845
|
+
* default (and the only one available before v0.5). Each operator
|
|
846
|
+
* coerces values the way an operator typically would: numerical
|
|
847
|
+
* comparisons cast to number, `like` is SQL `LIKE` (with `%` /
|
|
848
|
+
* `_` wildcards), `in`/`nin` accept array values.
|
|
849
|
+
*/
|
|
850
|
+
export type MetadataOp = "eq" | "ne" | "gt" | "gte" | "lt" | "lte" | "like" | "in" | "nin";
|
|
851
|
+
/**
|
|
852
|
+
* F2 (v0.5) — operator-aware metadata filter. Combines with other
|
|
853
|
+
* filters in the same `RunQuery.metadata` array via AND semantics.
|
|
854
|
+
*
|
|
855
|
+
* `value` is `string` for scalar operators (`eq` / `ne` / `gt` / `lt` /
|
|
856
|
+
* `gte` / `lte` / `like`), `string[]` for set operators (`in` / `nin`).
|
|
857
|
+
* Numeric comparisons treat the stored metadata value as a number when
|
|
858
|
+
* possible (the underlying JSON store preserves the native type).
|
|
859
|
+
*/
|
|
860
|
+
export interface MetadataFilter {
|
|
861
|
+
key: string;
|
|
862
|
+
op: MetadataOp;
|
|
863
|
+
value: string | string[];
|
|
864
|
+
}
|
|
211
865
|
export interface RunQuery {
|
|
212
866
|
workflow?: string;
|
|
213
867
|
status?: WorkflowRunStatus;
|
|
214
868
|
tags?: string[];
|
|
869
|
+
/**
|
|
870
|
+
* Filter by metadata key/value pairs. Multiple entries combine with
|
|
871
|
+
* AND semantics (a run matches only when every declared filter is
|
|
872
|
+
* satisfied).
|
|
873
|
+
*
|
|
874
|
+
* **Two accepted shapes** — `Record<string, string>` is back-compat
|
|
875
|
+
* sugar for an array of `{key, op: "eq", value}` filters. Pass an
|
|
876
|
+
* array to use operators beyond `=` (F2: `ne` / `gt` / `gte` / `lt`
|
|
877
|
+
* / `lte` / `like` / `in` / `nin`). Both shapes route through the
|
|
878
|
+
* same evaluator after normalisation.
|
|
879
|
+
*
|
|
880
|
+
* **Performance** — sequential JSON-extract scan by default;
|
|
881
|
+
* declare hot keys via `BLOK_INDEXED_METADATA_KEYS=tier,region` to
|
|
882
|
+
* get an indexed column + index on the SqliteRunStore side (F1).
|
|
883
|
+
*/
|
|
884
|
+
metadata?: Record<string, string> | MetadataFilter[];
|
|
215
885
|
limit?: number;
|
|
216
886
|
offset?: number;
|
|
217
887
|
sort?: "asc" | "desc";
|