@voyantjs/workflows 0.107.4 → 0.107.6

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.
@@ -1,4 +1,20 @@
1
1
  export declare const AUTH_HEADER: "x-voyant-dispatch-auth";
2
+ /**
3
+ * HMAC header carried on orchestrator → node-step-container dispatches
4
+ * (`POST /step`). Signed over the raw request body with the shared
5
+ * `VOYANT_WORKFLOW_STEP_AUTH_SECRET`. See `createCfContainerStepRunner`
6
+ * (signing side) and `apps/workflows-node-step-container` (verifying side).
7
+ */
8
+ export declare const STEP_AUTH_HEADER: "x-voyant-step-auth";
9
+ /**
10
+ * HMAC header returned by the node-step-container on successful `/step`
11
+ * responses. Signed over the raw JSON response body with the same
12
+ * `VOYANT_WORKFLOW_STEP_AUTH_SECRET` so the orchestrator can reject
13
+ * forged step journal entries before committing run state.
14
+ */
15
+ export declare const STEP_RESPONSE_AUTH_HEADER: "x-voyant-step-response-auth";
16
+ /** Parse a comma-separated token/origin list env var into trimmed, non-empty entries. */
17
+ export declare function parseTokenList(raw: string | null | undefined): string[];
2
18
  /**
3
19
  * Returns a verifier that accepts `Authorization: Bearer <token>`
4
20
  * where `<token>` matches any of the `validTokens` (case-sensitive,
@@ -10,6 +26,58 @@ export declare const AUTH_HEADER: "x-voyant-dispatch-auth";
10
26
  * issue per-tenant, short-lived tokens from a control plane.
11
27
  */
12
28
  export declare function createBearerVerifier(validTokens: readonly string[]): (req: Request) => void;
29
+ /**
30
+ * Error thrown by verifiers produced in this module. Carries an HTTP
31
+ * `status` + machine-readable `code` so HTTP surfaces
32
+ * (`handleWorkerRequest`, the node dashboard server, step handlers)
33
+ * can map auth failures to the right response instead of a blanket 401.
34
+ */
35
+ export declare class RequestAuthError extends Error {
36
+ readonly status: number;
37
+ readonly code: string;
38
+ constructor(status: number, code: string, message: string);
39
+ }
40
+ export type BearerAuthDecision = {
41
+ ok: true;
42
+ } | {
43
+ ok: false;
44
+ status: number;
45
+ error: string;
46
+ message: string;
47
+ };
48
+ export interface BearerAuthOptions {
49
+ /** Accepted bearer tokens. Empty/undefined = no auth configured. */
50
+ tokens?: readonly string[];
51
+ /**
52
+ * Explicit local-dev opt-out. When `true` AND no tokens are
53
+ * configured, requests are allowed through with a loud warning.
54
+ * When `false`/unset and no tokens are configured, every request is
55
+ * rejected with 503 `auth_not_configured` (fail closed).
56
+ */
57
+ allowUnauthenticated?: boolean;
58
+ /** Warning sink for the unauthenticated opt-out. Defaults to `console.warn`. */
59
+ warn?: (message: string) => void;
60
+ }
61
+ /**
62
+ * Build a transport-agnostic bearer authorizer from a raw
63
+ * `Authorization` header value. Fail-closed semantics:
64
+ *
65
+ * - tokens configured → exact (constant-time) Bearer match or 401
66
+ * - no tokens + opt-out → always allowed (warns loudly once, at creation)
67
+ * - no tokens, no opt-out → always 503 `auth_not_configured`
68
+ */
69
+ export declare function createBearerAuthorizer(opts: BearerAuthOptions): (authorizationHeader: string | null | undefined) => BearerAuthDecision;
70
+ /**
71
+ * Resolve a `verifyRequest` hook (the dep consumed by
72
+ * `handleWorkerRequest` / `createStepHandler`) with fail-closed
73
+ * defaults — the missing-token case yields a verifier that rejects
74
+ * every request with a 503 `auth_not_configured` `RequestAuthError`
75
+ * instead of `undefined` (which would skip auth entirely).
76
+ *
77
+ * Returns `undefined` (auth skipped) ONLY when no tokens are
78
+ * configured AND `allowUnauthenticated` is explicitly set.
79
+ */
80
+ export declare function resolveRequestVerifier(opts: BearerAuthOptions): ((req: Request) => void) | undefined;
13
81
  /** Returns a signer: `(body: string) => Promise<string>` (base64 HMAC-SHA256). */
14
82
  export declare function createHmacSigner(secret: string): Promise<(body: string) => Promise<string>>;
15
83
  /**
@@ -23,4 +91,35 @@ export declare function createHmacSigner(secret: string): Promise<(body: string)
23
91
  * passing in.
24
92
  */
25
93
  export declare function createHmacVerifier(secret: string): Promise<(req: Request) => Promise<void>>;
94
+ /**
95
+ * Returns a verifier over a raw body string + detached base64 HMAC
96
+ * signature (the value of `STEP_AUTH_HEADER`). Suitable for servers
97
+ * that have already buffered the request body (e.g. the node step
98
+ * container). `crypto.subtle.verify` is constant-time; malformed
99
+ * base64 or a missing signature simply yields `false`.
100
+ */
101
+ export declare function createHmacBodyVerifier(secret: string): Promise<(body: string, signatureBase64: string | null | undefined) => Promise<boolean>>;
102
+ export type BundleUrlDecision = {
103
+ ok: true;
104
+ } | {
105
+ ok: false;
106
+ message: string;
107
+ };
108
+ /**
109
+ * Build an origin allowlist check for caller-supplied `bundle.url`
110
+ * values (the node step container dynamically `import()`s the fetched
111
+ * bytes, so an unrestricted URL is remote-code-execution-adjacent —
112
+ * the SHA-256 hash pin is supplied by the same caller and is not a
113
+ * security control on its own).
114
+ *
115
+ * - `allowedOrigins` set (e.g. from `VOYANT_BUNDLE_ALLOWED_ORIGINS`):
116
+ * the URL's origin must match one of the entries exactly.
117
+ * Invalid entries throw at creation time (misconfiguration should
118
+ * fail loudly, not silently widen).
119
+ * - unset/empty: only HTTPS URLs on `*.r2.cloudflarestorage.com`
120
+ * are allowed — the production bundle source.
121
+ */
122
+ export declare function createBundleUrlPolicy(opts?: {
123
+ allowedOrigins?: readonly string[];
124
+ }): (url: string) => BundleUrlDecision;
26
125
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,WAAW,EAAG,wBAAiC,CAAA;AAE5D;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAiB3F;AAWD,kFAAkF;AAClF,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAMjG;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAmBjG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,WAAW,EAAG,wBAAiC,CAAA;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAG,oBAA6B,CAAA;AAE7D;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAG,6BAAsC,CAAA;AAE/E,yFAAyF;AACzF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,CAKvE;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAiB3F;AAoBD;;;;;GAKG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;gBAET,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAM1D;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjE,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,gFAAgF;IAChF,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC;AAQD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,iBAAiB,GACtB,CAAC,mBAAmB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,kBAAkB,CA8CxE;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,iBAAiB,GACtB,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,SAAS,CAatC;AAED,kFAAkF;AAClF,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAMjG;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAmBjG;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAYzF;AAID,MAAM,MAAM,iBAAiB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAW7E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,CAAC,EAAE;IAC3C,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CACnC,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,iBAAiB,CAsCrC"}
@@ -22,6 +22,27 @@
22
22
  // const verify = await createHmacVerifier(env.VOYANT_SIGNING_KEY);
