@voyantjs/workflows-cloud-adapter 0.52.0 → 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 +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +103 -0
- package/package.json +4 -4
- package/src/index.ts +142 -0
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
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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":"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"}
|
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.
|
|
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.
|
|
30
|
-
"@voyantjs/workflows-orchestrator": "0.52.
|
|
31
|
-
"@voyantjs/workflows-orchestrator-cloudflare": "0.52.
|
|
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()
|