@voyantjs/workflows-cloud-adapter 0.52.1 → 0.52.2

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/index.d.ts CHANGED
@@ -37,6 +37,8 @@ export interface CloudWorkflowsEnv {
37
37
  VOYANT_WORKFLOW_BUNDLE_R2_BUCKET?: string;
38
38
  /** Optional signed URL TTL in seconds. Defaults to 300. */
39
39
  VOYANT_WORKFLOW_BUNDLE_URL_TTL_SECONDS?: string;
40
+ /** Platform-managed Cloud Run node step runner endpoint. */
41
+ VOYANT_WORKFLOW_NODE_RUNNER_URL?: string;
40
42
  /** Shared secret used to sign dispatches to the platform step runner. */
41
43
  VOYANT_WORKFLOW_STEP_AUTH_SECRET?: string;
42
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EACL,KAAK,sBAAsB,EAK3B,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAI7B,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,6CAA6C,CAAA;AAEpD,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,eAAe,EAAE,0BAA0B,CAAA;IAC3C;;;;OAIG;IACH,WAAW,CAAC,EAAE,sBAAsB,CAAA;IACpC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,eAAe,CAAA;IACpC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B;;;OAGG;IACH,iCAAiC,CAAC,EAAE,MAAM,CAAA;IAC1C,sEAAsE;IACtE,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,sEAAsE;IACtE,2BAA2B,CAAC,EAAE,MAAM,CAAA;IACpC,8EAA8E;IAC9E,uCAAuC,CAAC,EAAE,MAAM,CAAA;IAChD,kFAAkF;IAClF,2CAA2C,CAAC,EAAE,MAAM,CAAA;IACpD,uEAAuE;IACvE,oCAAoC,CAAC,EAAE,MAAM,CAAA;IAC7C,mEAAmE;IACnE,gCAAgC,CAAC,EAAE,MAAM,CAAA;IACzC,2DAA2D;IAC3D,sCAAsC,CAAC,EAAE,MAAM,CAAA;IAC/C,4DAA4D;IAC5D,+BAA+B,CAAC,EAAE,MAAM,CAAA;IACxC,yEAAyE;IACzE,gCAAgC,CAAC,EAAE,MAAM,CAAA;CAC1C;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,wBAAwB,CAAA;CAClC;AAED,MAAM,WAAW,wBAAwB,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB;IACzF,aAAa,CAAC,EAAE,eAAe,CAAC,eAAe,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAA;IAClC,WAAW,CAAC,EAAE,eAAe,CAAC,aAAa,CAAC,CAAA;IAC5C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,eAAe,CAAC,YAAY,CAAC,CAAA;IAC1C,QAAQ,CAAC,EAAE,OAAO,4BAA4B,EAAE,eAAe,CAAA;IAC/D,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,CAAA;CAC/B;AAED,MAAM,WAAW,iBAAiB,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB;IAClF,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IACzD,aAAa,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAA;CACvC;AAYD,MAAM,MAAM,kBAAkB,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB,IAAI,KAClF,KAAK,EAAE,sBAAsB,EAC7B,GAAG,EAAE,GAAG,KACL,aAAa,CAAC,GAAG,CAAC,CAAA;AAEvB,KAAK,qBAAqB,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB,IAAI,IAAI,CAClF,wBAAwB,CAAC,GAAG,CAAC,EAC7B,UAAU,GAAG,KAAK,GAAG,QAAQ,CAC9B,CAAA;AAED,wBAAgB,uBAAuB,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB,EACvF,SAAS,CAAC,EAAE,OAAO,EACnB,QAAQ,CAAC,EAAE,GAAG,EACd,OAAO,GAAE,wBAAwB,CAAC,GAAG,CAAM,GAC1C,iBAAiB,CAAC,GAAG,CAAC,CAWxB;AAED,wBAAgB,cAAc,CAC5B,GAAG,SAAS;IACV,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,OAAO,CAAA;IAC9F,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CACzF,EACD,GAAG,SAAS,iBAAiB,GAAG,iBAAiB,EACjD,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,OAAO,GAAE,wBAAwB,CAAC,GAAG,CAAC,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,GAAG,CA2BjG;AAED,wBAAsB,gBAAgB,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB,EACtF,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,wBAAwB,CAAC,GAAG,CAAM,GAC1C,OAAO,CAAC,QAAQ,CAAC,CAmBnB;AAED,qBAAa,aAAa,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB;IAC1E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAK;gBAEb,KAAK,EAAE,sBAAsB,EAAE,GAAG,EAAE,GAAG;IAK7C,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAQ1C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,SAAS,CAAC,gBAAgB,IAAI,qBAAqB,CAAC,GAAG,CAAC;CAGzD;AAED,wBAAgB,yBAAyB,CAAC,GAAG,SAAS,iBAAiB,GAAG,iBAAiB,EACzF,GAAG,EAAE,GAAG,EACR,OAAO,GAAE,qBAAqB,CAAC,GAAG,CAAyD,GAC1F,cAAc,CAEhB"}
package/dist/index.js CHANGED
@@ -125,6 +125,9 @@ async function buildStepHandler(env, options = defaultExecutionOptions) {
125
125
  }, stepOptions);