23
23
  // export default { fetch: createStepHandler({ verifyRequest: verify }) };
24
24
  export const AUTH_HEADER = "x-voyant-dispatch-auth";
25
+ /**
26
+ * HMAC header carried on orchestrator → node-step-container dispatches
27
+ * (`POST /step`). Signed over the raw request body with the shared
28
+ * `VOYANT_WORKFLOW_STEP_AUTH_SECRET`. See `createCfContainerStepRunner`
29
+ * (signing side) and `apps/workflows-node-step-container` (verifying side).
30
+ */
31
+ export const STEP_AUTH_HEADER = "x-voyant-step-auth";
32
+ /**
33
+ * HMAC header returned by the node-step-container on successful `/step`
34
+ * responses. Signed over the raw JSON response body with the same
35
+ * `VOYANT_WORKFLOW_STEP_AUTH_SECRET` so the orchestrator can reject
36
+ * forged step journal entries before committing run state.
37
+ */
38
+ export const STEP_RESPONSE_AUTH_HEADER = "x-voyant-step-response-auth";
39
+ /** Parse a comma-separated token/origin list env var into trimmed, non-empty entries. */
40
+ export function parseTokenList(raw) {
41
+ return (raw ?? "")
42
+ .split(",")
43
+ .map((s) => s.trim())
44
+ .filter((s) => s.length > 0);
45
+ }
25
46
  /**
26
47
  * Returns a verifier that accepts `Authorization: Bearer <token>`
27
48
  * where `<token>` matches any of the `validTokens` (case-sensitive,
@@ -52,15 +73,123 @@ export function createBearerVerifier(validTokens) {
52
73
  throw new Error("bearer token does not match any configured value");
53
74
  };
54
75
  }
76
+ /**
77
+ * Constant-time string comparison. Does NOT early-return on length
78
+ * mismatch: the loop always runs over the longer input (out-of-range
79
+ * `charCodeAt` is NaN, which coerces to 0 under bitwise ops), and a
80
+ * length mismatch only sets a diff bit. This avoids leaking how many
81
+ * leading characters of a secret matched, or whether the length matched.
82
+ */
55
83
  function constantTimeEquals(a, b) {
56
- if (a.length !== b.length)
57
- return false;
58
- let diff = 0;
59
- for (let i = 0; i < a.length; i++) {
60
- diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
84
+ const length = Math.max(a.length, b.length, 1);
85
+ let diff = a.length === b.length ? 0 : 1;
86
+ for (let i = 0; i < length; i++) {
87
+ diff |= (a.charCodeAt(i) | 0) ^ (b.charCodeAt(i) | 0);
61
88
  }
62
89
  return diff === 0;
63
90
  }
91
+ // ---- Fail-closed bearer auth resolution ----
92
+ /**
93
+ * Error thrown by verifiers produced in this module. Carries an HTTP
94
+ * `status` + machine-readable `code` so HTTP surfaces
95
+ * (`handleWorkerRequest`, the node dashboard server, step handlers)
96
+ * can map auth failures to the right response instead of a blanket 401.
97
+ */
98
+ export class RequestAuthError extends Error {
99
+ status;
100
+ code;
101
+ constructor(status, code, message) {
102
+ super(message);
103
+ this.name = "RequestAuthError";
104
+ this.status = status;
105
+ this.code = code;
106
+ }
107
+ }
108
+ const UNAUTHENTICATED_WARNING = "[voyant-workflows] AUTH DISABLED: no bearer tokens are configured and " +
109
+ "VOYANT_WORKFLOWS_ALLOW_UNAUTHENTICATED is set. Every caller can trigger, read, " +
110
+ "resume, and cancel workflow runs. This mode is for LOCAL DEVELOPMENT ONLY — " +
111
+ "configure VOYANT_API_TOKENS before deploying.";
112
+ /**
113
+ * Build a transport-agnostic bearer authorizer from a raw
114
+ * `Authorization` header value. Fail-closed semantics:
115
+ *
116
+ * - tokens configured → exact (constant-time) Bearer match or 401
117
+ * - no tokens + opt-out → always allowed (warns loudly once, at creation)
118
+ * - no tokens, no opt-out → always 503 `auth_not_configured`
119
+ */
120
+ export function createBearerAuthorizer(opts) {
121
+ const tokens = (opts.tokens ?? []).filter((t) => t.length > 0);
122
+ if (tokens.length === 0) {
123
+ if (opts.allowUnauthenticated) {
124
+ ;
125
+ (opts.warn ?? console.warn)(UNAUTHENTICATED_WARNING);
126
+ return () => ({ ok: true });
127
+ }
128
+ return () => ({
129
+ ok: false,
130
+ status: 503,
131
+ error: "auth_not_configured",
132
+ message: "no bearer tokens are configured for this workflows API; set VOYANT_API_TOKENS " +
133
+ "(or pass tokens explicitly), or opt out for local development with " +
134
+ "VOYANT_WORKFLOWS_ALLOW_UNAUTHENTICATED=1",
135
+ });
136
+ }
137
+ return (header) => {
138
+ if (!header) {
139
+ return {
140
+ ok: false,
141
+ status: 401,
142
+ error: "unauthorized",
143
+ message: "missing Authorization header",
144
+ };
145
+ }
146
+ const match = /^Bearer (.+)$/.exec(header);
147
+ if (!match) {
148
+ return {
149
+ ok: false,
150
+ status: 401,
151
+ error: "unauthorized",
152
+ message: "Authorization header must use the Bearer scheme",
153
+ };
154
+ }
155
+ const presented = match[1];
156
+ for (const valid of tokens) {
157
+ if (constantTimeEquals(presented, valid))
158
+ return { ok: true };
159
+ }
160
+ return {
161
+ ok: false,
162
+ status: 401,
163
+ error: "unauthorized",
164
+ message: "bearer token does not match any configured value",
165
+ };
166
+ };
167
+ }
168
+ /**
169
+ * Resolve a `verifyRequest` hook (the dep consumed by
170
+ * `handleWorkerRequest` / `createStepHandler`) with fail-closed
171
+ * defaults — the missing-token case yields a verifier that rejects
172
+ * every request with a 503 `auth_not_configured` `RequestAuthError`
173
+ * instead of `undefined` (which would skip auth entirely).
174
+ *
175
+ * Returns `undefined` (auth skipped) ONLY when no tokens are
176
+ * configured AND `allowUnauthenticated` is explicitly set.
177
+ */
178
+ export function resolveRequestVerifier(opts) {
179
+ const tokens = (opts.tokens ?? []).filter((t) => t.length > 0);
180
+ if (tokens.length === 0 && opts.allowUnauthenticated) {
181
+ ;
182
+ (opts.warn ?? console.warn)(UNAUTHENTICATED_WARNING);
183
+ return undefined;
184
+ }
185
+ const authorize = createBearerAuthorizer({ ...opts, allowUnauthenticated: false });
186
+ return (req) => {
187
+ const decision = authorize(req.headers.get("authorization"));
188
+ if (!decision.ok) {
189
+ throw new RequestAuthError(decision.status, decision.error, decision.message);
190
+ }
191
+ };
192
+ }
64
193
  /** Returns a signer: `(body: string) => Promise<string>` (base64 HMAC-SHA256). */
65
194
  export async function createHmacSigner(secret) {
66
195
  const key = await importKey(secret, ["sign"]);
@@ -100,12 +229,98 @@ export async function createHmacVerifier(secret) {
100
229
  }
101
230
  };
102
231
  }
