@blokjs/shared 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/__tests__/unit/NodeBase.test.ts +10 -9
- package/__tests__/unit/utils/Mapper.test.ts +301 -32
- package/__tests__/unit/utils/MapperResolutionError.test.ts +64 -0
- package/dist/NodeBase.d.ts +58 -11
- package/dist/NodeBase.js +79 -12
- package/dist/NodeBase.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/types/ConnectionContext.d.ts +79 -0
- package/dist/types/ConnectionContext.js +2 -0
- package/dist/types/ConnectionContext.js.map +1 -0
- package/dist/types/Context.d.ts +51 -0
- package/dist/types/StreamContext.d.ts +92 -0
- package/dist/types/StreamContext.js +2 -0
- package/dist/types/StreamContext.js.map +1 -0
- package/dist/utils/Mapper.d.ts +111 -2
- package/dist/utils/Mapper.js +256 -23
- package/dist/utils/Mapper.js.map +1 -1
- package/dist/utils/MapperResolutionError.d.ts +84 -0
- package/dist/utils/MapperResolutionError.js +61 -0
- package/dist/utils/MapperResolutionError.js.map +1 -0
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
package/dist/NodeBase.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _ from "lodash";
|
|
2
2
|
import GlobalError from "./GlobalError";
|
|
3
3
|
import mapper from "./utils/Mapper";
|
|
4
|
+
import { MapperResolutionError } from "./utils/MapperResolutionError";
|
|
4
5
|
export default class NodeBase {
|
|
5
6
|
flow = false;
|
|
6
7
|
name = "";
|
|
@@ -8,17 +9,6 @@ export default class NodeBase {
|
|
|
8
9
|
active = true;
|
|
9
10
|
stop = false;
|
|
10
11
|
originalConfig = {};
|
|
11
|
-
/**
|
|
12
|
-
* @deprecated v2 default-stores every step's output. `set_var: true` is
|
|
13
|
-
* a no-op (default behaviour); `set_var: false` is normalized to
|
|
14
|
-
* `ephemeral: true` at workflow load time. Reading this field is still
|
|
15
|
-
* supported for legacy code paths but new code should rely on `ephemeral`.
|
|
16
|
-
*
|
|
17
|
-
* Default is `undefined` (NOT `false`) — `false` here would short-circuit
|
|
18
|
-
* `PersistenceHelper.applyStepOutput` and disable the v2 default-store
|
|
19
|
-
* rule for every step that didn't explicitly set the field.
|
|
20
|
-
*/
|
|
21
|
-
set_var;
|
|
22
12
|
// =========================================================================
|
|
23
13
|
// V2 persistence knobs — populated by Configuration.getSteps from the
|
|
24
14
|
// step definition. Read by PersistenceHelper.applyStepOutput.
|
|
@@ -39,6 +29,75 @@ export default class NodeBase {
|
|
|
39
29
|
* Only `ctx.prev` carries the result to the immediately next step.
|
|
40
30
|
*/
|
|
41
31
|
ephemeral = false;
|
|
32
|
+
// =========================================================================
|
|
33
|
+
// V2 idempotency cache + retry knobs — populated by Configuration.getSteps
|
|
34
|
+
// from the step definition. Read by RunnerSteps before delegating to
|
|
35
|
+
// `step.process()`. Caching layers ABOVE PersistenceHelper.applyStepOutput;
|
|
36
|
+
// retry wraps the same call site.
|
|
37
|
+
//
|
|
38
|
+
// Mirrors the Zod schema in `@blokjs/helper/src/types/StepOpts.ts`. Kept
|
|
39
|
+
// as a structural interface here to avoid a runtime dep from shared on
|
|
40
|
+
// helper.
|
|
41
|
+
// =========================================================================
|
|
42
|
+
/**
|
|
43
|
+
* Optional cache key for this step's result. When set, the runner consults
|
|
44
|
+
* the idempotency cache before executing — a hit returns the cached result
|
|
45
|
+
* (and emits a NODE_CACHED event); a miss runs the step and caches its
|
|
46
|
+
* result on success. Cache namespace is (workflowName, name, idempotencyKey).
|
|
47
|
+
*
|
|
48
|
+
* Author-facing values may be a literal string ("user-123") or a $ proxy
|
|
49
|
+
* expression compiled to `js/ctx....`. The runner resolves the expression
|
|
50
|
+
* against the live ctx at run time before consulting the cache.
|
|
51
|
+
*/
|
|
52
|
+
idempotencyKey;
|
|
53
|
+
/**
|
|
54
|
+
* Optional cache lifetime in milliseconds. Defaults to 24 hours
|
|
55
|
+
* (86_400_000) when undefined. Pass 0 to mark a stored result as
|
|
56
|
+
* immediately expired (effectively disables caching for this step).
|
|
57
|
+
*/
|
|
58
|
+
idempotencyKeyTTL;
|
|
59
|
+
/**
|
|
60
|
+
* Optional retry configuration with capped exponential backoff. When
|
|
61
|
+
* undefined, the step runs at most once (matches pre-v0.3.x behaviour).
|
|
62
|
+
* Per-attempt failures emit `NODE_ATTEMPT_FAILED` trace events.
|
|
63
|
+
*/
|
|
64
|
+
retry;
|
|
65
|
+
/**
|
|
66
|
+
* Tier 2 quick-wins — per-attempt execution timeout in milliseconds.
|
|
67
|
+
* When set, `RunnerSteps` wraps each `step.process()` in a setTimeout-
|
|
68
|
+
* based Promise.race. On timeout, throws `StepTimeoutError` (which the
|
|
69
|
+
* retry loop treats as any other error). On final-attempt timeout,
|
|
70
|
+
* the run auto-flips to `"timedOut"` status. When undefined, the
|
|
71
|
+
* step runs without a per-attempt cap (matches pre-quick-wins
|
|
72
|
+
* behaviour).
|
|
73
|
+
*
|
|
74
|
+
* Originally set as a duration string or number on the step schema;
|
|
75
|
+
* `Configuration.getSteps` converts to milliseconds via
|
|
76
|
+
* `parseDuration` before assigning here.
|
|
77
|
+
*/
|
|
78
|
+
maxDurationMs;
|
|
79
|
+
// =========================================================================
|
|
80
|
+
// V2 sub-workflow knobs — populated by Configuration.getSteps for steps
|
|
81
|
+
// that invoke another workflow (`subworkflow: "<name>"` shape). Read by
|
|
82
|
+
// `SubworkflowNode.run()` to look up the child workflow in the
|
|
83
|
+
// WorkflowRegistry. Mirrors the Zod schema in `@blokjs/helper`.
|
|
84
|
+
// =========================================================================
|
|
85
|
+
/**
|
|
86
|
+
* Name of the workflow to invoke when this step runs. When set, the
|
|
87
|
+
* step's `node` ref is `"@blokjs/subworkflow"` (a sentinel) and the
|
|
88
|
+
* runner resolves it to a `SubworkflowNode` that looks up the child
|
|
89
|
+
* by this name in the `WorkflowRegistry` singleton.
|
|
90
|
+
*/
|
|
91
|
+
subworkflow;
|
|
92
|
+
/**
|
|
93
|
+
* If true (default), the parent step blocks until the child workflow
|
|
94
|
+
* completes. The child's `ctx.response` becomes the parent step's
|
|
95
|
+
* output (lands on `state[<id>]` like any other step).
|
|
96
|
+
*
|
|
97
|
+
* `wait: false` (fire-and-forget) is rejected at workflow load time
|
|
98
|
+
* in v0.3.x — the schema includes a deferred-feature error message.
|
|
99
|
+
*/
|
|
100
|
+
wait;
|
|
42
101
|
async process(ctx, step) {
|
|
43
102
|
let response = {
|
|
44
103
|
success: true,
|
|
@@ -106,7 +165,15 @@ export default class NodeBase {
|
|
|
106
165
|
mapper.replaceObjectStrings(newObj, ctx, data);
|
|
107
166
|
}
|
|
108
167
|
catch (e) {
|
|
109
|
-
|
|
168
|
+
// `MapperResolutionError` (strict mode) carries full diagnostic
|
|
169
|
+
// context — let it escape so the step's error envelope surfaces
|
|
170
|
+
// the workflow / step / expression that failed.
|
|
171
|
+
if (e instanceof MapperResolutionError)
|
|
172
|
+
throw e;
|
|
173
|
+
// Anything else here is an UNEXPECTED bug in the mapper itself
|
|
174
|
+
// (recursion fault, OOM, logger crash). Surface loudly via
|
|
175
|
+
// stderr WITH the stack trace — never silently swallow.
|
|
176
|
+
console.error("[blok][mapper] unexpected error during input resolution:", e);
|
|
110
177
|
}
|
|
111
178
|
return newObj;
|
|
112
179
|
};
|
package/dist/NodeBase.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeBase.js","sourceRoot":"","sources":["../src/NodeBase.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;AACvB,OAAO,WAAW,MAAM,eAAe,CAAC;AASxC,OAAO,MAAM,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"NodeBase.js","sourceRoot":"","sources":["../src/NodeBase.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,9 @@ import { Metrics, type MetricsType } from "./Metrics";
|
|
|
5
5
|
import NodeBase from "./NodeBase";
|
|
6
6
|
import Trigger from "./Trigger";
|
|
7
7
|
import ConfigContext from "./types/ConfigContext";
|
|
8
|
+
import type ConnectionContext from "./types/ConnectionContext";
|
|
8
9
|
import Context from "./types/Context";
|
|
10
|
+
import EnvContext from "./types/EnvContext";
|
|
9
11
|
import ErrorContext from "./types/ErrorContext";
|
|
10
12
|
import FunctionContext from "./types/FunctionContext";
|
|
11
13
|
import LoggerContext from "./types/LoggerContext";
|
|
@@ -14,6 +16,8 @@ import RequestContext from "./types/RequestContext";
|
|
|
14
16
|
import ResponseContext from "./types/ResponseContext";
|
|
15
17
|
import StateContext from "./types/StateContext";
|
|
16
18
|
import Step from "./types/Step";
|
|
19
|
+
import type StreamContext from "./types/StreamContext";
|
|
17
20
|
import VarsContext from "./types/VarsContext";
|
|
21
|
+
import mapper from "./utils/Mapper";
|
|
18
22
|
import MemoryUsage from "./utils/MemoryUsage";
|
|
19
|
-
export { NodeBase, Context, RequestContext, ResponseContext, ErrorContext, LoggerContext, ConfigContext, Trigger, NodeConfigContext, FunctionContext, StateContext, VarsContext, Step, GlobalLogger, GlobalError, BlokError, type BlokErrorOpts, type NodeErrorPayload, ErrorCategory, ErrorSeverity, DEFAULT_HTTP_STATUS, DEFAULT_RETRYABLE, Metrics, MemoryUsage, type MetricsType, };
|
|
23
|
+
export { NodeBase, Context, RequestContext, ResponseContext, EnvContext, ErrorContext, LoggerContext, ConfigContext, type ConnectionContext, type StreamContext, Trigger, NodeConfigContext, FunctionContext, StateContext, VarsContext, Step, GlobalLogger, GlobalError, BlokError, type BlokErrorOpts, type NodeErrorPayload, ErrorCategory, ErrorSeverity, DEFAULT_HTTP_STATUS, DEFAULT_RETRYABLE, Metrics, MemoryUsage, type MetricsType, mapper, };
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import GlobalLogger from "./GlobalLogger";
|
|
|
4
4
|
import { Metrics } from "./Metrics";
|
|
5
5
|
import NodeBase from "./NodeBase";
|
|
6
6
|
import Trigger from "./Trigger";
|
|
7
|
+
import mapper from "./utils/Mapper";
|
|
7
8
|
import MemoryUsage from "./utils/MemoryUsage";
|
|
8
|
-
export { NodeBase, Trigger, GlobalLogger, GlobalError, BlokError, ErrorCategory, ErrorSeverity, DEFAULT_HTTP_STATUS, DEFAULT_RETRYABLE, Metrics, MemoryUsage, };
|
|
9
|
+
export { NodeBase, Trigger, GlobalLogger, GlobalError, BlokError, ErrorCategory, ErrorSeverity, DEFAULT_HTTP_STATUS, DEFAULT_RETRYABLE, Metrics, MemoryUsage, mapper, };
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,EAAE,EAEjB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,aAAa,GAEb,MAAM,aAAa,CAAC;AACrB,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAoB,MAAM,WAAW,CAAC;AACtD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,OAAO,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,EAAE,EAEjB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,aAAa,GAEb,MAAM,aAAa,CAAC;AACrB,OAAO,WAAW,MAAM,eAAe,CAAC;AACxC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAoB,MAAM,WAAW,CAAC;AACtD,OAAO,QAAQ,MAAM,YAAY,CAAC;AAClC,OAAO,OAAO,MAAM,WAAW,CAAC;AAehC,OAAO,MAAM,MAAM,gBAAgB,CAAC;AACpC,OAAO,WAAW,MAAM,qBAAqB,CAAC;AAE9C,OAAO,EACN,QAAQ,EAUR,OAAO,EAMP,YAAY,EACZ,WAAW,EACX,SAAS,EAGT,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,iBAAiB,EACjB,OAAO,EACP,WAAW,EAEX,MAAM,GACN,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.7 — per-connection API exposed on `ctx.connection` for triggers
|
|
3
|
+
* that hold long-lived bidirectional channels (WebSocket today; SSE
|
|
4
|
+
* gets a streaming variant in PR 3).
|
|
5
|
+
*
|
|
6
|
+
* Authors interact with the connection through this object — the
|
|
7
|
+
* trigger wraps the underlying transport's send/close primitives and
|
|
8
|
+
* tracks per-connection state. Lifecycle:
|
|
9
|
+
*
|
|
10
|
+
* - On `connect`: trigger creates the connection, runs the workflow
|
|
11
|
+
* once with `ctx.connection` bound. Author can call
|
|
12
|
+
* `setAttachment()` to store per-connection state.
|
|
13
|
+
* - On `message`: trigger runs the workflow again with the same
|
|
14
|
+
* `ctx.connection` instance — author reads `attachment` to recover
|
|
15
|
+
* the per-connection state.
|
|
16
|
+
* - On `disconnect`: same connection, last run. Cleanup happens here.
|
|
17
|
+
*
|
|
18
|
+
* Absent on contexts built for HTTP / Worker / Cron triggers.
|
|
19
|
+
*/
|
|
20
|
+
export interface ConnectionContext {
|
|
21
|
+
/** Stable connection identifier (uuid). Set once at connect. */
|
|
22
|
+
readonly id: string;
|
|
23
|
+
/**
|
|
24
|
+
* Send data to THIS connection.
|
|
25
|
+
* - Text payloads: send a string (typically `JSON.stringify(...)`).
|
|
26
|
+
* - Binary payloads: send a `Uint8Array` or `ArrayBuffer`.
|
|
27
|
+
*
|
|
28
|
+
* Buffered if the underlying socket is busy; backpressure visible
|
|
29
|
+
* via the trigger's `messageRateLimit` and Studio trace metrics.
|
|
30
|
+
*/
|
|
31
|
+
send(data: string | ArrayBuffer | Uint8Array): void;
|
|
32
|
+
/**
|
|
33
|
+
* Close THIS connection cleanly. Subsequent `send` calls are no-ops.
|
|
34
|
+
* Triggers the `disconnect` workflow run as a final step.
|
|
35
|
+
*
|
|
36
|
+
* @param code Close code per RFC 6455 (default 1000 — normal).
|
|
37
|
+
* @param reason Human-readable reason (max 123 bytes per RFC).
|
|
38
|
+
*/
|
|
39
|
+
close(code?: number, reason?: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Store per-connection state. Survives across message-event workflow
|
|
42
|
+
* runs on the same connection — the "userId + joinedAt + cursor"
|
|
43
|
+
* pattern. Reset by every call (no merge).
|
|
44
|
+
*
|
|
45
|
+
* Inspired by Cloudflare Durable Objects'
|
|
46
|
+
* `state.serializeAttachment()` API. Capped at 2 KB serialized JSON;
|
|
47
|
+
* larger values are rejected with a warning log (the connection
|
|
48
|
+
* stays open).
|
|
49
|
+
*/
|
|
50
|
+
setAttachment(value: unknown): void;
|
|
51
|
+
/**
|
|
52
|
+
* Retrieve per-connection state set by `setAttachment()`. Returns
|
|
53
|
+
* `undefined` if nothing was set on this connection.
|
|
54
|
+
*/
|
|
55
|
+
readonly attachment: unknown;
|
|
56
|
+
/**
|
|
57
|
+
* Channel/room membership for fan-out broadcasts. Multiple
|
|
58
|
+
* connections can join the same room; `@blokjs/ws-broadcast`
|
|
59
|
+
* targets every member.
|
|
60
|
+
*/
|
|
61
|
+
joinRoom(name: string): void;
|
|
62
|
+
leaveRoom(name: string): void;
|
|
63
|
+
readonly rooms: ReadonlySet<string>;
|
|
64
|
+
/**
|
|
65
|
+
* v0.7 — broadcast a message to every connection in the named
|
|
66
|
+
* room (workflow-scoped). Returns the number of recipients
|
|
67
|
+
* the trigger successfully sent to.
|
|
68
|
+
*
|
|
69
|
+
* Set `exceptSelf: true` to skip the connection that triggered
|
|
70
|
+
* the current workflow run (the "send to everyone except me"
|
|
71
|
+
* pattern). Bound by the trigger via this `ctx.connection`
|
|
72
|
+
* accessor so helper nodes (`@blokjs/ws-broadcast`) don't need
|
|
73
|
+
* to import the trigger package directly.
|
|
74
|
+
*/
|
|
75
|
+
broadcast(room: string, data: string | ArrayBuffer | Uint8Array, opts?: {
|
|
76
|
+
exceptSelf?: boolean;
|
|
77
|
+
}): number;
|
|
78
|
+
}
|
|
79
|
+
export default ConnectionContext;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConnectionContext.js","sourceRoot":"","sources":["../../src/types/ConnectionContext.ts"],"names":[],"mappings":""}
|
package/dist/types/Context.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type GlobalLogger from "../GlobalLogger";
|
|
2
2
|
import type ConfigContext from "./ConfigContext";
|
|
3
|
+
import type ConnectionContext from "./ConnectionContext";
|
|
3
4
|
import type EnvContext from "./EnvContext";
|
|
4
5
|
import type ErrorContext from "./ErrorContext";
|
|
5
6
|
import type FunctionContext from "./FunctionContext";
|
|
@@ -7,6 +8,7 @@ import type LoggerContext from "./LoggerContext";
|
|
|
7
8
|
import type RequestContext from "./RequestContext";
|
|
8
9
|
import type ResponseContext from "./ResponseContext";
|
|
9
10
|
import type StateContext from "./StateContext";
|
|
11
|
+
import type StreamContext from "./StreamContext";
|
|
10
12
|
import type VarsContext from "./VarsContext";
|
|
11
13
|
/**
|
|
12
14
|
* The runtime context for a single workflow execution. One Context object
|
|
@@ -94,6 +96,55 @@ type Context = {
|
|
|
94
96
|
* publish something other than its return value (most nodes don't).
|
|
95
97
|
*/
|
|
96
98
|
publish?: (name: string, value: unknown) => void;
|
|
99
|
+
/**
|
|
100
|
+
* Tier 2 follow-up · cooperative cancellation. AbortSignal whose
|
|
101
|
+
* `aborted` flips to true when an operator cancels the run via
|
|
102
|
+
* `POST /__blok/runs/:runId/cancel` while it's in `running` status.
|
|
103
|
+
*
|
|
104
|
+
* Nodes that perform long-running work (loops, fetch, db queries)
|
|
105
|
+
* should consult `ctx.signal.aborted` periodically and abort early
|
|
106
|
+
* — or pass the signal to fetch/abort-aware APIs:
|
|
107
|
+
*
|
|
108
|
+
* await fetch(url, { signal: ctx.signal });
|
|
109
|
+
* if (ctx.signal?.aborted) throw new Error("aborted");
|
|
110
|
+
*
|
|
111
|
+
* Always present on contexts created by `TriggerBase.createContext`.
|
|
112
|
+
* Optional on the type for back-compat with hand-built contexts in
|
|
113
|
+
* tests.
|
|
114
|
+
*/
|
|
115
|
+
signal?: AbortSignal;
|
|
116
|
+
/**
|
|
117
|
+
* v0.7 — per-connection API for long-lived bidirectional triggers
|
|
118
|
+
* (WebSocket). Present on contexts dispatched by `WebSocketTrigger`;
|
|
119
|
+
* absent on HTTP / Worker / Cron contexts.
|
|
120
|
+
*
|
|
121
|
+
* Authors call `ctx.connection.send(...)` to push to the specific
|
|
122
|
+
* connection that fired the event, `ctx.connection.close(...)` to
|
|
123
|
+
* terminate it, or `ctx.connection.setAttachment(...)` to store
|
|
124
|
+
* per-connection state that survives across the connect → N×message
|
|
125
|
+
* → disconnect lifecycle.
|
|
126
|
+
*
|
|
127
|
+
* Helper nodes (`@blokjs/ws-reply`, `@blokjs/ws-broadcast`,
|
|
128
|
+
* `@blokjs/ws-close`) read this field to interact with the
|
|
129
|
+
* connection without authors having to thread the ws handle through
|
|
130
|
+
* step inputs.
|
|
131
|
+
*/
|
|
132
|
+
connection?: ConnectionContext;
|
|
133
|
+
/**
|
|
134
|
+
* v0.7 — per-stream API for server-push HTTP triggers (SSE).
|
|
135
|
+
* Present on contexts dispatched by `SSETrigger` once per stream
|
|
136
|
+
* open; absent on HTTP / WebSocket / Worker / Cron contexts.
|
|
137
|
+
*
|
|
138
|
+
* Authors call `ctx.stream.writeSSE({ event, data, id, retry })`
|
|
139
|
+
* to emit frames, `ctx.stream.close()` to end the stream, and
|
|
140
|
+
* read `ctx.stream.signal.aborted` to detect client disconnects
|
|
141
|
+
* inside long-running loops.
|
|
142
|
+
*
|
|
143
|
+
* Helper nodes (`@blokjs/sse-stream`) read this field so workflow
|
|
144
|
+
* authors don't have to thread the stream handle through step
|
|
145
|
+
* inputs.
|
|
146
|
+
*/
|
|
147
|
+
stream?: StreamContext;
|
|
97
148
|
_PRIVATE_: unknown;
|
|
98
149
|
};
|
|
99
150
|
export default Context;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.7 — per-stream API exposed on `ctx.stream` for triggers that hold
|
|
3
|
+
* a long-lived, server-push HTTP channel (SSE today; the `streaming`
|
|
4
|
+
* Hono helper underneath). Authors emit events through this object;
|
|
5
|
+
* the trigger owns the underlying `c.writeSSE` / drain handling.
|
|
6
|
+
*
|
|
7
|
+
* Lifecycle (Pattern A — one workflow run per stream open):
|
|
8
|
+
*
|
|
9
|
+
* - The SSE trigger opens the HTTP stream via Hono's `streamSSE`,
|
|
10
|
+
* creates this object, attaches it to `ctx.stream`, and dispatches
|
|
11
|
+
* the workflow once.
|
|
12
|
+
* - The workflow body writes zero or more events via
|
|
13
|
+
* `writeSSE(...)`, typically via `@blokjs/sse-stream` consuming an
|
|
14
|
+
* async iterator from `@blokjs/sse-subscribe`.
|
|
15
|
+
* - The workflow returns when its iterator ends OR when
|
|
16
|
+
* `ctx.stream.signal.aborted` flips (client closed). The trigger
|
|
17
|
+
* ends the run with status `completed`.
|
|
18
|
+
*
|
|
19
|
+
* Absent on contexts built for HTTP (request/response), Worker, Cron,
|
|
20
|
+
* or WebSocket triggers.
|
|
21
|
+
*/
|
|
22
|
+
export interface StreamContext {
|
|
23
|
+
/** Stable stream/connection identifier (uuid). Set once at open. */
|
|
24
|
+
readonly id: string;
|
|
25
|
+
/**
|
|
26
|
+
* Write one SSE-framed event to the client. Each call produces a
|
|
27
|
+
* `data:` (and optional `event:`, `id:`, `retry:`) frame followed
|
|
28
|
+
* by a blank line.
|
|
29
|
+
*
|
|
30
|
+
* `data` is JSON-stringified when it's not a string. Pass a string
|
|
31
|
+
* to write the payload verbatim. Returns once the chunk has been
|
|
32
|
+
* accepted by Node's stream (honors backpressure via `drain`).
|
|
33
|
+
*/
|
|
34
|
+
writeSSE(opts: {
|
|
35
|
+
event?: string;
|
|
36
|
+
data: unknown;
|
|
37
|
+
id?: string;
|
|
38
|
+
retry?: number;
|
|
39
|
+
}): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Write an SSE comment line (`: <text>\n\n`). Used internally for
|
|
42
|
+
* heartbeats; authors rarely need this directly. Comments are
|
|
43
|
+
* ignored by `EventSource` clients but keep proxies from idling
|
|
44
|
+
* the connection.
|
|
45
|
+
*/
|
|
46
|
+
writeComment(text: string): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Close the stream cleanly. Subsequent `writeSSE` calls are no-ops.
|
|
49
|
+
* The workflow run ends at the next yield point.
|
|
50
|
+
*/
|
|
51
|
+
close(): void;
|
|
52
|
+
/** True after `close()` is called or the client disconnects. */
|
|
53
|
+
readonly closed: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* `AbortSignal` that fires when the client disconnects (browser tab
|
|
56
|
+
* closed, network drop, manual `EventSource.close()`). Long-running
|
|
57
|
+
* iterators / fetches should be bound to this signal so they unwind
|
|
58
|
+
* promptly:
|
|
59
|
+
*
|
|
60
|
+
* for await (const evt of source) {
|
|
61
|
+
* if (ctx.stream.signal.aborted) break;
|
|
62
|
+
* await ctx.stream.writeSSE({ data: evt });
|
|
63
|
+
* }
|
|
64
|
+
*/
|
|
65
|
+
readonly signal: AbortSignal;
|
|
66
|
+
/**
|
|
67
|
+
* `Last-Event-Id` HTTP header value from the inbound request, if
|
|
68
|
+
* the client is reconnecting. Helper nodes (`@blokjs/sse-subscribe`)
|
|
69
|
+
* read this to resume from the indicated cursor.
|
|
70
|
+
*/
|
|
71
|
+
readonly lastEventId: string | null;
|
|
72
|
+
/**
|
|
73
|
+
* v0.7 — subscribe to the in-process SSE event bus. Returns an
|
|
74
|
+
* async iterator that yields events published to any of the named
|
|
75
|
+
* channels. When `lastEventId` is provided (or omitted — defaults
|
|
76
|
+
* to `ctx.stream.lastEventId`), buffered events with `seq > lastEventId`
|
|
77
|
+
* are replayed before live events begin. Caller stops the
|
|
78
|
+
* subscription by exiting the for-await loop or calling
|
|
79
|
+
* `iterator.return()`.
|
|
80
|
+
*
|
|
81
|
+
* Bound by the trigger so helper nodes (`@blokjs/sse-subscribe`,
|
|
82
|
+
* `@blokjs/sse-stream`) don't have to import the trigger directly.
|
|
83
|
+
*/
|
|
84
|
+
subscribe(channels: string[], lastEventId?: string | null): AsyncIterableIterator<{
|
|
85
|
+
channel: string;
|
|
86
|
+
id: string;
|
|
87
|
+
event?: string;
|
|
88
|
+
data: unknown;
|
|
89
|
+
timestamp: number;
|
|
90
|
+
}>;
|
|
91
|
+
}
|
|
92
|
+
export default StreamContext;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamContext.js","sourceRoot":"","sources":["../../src/types/StreamContext.ts"],"names":[],"mappings":""}
|
package/dist/utils/Mapper.d.ts
CHANGED
|
@@ -1,10 +1,119 @@
|
|
|
1
1
|
import type Context from "../types/Context";
|
|
2
2
|
import type ParamsDictionary from "../types/ParamsDictionary";
|
|
3
|
+
/**
|
|
4
|
+
* Mapper — the workflow input resolver.
|
|
5
|
+
*
|
|
6
|
+
* Every step's `inputs` object is walked by `replaceObjectStrings`
|
|
7
|
+
* before the step runs (see `NodeBase.process` → `blueprintMapper`).
|
|
8
|
+
* Two template syntaxes are recognised:
|
|
9
|
+
*
|
|
10
|
+
* 1. **`${path.to.value}`** — interpolated string placeholder.
|
|
11
|
+
* Resolved via lodash `_.get(data, key)` first, with a JS-eval
|
|
12
|
+
* fallback when the key is not in `data`. Multiple placeholders
|
|
13
|
+
* in one string are concatenated.
|
|
14
|
+
*
|
|
15
|
+
* 2. **`"js/..."`** — full-string JS expression. The string is
|
|
16
|
+
* replaced ENTIRELY by the result of evaluating the expression
|
|
17
|
+
* (after stripping the `js/` prefix) against the live `ctx`.
|
|
18
|
+
* Returns whatever value the expression produces (string, number,
|
|
19
|
+
* object, array, etc.) — preserves type fidelity end-to-end.
|
|
20
|
+
*
|
|
21
|
+
* Both syntaxes evaluate inside a sandboxed `Function` with these
|
|
22
|
+
* names in scope: `ctx`, `data`, `func`, `vars`. (Symmetric scope
|
|
23
|
+
* across both syntaxes since v0.3.x — pre-v0.3.x `${...}` evaluator
|
|
24
|
+
* lacked `func`+`vars`, leading to surprising scope mismatches.)
|
|
25
|
+
*
|
|
26
|
+
* ## Failure modes — see {@link MapperResolutionError}
|
|
27
|
+
*
|
|
28
|
+
* Resolution failures (typo, undefined access, syntax error) used to
|
|
29
|
+
* be swallowed silently with a noisy `console.log("Mapper Error N", e)`
|
|
30
|
+
* — and worse, the unresolved expression string passed through to the
|
|
31
|
+
* node, producing silent miscompiles downstream. Since v0.3.x the
|
|
32
|
+
* Mapper packages every failure in a `MapperResolutionError` with full
|
|
33
|
+
* context (workflow, step, expression, underlying cause + heuristic
|
|
34
|
+
* hint) and routes it according to `BLOK_MAPPER_MODE`:
|
|
35
|
+
*
|
|
36
|
+
* - `"warn"` (default) — log via `ctx.logger.logLevel("warn", ...)`,
|
|
37
|
+
* pass through the original string. Backward-compatible diagnostics.
|
|
38
|
+
* - `"strict"` — throw the error, fail the step fast. **Recommended
|
|
39
|
+
* for production.**
|
|
40
|
+
* - `"silent"` — full suppression. Tests / opt-out only.
|
|
41
|
+
*
|
|
42
|
+
* ## Bug fixes shipped alongside the diagnostic upgrade (v0.3.x)
|
|
43
|
+
*
|
|
44
|
+
* - **Falsy values now preserved** — `_.get(data, key) || runJs(...)`
|
|
45
|
+
* used to fall through to `runJs` when the lookup returned `0`,
|
|
46
|
+
* `false`, `null`, or `""` (all valid values incorrectly treated
|
|
47
|
+
* as missing). Now uses an explicit `=== undefined` check.
|
|
48
|
+
* - **Object interpolation now JSON-encodes** — `value as string`
|
|
49
|
+
* used to produce `"[object Object]"` for object values. Now
|
|
50
|
+
* round-trips via `JSON.stringify`.
|
|
51
|
+
* - **`js/` prefix stripping** uses `slice(3)` instead of
|
|
52
|
+
* `replace("js/", "")` (the latter only strips the FIRST
|
|
53
|
+
* occurrence — fragile if the expression itself contained `js/`).
|
|
54
|
+
*/
|
|
55
|
+
/**
|
|
56
|
+
* How the Mapper reacts to expression resolution failures. Read from
|
|
57
|
+
* the `BLOK_MAPPER_MODE` env var at every call (no caching) so unit
|
|
58
|
+
* tests can flip the mode between cases.
|
|
59
|
+
*/
|
|
60
|
+
export type MapperMode = "warn" | "strict" | "silent";
|
|
3
61
|
declare class Mapper {
|
|
62
|
+
/**
|
|
63
|
+
* Walk an object recursively, resolving every string value via
|
|
64
|
+
* `replaceString`. Mutates in place. Used by `NodeBase.process` to
|
|
65
|
+
* resolve a step's `inputs` against the live `ctx` before the
|
|
66
|
+
* step runs.
|
|
67
|
+
*
|
|
68
|
+
* Object/array values are recursed into; primitive non-string
|
|
69
|
+
* values are left untouched. Null values are NOT recursed (avoids
|
|
70
|
+
* a TypeError on `for (const k in null)`).
|
|
71
|
+
*/
|
|
4
72
|
replaceObjectStrings(obj: ParamsDictionary, ctx: Context, data: ParamsDictionary): void;
|
|
5
|
-
|
|
6
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Resolve a single string. Returns `unknown` because a `js/...`
|
|
75
|
+
* expression may yield any value (number, object, array, etc.) —
|
|
76
|
+
* type fidelity is preserved across the resolver boundary.
|
|
77
|
+
*
|
|
78
|
+
* Pre-v0.3.x return was typed as `string` via `as string` cast
|
|
79
|
+
* which was a type lie; downstream consumers received the actual
|
|
80
|
+
* runtime value but couldn't see it through the type system.
|
|
81
|
+
*/
|
|
82
|
+
replaceString: (strData: string, ctx: Context, data: ParamsDictionary) => unknown;
|
|
83
|
+
/**
|
|
84
|
+
* Resolve a `${path}` expression. Lodash lookup first; JS-eval
|
|
85
|
+
* fallback when the path is not in `data`. Returns the resolved
|
|
86
|
+
* value OR the failure sentinel.
|
|
87
|
+
*/
|
|
88
|
+
private resolveTemplateExpression;
|
|
89
|
+
/**
|
|
90
|
+
* Evaluate a `js/...` full-string expression. Returns whatever the
|
|
91
|
+
* expression produces (any type), or — in warn/silent mode on
|
|
92
|
+
* failure — the original literal `js/...` string.
|
|
93
|
+
*
|
|
94
|
+
* Strict-mode failures throw `MapperResolutionError`.
|
|
95
|
+
*/
|
|
7
96
|
private jsMapper;
|
|
97
|
+
/**
|
|
98
|
+
* Apply the configured mode (`BLOK_MAPPER_MODE`) to a resolution
|
|
99
|
+
* failure. In strict mode, the error escapes here and propagates
|
|
100
|
+
* up through `replaceString` → `NodeBase.blueprintMapper` →
|
|
101
|
+
* `NodeBase.process` → step error envelope.
|
|
102
|
+
*/
|
|
103
|
+
private handleResolutionError;
|
|
104
|
+
/**
|
|
105
|
+
* Sandboxed JS evaluation. Compiles the expression as a function
|
|
106
|
+
* body returning the expression value; binds `ctx`, `data`, `func`,
|
|
107
|
+
* `vars` as positional arguments; runs in `"use strict"` mode.
|
|
108
|
+
*
|
|
109
|
+
* Throws on any evaluation error (typo, undefined access, syntax,
|
|
110
|
+
* unknown identifier). Callers wrap in try/catch and translate to
|
|
111
|
+
* `MapperResolutionError`.
|
|
112
|
+
*
|
|
113
|
+
* Public via the prototype but documented as internal — the only
|
|
114
|
+
* supported call sites are inside this class.
|
|
115
|
+
*/
|
|
116
|
+
private runJs;
|
|
8
117
|
}
|
|
9
118
|
declare const _default: Mapper;
|
|
10
119
|
export default _default;
|