126
126
  }
127
127
  async function createNodeStepRunner(env, options) {
128
+ if (env.VOYANT_WORKFLOW_NODE_RUNNER_URL) {
129
+ return createHttpNodeStepRunner(env, options);
130
+ }
128
131
  if (!env.STEP_RUNNER) {
129
132
  return createInlineNodeStepRunner(options.now);
130
133
  }
@@ -151,6 +154,106 @@ async function createNodeStepRunner(env, options) {
151
154
  }),
152
155
  });
153
156
  }
157
+ async function createHttpNodeStepRunner(env, options) {
158
+ const serviceUrl = env.VOYANT_WORKFLOW_NODE_RUNNER_URL?.replace(/\/+$/, "");
159
+ if (!serviceUrl) {
160
+ throw new Error("@voyantjs/workflows-cloud-adapter: VOYANT_WORKFLOW_NODE_RUNNER_URL is empty");
161
+ }
162
+ const key = env.VOYANT_WORKFLOW_BUNDLE_KEY;
163
+ const hash = env.VOYANT_WORKFLOW_BUNDLE_HASH;
164
+ const missing = [
165
+ ["VOYANT_WORKFLOW_BUNDLE_KEY", key],
166
+ ["VOYANT_WORKFLOW_BUNDLE_HASH", hash],
167
+ ].filter(([, value]) => typeof value !== "string" || value.length === 0);
168
+ if (missing.length > 0) {
169
+ throw new Error(`@voyantjs/workflows-cloud-adapter: Cloud Run node runner is configured but bundle env is incomplete: ${missing
170
+ .map(([name]) => name)
171
+ .join(", ")}`);
172
+ }
173
+ const sign = env.VOYANT_WORKFLOW_STEP_AUTH_SECRET
174
+ ? await createHmacSigner(env.VOYANT_WORKFLOW_STEP_AUTH_SECRET)
175
+ : undefined;
176
+ return async ({ stepId, attempt, input, stepCtx, runId, workflowId, workflowVersion, projectId, organizationId, options: stepOptions, journal, }) => {
177
+ const startedAt = Date.now();
178
+ const payload = {
179
+ runId,
180
+ workflowId,
181
+ workflowVersion,
182
+ projectId,
183
+ organizationId,
184
+ stepId,
185
+ attempt,
186
+ input,
187
+ options: {
188
+ machine: stepOptions.machine,
189
+ timeout: typeof stepOptions.timeout === "string" || typeof stepOptions.timeout === "number"
190
+ ? stepOptions.timeout
191
+ : undefined,
192
+ },
193
+ bundle: {
194
+ key,
195
+ hash,
196
+ },
197
+ journal,
198
+ };
199
+ const body = JSON.stringify(payload);
200
+ const headers = {
201
+ "content-type": "application/json; charset=utf-8",
202
+ };
203
+ if (sign)
204
+ headers["x-voyant-step-auth"] = await sign(body);
205
+ let response;
206
+ try {
207
+ response = await fetch(`${serviceUrl}/step`, {
208
+ method: "POST",
209
+ headers,
210
+ body,
211
+ signal: stepCtx.signal,
212
+ });
213
+ }
214
+ catch (err) {
215
+ options.logger?.("error", "cloud-run-node: fetch threw", {
216
+ runId,
217
+ stepId,
218
+ error: err instanceof Error ? err.message : String(err),
219
+ });
220
+ return failedNodeStep(attempt, startedAt, "NODE_RUNNER_DISPATCH_FAILED", err);
221
+ }
222
+ const text = await response.text();
223
+ if (!response.ok) {
224
+ options.logger?.("warn", "cloud-run-node: non-2xx response", {
225
+ runId,
226
+ stepId,
227
+ status: response.status,
228
+ body: text.slice(0, 500),
229
+ });
230
+ return failedNodeStep(attempt, startedAt, "NODE_RUNNER_HTTP_ERROR", new Error(`node runner returned HTTP ${response.status}: ${text}`));
231
+ }
232
+ try {
233
+ return JSON.parse(text);
234
+ }
235
+ catch (err) {
236
+ return failedNodeStep(attempt, startedAt, "NODE_RUNNER_INVALID_RESPONSE", new Error(`node runner returned non-JSON body: ${String(err)}`));
237
+ }
238
+ };
239
+ }
240
+ function failedNodeStep(attempt, startedAt, code, err) {
241
+ const e = err instanceof Error ? err : new Error(String(err));
242
+ return {
243
+ attempt,
244
+ status: "err",
245
+ startedAt,
246
+ finishedAt: Date.now(),
247
+ runtime: "node",
248
+ error: {
249
+ category: "RUNTIME_ERROR",
250
+ code,
251
+ message: e.message,
252
+ name: e.name,
253
+ stack: e.stack,
254
+ },
255
+ };
256
+ }
154
257
  function createInlineNodeStepRunner(now = () => Date.now()) {
155
258
  return async ({ attempt, fn, stepCtx }) => {
156
259
  const startedAt = now();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/workflows-cloud-adapter",
3
- "version": "0.52.1",
3
+ "version": "0.52.2",
4
4
  "description": "Tenant Worker adapter for Voyant Cloud Workflows deployments. Wires WorkflowRunDO, inline local dispatch, and platform step-runner bindings from env.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -26,9 +26,9 @@
26
26
  "NOTICE"
27
27
  ],
28
28
  "dependencies": {
29
- "@voyantjs/workflows": "0.52.1",
30
- "@voyantjs/workflows-orchestrator": "0.52.1",
31
- "@voyantjs/workflows-orchestrator-cloudflare": "0.52.1"
29
+ "@voyantjs/workflows": "0.52.2",
30
+ "@voyantjs/workflows-orchestrator": "0.52.2",
31
+ "@voyantjs/workflows-orchestrator-cloudflare": "0.52.2"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^20.12.0",
package/src/index.ts CHANGED
@@ -66,6 +66,8 @@ export interface CloudWorkflowsEnv {
66
66
  VOYANT_WORKFLOW_BUNDLE_R2_BUCKET?: string
67
67
  /** Optional signed URL TTL in seconds. Defaults to 300. */
68
68
  VOYANT_WORKFLOW_BUNDLE_URL_TTL_SECONDS?: string
69
+ /** Platform-managed Cloud Run node step runner endpoint. */
70
+ VOYANT_WORKFLOW_NODE_RUNNER_URL?: string
69
71
  /** Shared secret used to sign dispatches to the platform step runner. */
70
72
  VOYANT_WORKFLOW_STEP_AUTH_SECRET?: string
71
73
  }
@@ -284,6 +286,10 @@ async function createNodeStepRunner<Env extends CloudWorkflowsEnv>(
284
286
  env: Env,
285
287
  options: CloudExecutionOptions<Env>,
286
288
  ): Promise<StepRunner> {
289
+ if (env.VOYANT_WORKFLOW_NODE_RUNNER_URL) {
290
+ return createHttpNodeStepRunner(env, options)
291
+ }
292
+
287
293
  if (!env.STEP_RUNNER) {
288
294
  return createInlineNodeStepRunner(options.now)
289
295
  }
@@ -313,6 +319,142 @@ async function createNodeStepRunner<Env extends CloudWorkflowsEnv>(
313
319
  })
314
320
  }
315
321
 
322
+ async function createHttpNodeStepRunner<Env extends CloudWorkflowsEnv>(
323
+ env: Env,
324
+ options: CloudExecutionOptions<Env>,
325
+ ): Promise<StepRunner> {
326
+ const serviceUrl = env.VOYANT_WORKFLOW_NODE_RUNNER_URL?.replace(/\/+$/, "")
327
+ if (!serviceUrl) {
328
+ throw new Error("@voyantjs/workflows-cloud-adapter: VOYANT_WORKFLOW_NODE_RUNNER_URL is empty")
329
+ }
330
+ const key = env.VOYANT_WORKFLOW_BUNDLE_KEY
331
+ const hash = env.VOYANT_WORKFLOW_BUNDLE_HASH
332
+ const missing = [
333
+ ["VOYANT_WORKFLOW_BUNDLE_KEY", key],
334
+ ["VOYANT_WORKFLOW_BUNDLE_HASH", hash],
335
+ ].filter(([, value]) => typeof value !== "string" || value.length === 0)
336
+ if (missing.length > 0) {
337
+ throw new Error(
338
+ `@voyantjs/workflows-cloud-adapter: Cloud Run node runner is configured but bundle env is incomplete: ${missing
339
+ .map(([name]) => name)
340
+ .join(", ")}`,
341
+ )
342
+ }
343
+ const sign = env.VOYANT_WORKFLOW_STEP_AUTH_SECRET
344
+ ? await createHmacSigner(env.VOYANT_WORKFLOW_STEP_AUTH_SECRET)
345
+ : undefined
346
+
347
+ return async ({
348
+ stepId,
349
+ attempt,
350
+ input,
351
+ stepCtx,
352
+ runId,
353
+ workflowId,
354
+ workflowVersion,
355
+ projectId,
356
+ organizationId,
357
+ options: stepOptions,
358
+ journal,
359
+ }): Promise<StepJournalEntry> => {
360
+ const startedAt = Date.now()
361
+ const payload = {
362
+ runId,
363
+ workflowId,
364
+ workflowVersion,
365
+ projectId,
366
+ organizationId,
367
+ stepId,
368
+ attempt,
369
+ input,
370
+ options: {
371
+ machine: stepOptions.machine,
372
+ timeout:
373
+ typeof stepOptions.timeout === "string" || typeof stepOptions.timeout === "number"
374
+ ? stepOptions.timeout
375
+ : undefined,
376
+ },
377
+ bundle: {
378
+ key,
379
+ hash,
380
+ },
381
+ journal,
382
+ }
383
+ const body = JSON.stringify(payload)
384
+ const headers: Record<string, string> = {
385
+ "content-type": "application/json; charset=utf-8",
386
+ }
387
+ if (sign) headers["x-voyant-step-auth"] = await sign(body)
388
+
389
+ let response: Response
390
+ try {
391
+ response = await fetch(`${serviceUrl}/step`, {
392
+ method: "POST",
393
+ headers,
394
+ body,
395
+ signal: stepCtx.signal,
396
+ })
397
+ } catch (err) {
398
+ options.logger?.("error", "cloud-run-node: fetch threw", {
399
+ runId,
400
+ stepId,
401
+ error: err instanceof Error ? err.message : String(err),
402
+ })
403
+ return failedNodeStep(attempt, startedAt, "NODE_RUNNER_DISPATCH_FAILED", err)
404
+ }
405
+
406
+ const text = await response.text()
407
+ if (!response.ok) {
408
+ options.logger?.("warn", "cloud-run-node: non-2xx response", {
409
+ runId,
410
+ stepId,
411
+ status: response.status,
412
+ body: text.slice(0, 500),
413
+ })
414
+ return failedNodeStep(
415
+ attempt,
416
+ startedAt,
417
+ "NODE_RUNNER_HTTP_ERROR",
418
+ new Error(`node runner returned HTTP ${response.status}: ${text}`),
419
+ )
420
+ }
421
+
422
+ try {
423
+ return JSON.parse(text) as StepJournalEntry
424
+ } catch (err) {
425
+ return failedNodeStep(
426
+ attempt,
427
+ startedAt,
428
+ "NODE_RUNNER_INVALID_RESPONSE",
429
+ new Error(`node runner returned non-JSON body: ${String(err)}`),
430
+ )
431
+ }
432
+ }
433
+ }
434
+
435
+ function failedNodeStep(
436
+ attempt: number,
437
+ startedAt: number,
438
+ code: string,
439
+ err: unknown,
440
+ ): StepJournalEntry {
441
+ const e = err instanceof Error ? err : new Error(String(err))
442
+ return {
443
+ attempt,
444
+ status: "err",
445
+ startedAt,
446
+ finishedAt: Date.now(),
447
+ runtime: "node",
448
+ error: {
449
+ category: "RUNTIME_ERROR",
450
+ code,
451
+ message: e.message,
452
+ name: e.name,
453
+ stack: e.stack,
454
+ },
455
+ }
456
+ }
457
+
316
458
  function createInlineNodeStepRunner(now = () => Date.now()): StepRunner {
317
459
  return async ({ attempt, fn, stepCtx }): Promise<StepJournalEntry> => {
318
460
  const startedAt = now()