232
+ /**
233
+ * Returns a verifier over a raw body string + detached base64 HMAC
234
+ * signature (the value of `STEP_AUTH_HEADER`). Suitable for servers
235
+ * that have already buffered the request body (e.g. the node step
236
+ * container). `crypto.subtle.verify` is constant-time; malformed
237
+ * base64 or a missing signature simply yields `false`.
238
+ */
239
+ export async function createHmacBodyVerifier(secret) {
240
+ const key = await importKey(secret, ["verify"]);
241
+ return async (body, signatureBase64) => {
242
+ if (!signatureBase64)
243
+ return false;
244
+ let sig;
245
+ try {
246
+ sig = fromBase64(signatureBase64);
247
+ }
248
+ catch {
249
+ return false;
250
+ }
251
+ return crypto.subtle.verify("HMAC", key, sig, encode(body));
252
+ };
253
+ }
254
+ /**
255
+ * Default bundle source: Cloudflare R2's S3 endpoint
256
+ * (`<account>.r2.cloudflarestorage.com`), which is where deploy
257
+ * pipelines stage `container.mjs` and the orchestrator mints
258
+ * short-lived signed URLs. Anything else must be explicitly
259
+ * allowlisted via `allowedOrigins`.
260
+ */
261
+ const R2_HOST_SUFFIX = ".r2.cloudflarestorage.com";
262
+ /**
263
+ * Build an origin allowlist check for caller-supplied `bundle.url`
264
+ * values (the node step container dynamically `import()`s the fetched
265
+ * bytes, so an unrestricted URL is remote-code-execution-adjacent —
266
+ * the SHA-256 hash pin is supplied by the same caller and is not a
267
+ * security control on its own).
268
+ *
269
+ * - `allowedOrigins` set (e.g. from `VOYANT_BUNDLE_ALLOWED_ORIGINS`):
270
+ * the URL's origin must match one of the entries exactly.
271
+ * Invalid entries throw at creation time (misconfiguration should
272
+ * fail loudly, not silently widen).
273
+ * - unset/empty: only HTTPS URLs on `*.r2.cloudflarestorage.com`
274
+ * are allowed — the production bundle source.
275
+ */
276
+ export function createBundleUrlPolicy(opts) {
277
+ const entries = (opts?.allowedOrigins ?? []).filter((entry) => entry.length > 0);
278
+ const allowed = new Set();
279
+ for (const entry of entries) {
280
+ let parsed;
281
+ try {
282
+ parsed = new URL(entry);
283
+ }
284
+ catch {
285
+ throw new Error(`createBundleUrlPolicy: invalid origin in allowlist: "${entry}"`);
286
+ }
287
+ allowed.add(parsed.origin);
288
+ }
289
+ return (url) => {
290
+ let parsed;
291
+ try {
292
+ parsed = new URL(url);
293
+ }
294
+ catch {
295
+ return { ok: false, message: `bundle url is not a valid URL: "${url}"` };
296
+ }
297
+ if (allowed.size > 0) {
298
+ if (allowed.has(parsed.origin))
299
+ return { ok: true };
300
+ return {
301
+ ok: false,
302
+ message: `bundle url origin "${parsed.origin}" is not in the configured allowlist ` +
303
+ "(VOYANT_BUNDLE_ALLOWED_ORIGINS)",
304
+ };
305
+ }
306
+ if (parsed.protocol === "https:" && parsed.hostname.endsWith(R2_HOST_SUFFIX)) {
307
+ return { ok: true };
308
+ }
309
+ return {
310
+ ok: false,
311
+ message: `bundle url origin "${parsed.origin}" rejected: with no VOYANT_BUNDLE_ALLOWED_ORIGINS ` +
312
+ `configured, only https://*${R2_HOST_SUFFIX} bundle sources are allowed`,
313
+ };
314
+ };
315
+ }
103
316
  // ---- Internals ----
104
317
  async function importKey(secret, usages) {
105
318
  if (secret.length === 0) {
106
319
  throw new Error("HMAC secret must be a non-empty string");
107
320
  }
108
- return crypto.subtle.importKey("raw", encode(secret), { name: "HMAC", hash: "SHA-256" }, false, usages);
321
+ return crypto.subtle.importKey("raw", encode(secret), { name: "HMAC", hash: "SHA-256" }, false, [
322
+ ...usages,
323
+ ]);
109
324
  }
110
325
  /**
111
326
  * Encode to a freshly-allocated ArrayBuffer. TextEncoder's Uint8Array
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/events/registry.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAI3D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAA;IAC3C,qCAAqC;IACrC,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAA;IACrD,yDAAyD;IACzD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC;AAED,UAAU,mBAAmB;IAC3B,GAAG,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAA;IACzC,IAAI,IAAI,uBAAuB,EAAE,CAAA;IACjC,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAA;CACd;AAgCD,gEAAgE;AAChE,wBAAgB,sBAAsB,IAAI,mBAAmB,CAE5D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/events/registry.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAA;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAI3D;;;;;;;;;;GAUG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAA;IAC3C,qCAAqC;IACrC,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC,OAAO,CAAC,CAAA;IACrD,yDAAyD;IACzD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC;AAED,UAAU,mBAAmB;IAC3B,GAAG,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAA;IACzC,IAAI,IAAI,uBAAuB,EAAE,CAAA;IACjC,oEAAoE;IACpE,KAAK,IAAI,IAAI,CAAA;CACd;AA8BD,gEAAgE;AAChE,wBAAgB,sBAAsB,IAAI,mBAAmB,CAE5D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
@@ -203,9 +203,15 @@ function parseRequest(raw) {
203
203
  if (typeof r.workflowId !== "string" || r.workflowId.length === 0) {
204
204
  return { ok: false, message: "`workflowId` must be a non-empty string" };
205
205
  }
206
+ if (typeof r.workflowVersion !== "string" || r.workflowVersion.length === 0) {
207
+ return { ok: false, message: "`workflowVersion` must be a non-empty string" };
208
+ }
206
209
  if (typeof r.invocationCount !== "number" || r.invocationCount < 1) {
207
210
  return { ok: false, message: "`invocationCount` must be >= 1" };
208
211
  }
212
+ if (typeof r.deadline !== "number") {
213
+ return { ok: false, message: "`deadline` must be a number" };
214
+ }
209
215
  if (!r.journal || typeof r.journal !== "object") {
210
216
  return { ok: false, message: "`journal` must be an object" };
211
217
  }
@@ -219,7 +225,22 @@ function parseRequest(raw) {
219
225
  if (!r.runMeta || typeof r.runMeta !== "object") {
220
226
  return { ok: false, message: "`runMeta` must be an object" };
221
227
  }
222
- return { ok: true, value: r };
228
+ return {
229
+ ok: true,
230
+ value: {
231
+ protocolVersion: r.protocolVersion,
232
+ runId: r.runId,
233
+ workflowId: r.workflowId,
234
+ workflowVersion: r.workflowVersion,
235
+ invocationCount: r.invocationCount,
236
+ input: r.input,
237
+ journal: r.journal,
238
+ environment: env,
239
+ deadline: r.deadline,
240
+ tenantMeta: r.tenantMeta,
241
+ runMeta: r.runMeta,
242
+ },
243
+ };
223
244
  }
224
245
  // ---- Helpers ----
225
246
  function jsonResponse(status, body) {
@@ -1 +1 @@
1
- {"version":3,"file":"ctx.d.ts","sourceRoot":"","sources":["../../src/runtime/ctx.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ctx.d.ts","sourceRoot":"","sources":["../../src/runtime/ctx.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  // Builds the `ctx` object passed to the workflow body.
2
+ // agent-quality: file-size exception -- Central ctx API wiring remains together until wait/stream/group runtime slices can be extracted safely.
2
3
  //
3
4
  // The executor owns the waitpoint-pending queue and the callbacks
4
5
  // into the orchestrator; ctx is a thin shell that delegates.
@@ -380,22 +381,21 @@ export function buildCtx(args) {
380
381
  throw err;
381
382
  }
382
383
  }
383
- const streamImpl = async (streamId, sourceOrFn) => {
384
- const source = typeof sourceOrFn === "function"
385
- ? sourceOrFn()
386
- : sourceOrFn;
384
+ const streamImpl = async (streamId, sourceFn) => {
385
+ const source = sourceFn();
387
386
  await consumeStream(streamId, source, inferEncoding(source));
388
387
  };
389
- streamImpl.text = async (id, source) => {
390
- await consumeStream(id, source, "text");
391
- };
392
- streamImpl.json = async (id, source) => {
393
- await consumeStream(id, source, "json");
394
- };
395
- streamImpl.bytes = async (id, source) => {
396
- await consumeStream(id, source, "base64");
397
- };
398
- const stream = streamImpl;
388
+ const stream = Object.assign(streamImpl, {
389
+ text: async (id, source) => {
390
+ await consumeStream(id, source, "text");
391
+ },
392
+ json: async (id, source) => {
393
+ await consumeStream(id, source, "json");
394
+ },
395
+ bytes: async (id, source) => {
396
+ await consumeStream(id, source, "base64");
397
+ },
398
+ });
399
399
  // ---- groups ----
400
400
  // `ctx.group(name, fn)` creates a compensation scope. Implementation
401
401
  // strategy: the outer compensable list is the single source of truth;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}
@@ -2,12 +2,16 @@
2
2
  //
3
3
  // In-process test harness with mocked steps, waits, and invokes.
4
4
  // Contract in docs/sdk-surface.md §11.
5
+ // agent-quality: file-size exception -- legacy test harness stays co-located until pause/resume helpers are split.
5
6
  //
6
7
  // Drives `executeWorkflowStep` across resumptions. Steps resolve
7
8
  // from a user-supplied stub map; waitpoints resolve from fixtures.
8
9
  import { executeWorkflowStep, } from "../runtime/executor.js";
9
10
  import { emptyJournal } from "../runtime/journal.js";
10
11
  import { getWorkflow } from "../workflow.js";
12
+ function workflowForExecutor(def) {
13
+ return def;
14
+ }
11
15
  export async function runWorkflowForTest(workflow, input, opts = {}) {
12
16
  const def = workflow;
13
17
  const now = opts.now ?? (() => Date.now());
@@ -33,7 +37,7 @@ export async function runWorkflowForTest(workflow, input, opts = {}) {
33
37
  const cursors = { event: new Map(), signal: new Map() };
34
38
  while (invocationCount < maxInvocations) {
35
39
  invocationCount += 1;
36
- const response = await executeWorkflowStep(def, {
40
+ const response = await executeWorkflowStep(workflowForExecutor(def), {
37
41
  runId: `run_test_${def.id}`,
38
42
  workflowId: def.id,
39
43
  workflowVersion: "test",
@@ -219,7 +223,7 @@ export async function resumeWorkflowForTest(workflow, input, opts) {
219
223
  let carryover = opts.pause.pendingWaitpoints.filter((w) => w.clientWaitpointId !== matched.clientWaitpointId);
220
224
  while (invocationCount < maxInvocations) {
221
225
  invocationCount += 1;
222
- const response = await executeWorkflowStep(def, {
226
+ const response = await executeWorkflowStep(workflowForExecutor(def), {
223
227
  runId: `run_test_${def.id}`,
224
228
  workflowId: def.id,
225
229
  workflowVersion: "test",
@@ -1 +1 @@
1
- {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/workflows",
3
- "version": "0.107.4",
3
+ "version": "0.107.6",
4
4
  "description": "Authoring SDK for Voyant Workflows — durable, step-based orchestrations for Voyant Cloud.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/src/auth/index.ts CHANGED
@@ -24,6 +24,30 @@
24
24
 
25
25
  export const AUTH_HEADER = "x-voyant-dispatch-auth" as const
26
26
 
27
+ /**
28
+ * HMAC header carried on orchestrator → node-step-container dispatches
29
+ * (`POST /step`). Signed over the raw request body with the shared
30
+ * `VOYANT_WORKFLOW_STEP_AUTH_SECRET`. See `createCfContainerStepRunner`
31
+ * (signing side) and `apps/workflows-node-step-container` (verifying side).
32
+ */
33
+ export const STEP_AUTH_HEADER = "x-voyant-step-auth" as const
34
+
35
+ /**
36
+ * HMAC header returned by the node-step-container on successful `/step`
37
+ * responses. Signed over the raw JSON response body with the same
38
+ * `VOYANT_WORKFLOW_STEP_AUTH_SECRET` so the orchestrator can reject
39
+ * forged step journal entries before committing run state.
40
+ */
41
+ export const STEP_RESPONSE_AUTH_HEADER = "x-voyant-step-response-auth" as const
42
+
43
+ /** Parse a comma-separated token/origin list env var into trimmed, non-empty entries. */
44
+ export function parseTokenList(raw: string | null | undefined): string[] {
45
+ return (raw ?? "")
46
+ .split(",")
47
+ .map((s) => s.trim())
48
+ .filter((s) => s.length > 0)
49
+ }
50
+
27
51
  /**
28
52
  * Returns a verifier that accepts `Authorization: Bearer <token>`
29
53
  * where `<token>` matches any of the `validTokens` (case-sensitive,
@@ -53,15 +77,151 @@ export function createBearerVerifier(validTokens: readonly string[]): (req: Requ
53
77
  }
54
78
  }
55
79
 
80
+ /**
81
+ * Constant-time string comparison. Does NOT early-return on length
82
+ * mismatch: the loop always runs over the longer input (out-of-range
83
+ * `charCodeAt` is NaN, which coerces to 0 under bitwise ops), and a
84
+ * length mismatch only sets a diff bit. This avoids leaking how many
85
+ * leading characters of a secret matched, or whether the length matched.
86
+ */
56
87
  function constantTimeEquals(a: string, b: string): boolean {
57
- if (a.length !== b.length) return false
58
- let diff = 0
59
- for (let i = 0; i < a.length; i++) {
60
- diff |= a.charCodeAt(i) ^ b.charCodeAt(i)
88
+ const length = Math.max(a.length, b.length, 1)
89
+ let diff = a.length === b.length ? 0 : 1
90
+ for (let i = 0; i < length; i++) {
91
+ diff |= (a.charCodeAt(i) | 0) ^ (b.charCodeAt(i) | 0)
61
92
  }
62
93
  return diff === 0
63
94
  }
64
95
 
96
+ // ---- Fail-closed bearer auth resolution ----
97
+
98
+ /**
99
+ * Error thrown by verifiers produced in this module. Carries an HTTP
100
+ * `status` + machine-readable `code` so HTTP surfaces
101
+ * (`handleWorkerRequest`, the node dashboard server, step handlers)
102
+ * can map auth failures to the right response instead of a blanket 401.
103
+ */
104
+ export class RequestAuthError extends Error {
105
+ readonly status: number
106
+ readonly code: string
107
+
108
+ constructor(status: number, code: string, message: string) {
109
+ super(message)
110
+ this.name = "RequestAuthError"
111
+ this.status = status
112
+ this.code = code
113
+ }
114
+ }
115
+
116
+ export type BearerAuthDecision =
117
+ | { ok: true }
118
+ | { ok: false; status: number; error: string; message: string }
119
+
120
+ export interface BearerAuthOptions {
121
+ /** Accepted bearer tokens. Empty/undefined = no auth configured. */
122
+ tokens?: readonly string[]
123
+ /**
124
+ * Explicit local-dev opt-out. When `true` AND no tokens are
125
+ * configured, requests are allowed through with a loud warning.
126
+ * When `false`/unset and no tokens are configured, every request is
127
+ * rejected with 503 `auth_not_configured` (fail closed).
128
+ */
129
+ allowUnauthenticated?: boolean
130
+ /** Warning sink for the unauthenticated opt-out. Defaults to `console.warn`. */
131
+ warn?: (message: string) => void
132
+ }
133
+
134
+ const UNAUTHENTICATED_WARNING =
135
+ "[voyant-workflows] AUTH DISABLED: no bearer tokens are configured and " +
136
+ "VOYANT_WORKFLOWS_ALLOW_UNAUTHENTICATED is set. Every caller can trigger, read, " +
137
+ "resume, and cancel workflow runs. This mode is for LOCAL DEVELOPMENT ONLY — " +
138
+ "configure VOYANT_API_TOKENS before deploying."
139
+
140
+ /**
141
+ * Build a transport-agnostic bearer authorizer from a raw
142
+ * `Authorization` header value. Fail-closed semantics:
143
+ *
144
+ * - tokens configured → exact (constant-time) Bearer match or 401
145
+ * - no tokens + opt-out → always allowed (warns loudly once, at creation)
146
+ * - no tokens, no opt-out → always 503 `auth_not_configured`
147
+ */
148
+ export function createBearerAuthorizer(
149
+ opts: BearerAuthOptions,
150
+ ): (authorizationHeader: string | null | undefined) => BearerAuthDecision {
151
+ const tokens = (opts.tokens ?? []).filter((t) => t.length > 0)
152
+ if (tokens.length === 0) {
153
+ if (opts.allowUnauthenticated) {
154
+ ;(opts.warn ?? console.warn)(UNAUTHENTICATED_WARNING)
155
+ return () => ({ ok: true })
156
+ }
157
+ return () => ({
158
+ ok: false,
159
+ status: 503,
160
+ error: "auth_not_configured",
161
+ message:
162
+ "no bearer tokens are configured for this workflows API; set VOYANT_API_TOKENS " +
163
+ "(or pass tokens explicitly), or opt out for local development with " +
164
+ "VOYANT_WORKFLOWS_ALLOW_UNAUTHENTICATED=1",
165
+ })
166
+ }
167
+ return (header) => {
168
+ if (!header) {
169
+ return {
170
+ ok: false,
171
+ status: 401,
172
+ error: "unauthorized",
173
+ message: "missing Authorization header",
174
+ }
175
+ }
176
+ const match = /^Bearer (.+)$/.exec(header)
177
+ if (!match) {
178
+ return {
179
+ ok: false,
180
+ status: 401,
181
+ error: "unauthorized",
182
+ message: "Authorization header must use the Bearer scheme",
183
+ }
184
+ }
185
+ const presented = match[1]!
186
+ for (const valid of tokens) {
187
+ if (constantTimeEquals(presented, valid)) return { ok: true }
188
+ }
189
+ return {
190
+ ok: false,
191
+ status: 401,
192
+ error: "unauthorized",
193
+ message: "bearer token does not match any configured value",
194
+ }
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Resolve a `verifyRequest` hook (the dep consumed by
200
+ * `handleWorkerRequest` / `createStepHandler`) with fail-closed
201
+ * defaults — the missing-token case yields a verifier that rejects
202
+ * every request with a 503 `auth_not_configured` `RequestAuthError`
203
+ * instead of `undefined` (which would skip auth entirely).
204
+ *
205
+ * Returns `undefined` (auth skipped) ONLY when no tokens are
206
+ * configured AND `allowUnauthenticated` is explicitly set.
207
+ */
208
+ export function resolveRequestVerifier(
209
+ opts: BearerAuthOptions,
210
+ ): ((req: Request) => void) | undefined {
211
+ const tokens = (opts.tokens ?? []).filter((t) => t.length > 0)
212
+ if (tokens.length === 0 && opts.allowUnauthenticated) {
213
+ ;(opts.warn ?? console.warn)(UNAUTHENTICATED_WARNING)
214
+ return undefined
215
+ }
216
+ const authorize = createBearerAuthorizer({ ...opts, allowUnauthenticated: false })
217
+ return (req) => {
218
+ const decision = authorize(req.headers.get("authorization"))
219
+ if (!decision.ok) {
220
+ throw new RequestAuthError(decision.status, decision.error, decision.message)
221
+ }
222
+ }
223
+ }
224
+
65
225
  /** Returns a signer: `(body: string) => Promise<string>` (base64 HMAC-SHA256). */
66
226
  export async function createHmacSigner(secret: string): Promise<(body: string) => Promise<string>> {
67
227
  const key = await importKey(secret, ["sign"])
@@ -102,6 +262,98 @@ export async function createHmacVerifier(secret: string): Promise<(req: Request)
102
262
  }
103
263
  }
104
264
 
265
+ /**
266
+ * Returns a verifier over a raw body string + detached base64 HMAC
267
+ * signature (the value of `STEP_AUTH_HEADER`). Suitable for servers
268
+ * that have already buffered the request body (e.g. the node step
269
+ * container). `crypto.subtle.verify` is constant-time; malformed
270
+ * base64 or a missing signature simply yields `false`.
271
+ */
272
+ export async function createHmacBodyVerifier(
273
+ secret: string,
274
+ ): Promise<(body: string, signatureBase64: string | null | undefined) => Promise<boolean>> {
275
+ const key = await importKey(secret, ["verify"])
276
+ return async (body, signatureBase64) => {
277
+ if (!signatureBase64) return false
278
+ let sig: ArrayBuffer
279
+ try {
280
+ sig = fromBase64(signatureBase64)
281
+ } catch {
282
+ return false
283
+ }
284
+ return crypto.subtle.verify("HMAC", key, sig, encode(body))
285
+ }
286
+ }
287
+
288
+ // ---- Bundle URL origin policy ----
289
+
290
+ export type BundleUrlDecision = { ok: true } | { ok: false; message: string }
291
+
292
+ /**
293
+ * Default bundle source: Cloudflare R2's S3 endpoint
294
+ * (`<account>.r2.cloudflarestorage.com`), which is where deploy
295
+ * pipelines stage `container.mjs` and the orchestrator mints
296
+ * short-lived signed URLs. Anything else must be explicitly
297
+ * allowlisted via `allowedOrigins`.
298
+ */
299
+ const R2_HOST_SUFFIX = ".r2.cloudflarestorage.com"
300
+
301
+ /**
302
+ * Build an origin allowlist check for caller-supplied `bundle.url`
303
+ * values (the node step container dynamically `import()`s the fetched
304
+ * bytes, so an unrestricted URL is remote-code-execution-adjacent —
305
+ * the SHA-256 hash pin is supplied by the same caller and is not a
306
+ * security control on its own).
307
+ *
308
+ * - `allowedOrigins` set (e.g. from `VOYANT_BUNDLE_ALLOWED_ORIGINS`):
309
+ * the URL's origin must match one of the entries exactly.
310
+ * Invalid entries throw at creation time (misconfiguration should
311
+ * fail loudly, not silently widen).
312
+ * - unset/empty: only HTTPS URLs on `*.r2.cloudflarestorage.com`
313
+ * are allowed — the production bundle source.
314
+ */
315
+ export function createBundleUrlPolicy(opts?: {
316
+ allowedOrigins?: readonly string[]
317
+ }): (url: string) => BundleUrlDecision {
318
+ const entries = (opts?.allowedOrigins ?? []).filter((entry) => entry.length > 0)
319
+ const allowed = new Set<string>()
320
+ for (const entry of entries) {
321
+ let parsed: URL
322
+ try {
323
+ parsed = new URL(entry)
324
+ } catch {
325
+ throw new Error(`createBundleUrlPolicy: invalid origin in allowlist: "${entry}"`)
326
+ }
327
+ allowed.add(parsed.origin)
328
+ }
329
+ return (url) => {
330
+ let parsed: URL
331
+ try {
332
+ parsed = new URL(url)
333
+ } catch {
334
+ return { ok: false, message: `bundle url is not a valid URL: "${url}"` }
335
+ }
336
+ if (allowed.size > 0) {
337
+ if (allowed.has(parsed.origin)) return { ok: true }
338
+ return {
339
+ ok: false,
340
+ message:
341
+ `bundle url origin "${parsed.origin}" is not in the configured allowlist ` +
342
+ "(VOYANT_BUNDLE_ALLOWED_ORIGINS)",
343
+ }
344
+ }
345
+ if (parsed.protocol === "https:" && parsed.hostname.endsWith(R2_HOST_SUFFIX)) {
346
+ return { ok: true }
347
+ }
348
+ return {
349
+ ok: false,
350
+ message:
351
+ `bundle url origin "${parsed.origin}" rejected: with no VOYANT_BUNDLE_ALLOWED_ORIGINS ` +
352
+ `configured, only https://*${R2_HOST_SUFFIX} bundle sources are allowed`,
353
+ }
354
+ }
355
+ }
356
+
105
357
  // ---- Internals ----
106
358
 
107
359
  async function importKey(
@@ -111,13 +363,9 @@ async function importKey(
111
363
  if (secret.length === 0) {
112
364
  throw new Error("HMAC secret must be a non-empty string")
113
365
  }
114
- return crypto.subtle.importKey(
115
- "raw",
116
- encode(secret),
117
- { name: "HMAC", hash: "SHA-256" },
118
- false,
119
- usages as KeyUsage[],
120
- )
366
+ return crypto.subtle.importKey("raw", encode(secret), { name: "HMAC", hash: "SHA-256" }, false, [
367
+ ...usages,
368
+ ])
121
369
  }
122
370
 
123
371
  /**
@@ -44,10 +44,8 @@ interface EventFilterRegistry {
44
44
  reset(): void
45
45
  }
46
46
 
47
- const globalRef = globalThis as unknown as Record<
48
- typeof REGISTRY_KEY,
49
- Map<string, EventFilterRuntimeEntry> | undefined
50
- >
47
+ const globalRef = globalThis as typeof globalThis &
48
+ Record<typeof REGISTRY_KEY, Map<string, EventFilterRuntimeEntry> | undefined>
51
49
 
52
50
  const REGISTRY: Map<string, EventFilterRuntimeEntry> =
53
51
  globalRef[REGISTRY_KEY] ?? new Map<string, EventFilterRuntimeEntry>()
@@ -335,9 +335,15 @@ function parseRequest(
335
335
  if (typeof r.workflowId !== "string" || r.workflowId.length === 0) {
336
336
  return { ok: false, message: "`workflowId` must be a non-empty string" }
337
337
  }
338
+ if (typeof r.workflowVersion !== "string" || r.workflowVersion.length === 0) {
339
+ return { ok: false, message: "`workflowVersion` must be a non-empty string" }
340
+ }
338
341
  if (typeof r.invocationCount !== "number" || r.invocationCount < 1) {
339
342
  return { ok: false, message: "`invocationCount` must be >= 1" }
340
343
  }
344
+ if (typeof r.deadline !== "number") {
345
+ return { ok: false, message: "`deadline` must be a number" }
346
+ }
341
347
  if (!r.journal || typeof r.journal !== "object") {
342
348
  return { ok: false, message: "`journal` must be an object" }
343
349
  }
@@ -351,7 +357,22 @@ function parseRequest(
351
357
  if (!r.runMeta || typeof r.runMeta !== "object") {
352
358
  return { ok: false, message: "`runMeta` must be an object" }
353
359
  }
354
- return { ok: true, value: r as unknown as WorkflowStepRequest }
360
+ return {
361
+ ok: true,
362
+ value: {
363
+ protocolVersion: r.protocolVersion as ProtocolVersion,
364
+ runId: r.runId,
365
+ workflowId: r.workflowId,
366
+ workflowVersion: r.workflowVersion,
367
+ invocationCount: r.invocationCount,
368
+ input: r.input,
369
+ journal: r.journal as JournalSlice,
370
+ environment: env,
371
+ deadline: r.deadline,
372
+ tenantMeta: r.tenantMeta as WorkflowStepRequest["tenantMeta"],
373
+ runMeta: r.runMeta as WorkflowStepRequest["runMeta"],
374
+ },
375
+ }
355
376
  }
356
377
 
357
378
  // ---- Helpers ----
@@ -1,4 +1,5 @@
1
1
  // Builds the `ctx` object passed to the workflow body.
2
+ // agent-quality: file-size exception -- Central ctx API wiring remains together until wait/stream/group runtime slices can be extracted safely.
2
3
  //
3
4
  // The executor owns the waitpoint-pending queue and the callbacks
4
5
  // into the orchestrator; ctx is a thin shell that delegates.
@@ -360,7 +361,7 @@ export function buildCtx(args: CtxBuildArgs): WorkflowContext<unknown> {
360
361
  let closed = false
361
362
  return {
362
363
  async next(): Promise<IteratorResult<T>> {
363
- if (closed) return { value: undefined as unknown as T, done: true }
364
+ if (closed) return { value: undefined, done: true }
364
365
  checkCancel()
365
366
  const iterId = `${iterIdPrefix}:iter:${nextClientId()}`
366
367
  const resolvedIter = lookupWaitpoint(iterId)
@@ -373,7 +374,7 @@ export function buildCtx(args: CtxBuildArgs): WorkflowContext<unknown> {
373
374
  const payload = resolvedIter.payload as unknown
374
375
  if (isStreamEnd(payload)) {
375
376
  closed = true
376
- return { value: undefined as unknown as T, done: true }
377
+ return { value: undefined, done: true }
377
378
  }
378
379
  if (payload === undefined && onTimeout === "throw") {
379
380
  throw new Error(`waitpoint ${iterId} timed out`)
@@ -382,7 +383,7 @@ export function buildCtx(args: CtxBuildArgs): WorkflowContext<unknown> {
382
383
  },
383
384
  async return(): Promise<IteratorResult<T>> {
384
385
  closed = true
385
- return { value: undefined as unknown as T, done: true }
386
+ return { value: undefined, done: true }
386
387
  },
387
388
  [Symbol.asyncIterator]() {
388
389
  return this
@@ -611,29 +612,25 @@ export function buildCtx(args: CtxBuildArgs): WorkflowContext<unknown> {
611
612
  }
612
613
  }
613
614
 
614
- const streamImpl = async (
615
+ const streamImpl = async <T>(
615
616
  streamId: string,
616
- sourceOrFn: AsyncIterable<unknown> | (() => AsyncGenerator<unknown>),
617
+ sourceFn: () => AsyncGenerator<T>,
617
618
  ): Promise<void> => {
618
- const source =
619
- typeof sourceOrFn === "function"
620
- ? (sourceOrFn as () => AsyncGenerator<unknown>)()
621
- : sourceOrFn
619
+ const source = sourceFn()
622
620
  await consumeStream(streamId, source, inferEncoding(source))
623
621
  }
624
622
 
625
- // Typed shape variants. Each forwards to consumeStream with a fixed encoding.
626
- ;(streamImpl as unknown as { text: StreamApi["text"] }).text = async (id, source) => {
627
- await consumeStream(id, source, "text")
628
- }
629
- ;(streamImpl as unknown as { json: StreamApi["json"] }).json = async (id, source) => {
630
- await consumeStream(id, source, "json")
631
- }
632
- ;(streamImpl as unknown as { bytes: StreamApi["bytes"] }).bytes = async (id, source) => {
633
- await consumeStream(id, source, "base64")
634
- }
635
-
636
- const stream = streamImpl as unknown as StreamApi
623
+ const stream: StreamApi = Object.assign(streamImpl, {
624
+ text: async (id, source) => {
625
+ await consumeStream(id, source, "text")
626
+ },
627
+ json: async (id, source) => {
628
+ await consumeStream(id, source, "json")
629
+ },
630
+ bytes: async (id, source) => {
631
+ await consumeStream(id, source, "base64")
632
+ },
633
+ } satisfies Pick<StreamApi, "text" | "json" | "bytes">)
637
634
 
638
635
  // ---- groups ----
639
636
 
@@ -769,7 +766,7 @@ function normalizeChunk(value: unknown, encoding: "text" | "json" | "base64"): u
769
766
  function toBase64(bytes: Uint8Array): string {
770
767
  // Node + modern runtimes provide Buffer or btoa. Use Buffer when
771
768
  // available for efficiency; fall back to manual encode for isolates.
772
- const g = globalThis as unknown as {
769
+ const g = globalThis as typeof globalThis & {
773
770
  Buffer?: { from(b: Uint8Array): { toString(enc: "base64"): string } }
774
771
  btoa?: (s: string) => string
775
772
  }
@@ -2,6 +2,7 @@
2
2
  //
3
3
  // In-process test harness with mocked steps, waits, and invokes.
4
4
  // Contract in docs/sdk-surface.md §11.
5
+ // agent-quality: file-size exception -- legacy test harness stays co-located until pause/resume helpers are split.
5
6
  //
6
7
  // Drives `executeWorkflowStep` across resumptions. Steps resolve
7
8
  // from a user-supplied stub map; waitpoints resolve from fixtures.
@@ -31,6 +32,10 @@ import type {
31
32
  } from "../workflow.js"
32
33
  import { getWorkflow } from "../workflow.js"
33
34
 
35
+ function workflowForExecutor<TIn, TOut>(def: WorkflowDefinition<TIn, TOut>): WorkflowDefinition {
36
+ return def as WorkflowDefinition
37
+ }
38
+
34
39
  export interface TestOptions<_TIn> {
35
40
  /** Map of stepId → function run in place of the real step body. */
36
41
  steps?: Record<string, (stepCtx: StepContext) => unknown | Promise<unknown>>
@@ -128,7 +133,7 @@ export async function runWorkflowForTest<TIn, TOut>(
128
133
  while (invocationCount < maxInvocations) {
129
134
  invocationCount += 1
130
135
 
131
- const response = await executeWorkflowStep(def as unknown as WorkflowDefinition, {
136
+ const response = await executeWorkflowStep(workflowForExecutor(def), {
132
137
  runId: `run_test_${def.id}`,
133
138
  workflowId: def.id,
134
139
  workflowVersion: "test",
@@ -363,7 +368,7 @@ export async function resumeWorkflowForTest<TIn, TOut>(
363
368
  while (invocationCount < maxInvocations) {
364
369
  invocationCount += 1
365
370
 
366
- const response = await executeWorkflowStep(def as unknown as WorkflowDefinition, {
371
+ const response = await executeWorkflowStep(workflowForExecutor(def), {
367
372
  runId: `run_test_${def.id}`,
368
373
  workflowId: def.id,
369
374
  workflowVersion: "test",
@@ -681,23 +686,19 @@ async function resolveWaitpoint(
681
686
  at: now(),
682
687
  data: { childWorkflowId, input: childInput },
683
688
  })
684
- const childResult = await runWorkflowForTest(
685
- child as unknown as WorkflowHandle<unknown, unknown>,
686
- childInput,
687
- {
688
- steps: opts.steps,
689
- waitForEvent: opts.waitForEvent,
690
- waitForSignal: opts.waitForSignal,
691
- waitForToken: opts.waitForToken,
692
- invoke: opts.invoke,
693
- env: opts.env,
694
- environment: opts.environment,
695
- now: opts.now,
696
- random: opts.random,
697
- maxInvocations: opts.maxInvocations,
698
- pauseOnWait: detach || opts.pauseOnWait,
699
- },
700
- )
689
+ const childResult = await runWorkflowForTest(child, childInput, {
690
+ steps: opts.steps,
691
+ waitForEvent: opts.waitForEvent,
692
+ waitForSignal: opts.waitForSignal,
693
+ waitForToken: opts.waitForToken,
694
+ invoke: opts.invoke,
695
+ env: opts.env,
696
+ environment: opts.environment,
697
+ now: opts.now,
698
+ random: opts.random,
699
+ maxInvocations: opts.maxInvocations,
700
+ pauseOnWait: detach || opts.pauseOnWait,
701
+ })
701
702
  parentEvents.push({
702
703
  type: "child.finished",
703
704
  at: now(),
package/src/workflow.ts CHANGED
@@ -72,10 +72,8 @@ export interface ConcurrencyPolicy<TInput> {
72
72
  * would create a private map per bundle copy.
73
73
  */
74
74
  const REGISTRY_KEY = "__voyantWorkflowRegistry" as const
75
- const globalRef = globalThis as unknown as Record<
76
- typeof REGISTRY_KEY,
77
- Map<string, WorkflowDefinition> | undefined
78
- >
75
+ const globalRef = globalThis as typeof globalThis &
76
+ Record<typeof REGISTRY_KEY, Map<string, WorkflowDefinition> | undefined>
79
77
  const REGISTRY: Map<string, WorkflowDefinition> =
80
78
  globalRef[REGISTRY_KEY] ?? new Map<string, WorkflowDefinition>()
81
79
  globalRef[REGISTRY_KEY] = REGISTRY