@voyant-travel/workflows-orchestrator 0.112.0 → 0.114.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/driver-inmemory.d.ts +8 -0
- package/dist/driver-inmemory.d.ts.map +1 -1
- package/dist/driver-inmemory.js +7 -2
- package/dist/node/node-selfhost-deps.d.ts.map +1 -1
- package/dist/node/node-selfhost-deps.js +9 -4
- package/dist/node/node-standalone-driver.d.ts +8 -0
- package/dist/node/node-standalone-driver.d.ts.map +1 -1
- package/dist/node/node-standalone-driver.js +7 -2
- package/package.json +2 -2
- package/src/__tests__/orchestrator-test-support.ts +11 -3
- package/src/driver-inmemory.ts +19 -2
- package/src/node/node-selfhost-deps.ts +10 -5
- package/src/node/node-standalone-driver.ts +19 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { EnvironmentName } from "@voyant-travel/workflows";
|
|
2
2
|
import { type DriverFactory } from "@voyant-travel/workflows/driver";
|
|
3
|
+
import { type WorkflowResolver } from "@voyant-travel/workflows/handler";
|
|
3
4
|
import type { RunRecord, StepHandler } from "./types.js";
|
|
4
5
|
export interface InMemoryDriverOptions {
|
|
5
6
|
/** Default environment for `trigger()` calls that don't specify one. */
|
|
@@ -8,6 +9,13 @@ export interface InMemoryDriverOptions {
|
|
|
8
9
|
tenantMeta?: RunRecord["tenantMeta"];
|
|
9
10
|
/** Injectable clock; defaults to `Date.now`. */
|
|
10
11
|
now?: () => number;
|
|
12
|
+
/**
|
|
13
|
+
* Executable workflow lookup for this driver instance.
|
|
14
|
+
*
|
|
15
|
+
* Omitting this dependency is deprecated and falls back to the process-global
|
|
16
|
+
* authoring registry for backward compatibility with existing consumers.
|
|
17
|
+
*/
|
|
18
|
+
workflowResolver?: WorkflowResolver;
|
|
11
19
|
/** Step handler override — defaults to in-process `handleStepRequest`. */
|
|
12
20
|
handler?: StepHandler;
|
|
13
21
|
/** Schedule runner tick interval. Defaults to 1_000 ms. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver-inmemory.d.ts","sourceRoot":"","sources":["../src/driver-inmemory.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"driver-inmemory.d.ts","sourceRoot":"","sources":["../src/driver-inmemory.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,eAAe,EAMhB,MAAM,0BAA0B,CAAA;AAEjC,OAAO,EACL,KAAK,aAAa,EAQnB,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,kCAAkC,CAAA;AAgBzC,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAIxD,MAAM,WAAW,qBAAqB;IACpC,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,eAAe,CAAA;IACpC,wDAAwD;IACxD,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;IACpC,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,0EAA0E;IAC1E,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,2DAA2D;IAC3D,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAYD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,qBAA0B,GAAG,aAAa,CAgUpF"}
|
package/dist/driver-inmemory.js
CHANGED
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
// call to the factory yields a fresh, isolated driver. No global state.
|
|
12
12
|
//
|
|
13
13
|
// Authoritative architecture: docs/architecture/workflows-runtime-architecture.md §6.
|
|
14
|
+
import { getWorkflow } from "@voyant-travel/workflows";
|
|
14
15
|
import { ManifestNotRegisteredError, } from "@voyant-travel/workflows/driver";
|
|
15
16
|
import { deriveStableEventId } from "@voyant-travel/workflows/events";
|
|
16
|
-
import { handleStepRequest } from "@voyant-travel/workflows/handler";
|
|
17
|
+
import { handleStepRequest, } from "@voyant-travel/workflows/handler";
|
|
17
18
|
import { createInProcessConcurrencyCoordinator, } from "./concurrency.js";
|
|
18
19
|
import { routeEvent } from "./event-router.js";
|
|
19
20
|
import { createInMemoryRunStore } from "./in-memory-store.js";
|
|
@@ -24,6 +25,9 @@ const DEFAULT_TENANT_META = {
|
|
|
24
25
|
projectId: "default",
|
|
25
26
|
organizationId: "default",
|
|
26
27
|
};
|
|
28
|
+
const legacyWorkflowResolver = {
|
|
29
|
+
resolve: getWorkflow,
|
|
30
|
+
};
|
|
27
31
|
/**
|
|
28
32
|
* Build an in-memory driver factory. The factory closes over its
|
|
29
33
|
* options and returns a fresh `WorkflowDriver` when `createApp()`
|
|
@@ -43,11 +47,12 @@ export function createInMemoryDriver(opts = {}) {
|
|
|
43
47
|
const now = opts.now ?? deps.now ?? (() => Date.now());
|
|
44
48
|
const tenantMeta = opts.tenantMeta ?? DEFAULT_TENANT_META;
|
|
45
49
|
const defaultEnv = opts.defaultEnvironment ?? "development";
|
|
50
|
+
const workflowResolver = opts.workflowResolver ?? legacyWorkflowResolver;
|
|
46
51
|
// Wire the framework-supplied service container through to step bodies.
|
|
47
52
|
// The handler closes over `deps.services` so every step invocation
|
|
48
53
|
// surfaces it as `ctx.services` inside the workflow body.
|
|
49
54
|
const handler = opts.handler ??
|
|
50
|
-
(async (req, stepOpts) => handleStepRequest(req, { services: deps.services }, stepOpts));
|
|
55
|
+
(async (req, stepOpts) => handleStepRequest(req, { workflowResolver, services: deps.services }, stepOpts));
|
|
51
56
|
let shuttingDown = false;
|
|
52
57
|
const concurrency = createInProcessConcurrencyCoordinator({
|
|
53
58
|
async cancelRun(runId, reason) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-selfhost-deps.d.ts","sourceRoot":"","sources":["../../src/node/node-selfhost-deps.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,SAAS,EACT,WAAW,EACZ,MAAM,sBAAsB,CAAA;AAwB7B,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAS3F;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,CACR,qBAAqB,EACnB,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,UAAU,GACV,OAAO,GACP,aAAa,GACb,sBAAsB,GACtB,eAAe,GACf,kBAAkB,CACrB,GACA,OAAO,CAAC,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"node-selfhost-deps.d.ts","sourceRoot":"","sources":["../../src/node/node-selfhost-deps.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAEV,qBAAqB,EACrB,SAAS,EACT,WAAW,EACZ,MAAM,sBAAsB,CAAA;AAwB7B,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAS3F;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,CACR,qBAAqB,EACnB,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,UAAU,GACV,OAAO,GACP,aAAa,GACb,sBAAsB,GACtB,eAAe,GACf,kBAAkB,CACrB,GACA,OAAO,CAAC,SAAS,CAAC,CAuapB"}
|
|
@@ -47,12 +47,17 @@ export async function createSelfHostDeps(opts) {
|
|
|
47
47
|
await assertReadableFile(entryAbs, "workflow entry");
|
|
48
48
|
await loadEntryFile(entryAbs, { cacheBust: opts.cacheBustEntry });
|
|
49
49
|
const _handlerMod = await import("@voyant-travel/workflows/handler");
|
|
50
|
+
const workflowDefinitions = wfMod.__listRegisteredWorkflows();
|
|
51
|
+
const workflowsById = new Map(workflowDefinitions.map((workflow) => [workflow.id, workflow]));
|
|
52
|
+
const workflowResolver = {
|
|
53
|
+
resolve: (workflowId) => workflowsById.get(workflowId),
|
|
54
|
+
};
|
|
50
55
|
const rateLimiter = createInMemoryRateLimiter();
|
|
51
56
|
const chunkBus = createChunkBus();
|
|
52
|
-
const stepHandler = async (req, stepOpts) => handleStepRequest(req, { rateLimiter, services: opts.services }, stepOpts);
|
|
57
|
+
const stepHandler = async (req, stepOpts) => handleStepRequest(req, { workflowResolver, rateLimiter, services: opts.services }, stepOpts);
|
|
53
58
|
const wakeupStore = pg ? createPostgresWakeupStore({ db: pg.db }) : createFsWakeupStore();
|
|
54
59
|
const leaseOwner = opts.wakeupLeaseOwner ?? createDefaultWakeupLeaseOwner();
|
|
55
|
-
const listWorkflows = () =>
|
|
60
|
+
const listWorkflows = () => workflowDefinitions.map((workflow) => ({
|
|
56
61
|
id: workflow.id,
|
|
57
62
|
description: workflow.config.description,
|
|
58
63
|
}));
|
|
@@ -162,7 +167,7 @@ export async function createSelfHostDeps(opts) {
|
|
|
162
167
|
return { ok: true, saved };
|
|
163
168
|
};
|
|
164
169
|
const triggerRun = async ({ workflowId, input, runId, tags, triggeredByUserId, }) => {
|
|
165
|
-
const workflow =
|
|
170
|
+
const workflow = workflowResolver.resolve(workflowId);
|
|
166
171
|
if (!workflow) {
|
|
167
172
|
return {
|
|
168
173
|
ok: false,
|
|
@@ -231,7 +236,7 @@ export async function createSelfHostDeps(opts) {
|
|
|
231
236
|
};
|
|
232
237
|
}
|
|
233
238
|
const workflowId = parent?.workflowId ?? requestedWorkflowId;
|
|
234
|
-
const workflow =
|
|
239
|
+
const workflow = workflowResolver.resolve(workflowId);
|
|
235
240
|
if (!workflow) {
|
|
236
241
|
return {
|
|
237
242
|
ok: false,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DriverFactory } from "@voyant-travel/workflows/driver";
|
|
2
|
+
import { type WorkflowResolver } from "@voyant-travel/workflows/handler";
|
|
2
3
|
import type { drizzle } from "drizzle-orm/node-postgres";
|
|
3
4
|
import { type RunRecord, type StepHandler } from "./core.js";
|
|
4
5
|
type Db = ReturnType<typeof drizzle>;
|
|
@@ -11,6 +12,13 @@ export interface StandaloneDriverOptions {
|
|
|
11
12
|
tenantMeta?: RunRecord["tenantMeta"];
|
|
12
13
|
/** Injectable clock; defaults to `Date.now`. */
|
|
13
14
|
now?: () => number;
|
|
15
|
+
/**
|
|
16
|
+
* Executable workflow lookup for this driver instance.
|
|
17
|
+
*
|
|
18
|
+
* Omitting this dependency is deprecated and falls back to the process-global
|
|
19
|
+
* authoring registry for backward compatibility with existing consumers.
|
|
20
|
+
*/
|
|
21
|
+
workflowResolver?: WorkflowResolver;
|
|
14
22
|
/**
|
|
15
23
|
* Step handler override. Defaults to in-process `handleStepRequest`
|
|
16
24
|
* with the framework-supplied `services` container plumbed through
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-standalone-driver.d.ts","sourceRoot":"","sources":["../../src/node/node-standalone-driver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"node-standalone-driver.d.ts","sourceRoot":"","sources":["../../src/node/node-standalone-driver.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EACV,aAAa,EAOd,MAAM,iCAAiC,CAAA;AAExC,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,kCAAkC,CAAA;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AACxD,OAAO,EAML,KAAK,SAAS,EAId,KAAK,WAAW,EAEjB,MAAM,WAAW,CAAA;AAWlB,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAA;AAIpC,MAAM,WAAW,uBAAuB;IACtC,4EAA4E;IAC5E,EAAE,EAAE,EAAE,CAAA;IACN,wEAAwE;IACxE,kBAAkB,CAAC,EAAE,YAAY,GAAG,SAAS,GAAG,aAAa,CAAA;IAC7D,wDAAwD;IACxD,UAAU,CAAC,EAAE,SAAS,CAAC,YAAY,CAAC,CAAA;IACpC,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,2DAA2D;IAC3D,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAChC;AAmGD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,uBAAuB,GAAG,aAAa,CAwXnF"}
|
|
@@ -17,8 +17,9 @@
|
|
|
17
17
|
// `createApp()` — by the framework's bootstrap.
|
|
18
18
|
//
|
|
19
19
|
// See docs/architecture/workflows-runtime-architecture.md.
|
|
20
|
+
import { getWorkflow } from "@voyant-travel/workflows";
|
|
20
21
|
import { deriveStableEventId } from "@voyant-travel/workflows/events";
|
|
21
|
-
import { handleStepRequest } from "@voyant-travel/workflows/handler";
|
|
22
|
+
import { handleStepRequest, } from "@voyant-travel/workflows/handler";
|
|
22
23
|
import { createInProcessConcurrencyCoordinator, createScheduler, manifestScheduleSources, cancel as orchestratorCancel, trigger as orchestratorTrigger, routeEvent, } from "./core.js";
|
|
23
24
|
import { createPersistentWakeupManager, } from "./persistent-wakeup-manager.js";
|
|
24
25
|
import { createPostgresManifestStore } from "./postgres-manifest-store.js";
|
|
@@ -31,6 +32,9 @@ const DEFAULT_TENANT_META = {
|
|
|
31
32
|
organizationId: "default",
|
|
32
33
|
};
|
|
33
34
|
const DEFAULT_MANIFEST_KEEP = 3;
|
|
35
|
+
const legacyWorkflowResolver = {
|
|
36
|
+
resolve: getWorkflow,
|
|
37
|
+
};
|
|
34
38
|
function serializeWorkflowManifest(manifest) {
|
|
35
39
|
return { ...manifest };
|
|
36
40
|
}
|
|
@@ -121,11 +125,12 @@ export function createStandaloneDriver(opts) {
|
|
|
121
125
|
const defaultEnv = opts.defaultEnvironment ?? "development";
|
|
122
126
|
const keep = opts.manifestVersionsToKeep ?? DEFAULT_MANIFEST_KEEP;
|
|
123
127
|
const leaseOwner = opts.wakeupLeaseOwner ?? `selfhost-standalone-${randomToken()}`;
|
|
128
|
+
const workflowResolver = opts.workflowResolver ?? legacyWorkflowResolver;
|
|
124
129
|
// Wire the framework-supplied service container through to step bodies.
|
|
125
130
|
// The handler closes over `deps.services` so every step invocation
|
|
126
131
|
// surfaces it as `ctx.services` inside the workflow body.
|
|
127
132
|
const handler = opts.handler ??
|
|
128
|
-
(async (req, stepOpts) => handleStepRequest(req, { services: deps.services }, stepOpts));
|
|
133
|
+
(async (req, stepOpts) => handleStepRequest(req, { workflowResolver, services: deps.services }, stepOpts));
|
|
129
134
|
// Persistent wakeup manager — polls `voyant_wakeups` for runs
|
|
130
135
|
// parked on DATETIME waitpoints and resumes them via the orchestrator's
|
|
131
136
|
// `resumeDueAlarms`. This is what makes `ctx.sleep(...)` actually
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyant-travel/workflows-orchestrator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.114.0",
|
|
4
4
|
"description": "Postgres self-host orchestrator runtime for Voyant Workflows — drives runs through the tenant step handler over the v1 wire protocol.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"drizzle-orm": "^0.45.2",
|
|
51
51
|
"pg": "^8.22.0",
|
|
52
|
-
"@voyant-travel/workflows": "^0.
|
|
52
|
+
"@voyant-travel/workflows": "^0.114.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@types/node": "^25.5.2",
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
import { __resetRegistry } from "@voyant-travel/workflows"
|
|
2
|
-
import {
|
|
1
|
+
import { __resetRegistry, getWorkflow } from "@voyant-travel/workflows"
|
|
2
|
+
import {
|
|
3
|
+
handleStepRequest,
|
|
4
|
+
type WorkflowResolver,
|
|
5
|
+
type WorkflowStepRequest,
|
|
6
|
+
} from "@voyant-travel/workflows/handler"
|
|
3
7
|
import { beforeEach } from "vitest"
|
|
4
8
|
import type { StepHandler } from "../index.js"
|
|
5
9
|
|
|
10
|
+
export const workflowResolver: WorkflowResolver = {
|
|
11
|
+
resolve: (workflowId) => getWorkflow(workflowId),
|
|
12
|
+
}
|
|
13
|
+
|
|
6
14
|
export const handler: StepHandler = async (req: WorkflowStepRequest, opts) => {
|
|
7
|
-
return await handleStepRequest(req, {}, opts)
|
|
15
|
+
return await handleStepRequest(req, { workflowResolver }, opts)
|
|
8
16
|
}
|
|
9
17
|
|
|
10
18
|
export const tenantMeta = {
|
package/src/driver-inmemory.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
RunSummary,
|
|
21
21
|
TriggerOptions,
|
|
22
22
|
} from "@voyant-travel/workflows"
|
|
23
|
+
import { getWorkflow } from "@voyant-travel/workflows"
|
|
23
24
|
import {
|
|
24
25
|
type DriverFactory,
|
|
25
26
|
type DriverFactoryDeps,
|
|
@@ -31,7 +32,11 @@ import {
|
|
|
31
32
|
type WorkflowDriver,
|
|
32
33
|
} from "@voyant-travel/workflows/driver"
|
|
33
34
|
import { deriveStableEventId } from "@voyant-travel/workflows/events"
|
|
34
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
handleStepRequest,
|
|
37
|
+
type WorkflowResolver,
|
|
38
|
+
type WorkflowStepRequest,
|
|
39
|
+
} from "@voyant-travel/workflows/handler"
|
|
35
40
|
import type { WorkflowManifest } from "@voyant-travel/workflows/protocol"
|
|
36
41
|
|
|
37
42
|
import {
|
|
@@ -58,6 +63,13 @@ export interface InMemoryDriverOptions {
|
|
|
58
63
|
tenantMeta?: RunRecord["tenantMeta"]
|
|
59
64
|
/** Injectable clock; defaults to `Date.now`. */
|
|
60
65
|
now?: () => number
|
|
66
|
+
/**
|
|
67
|
+
* Executable workflow lookup for this driver instance.
|
|
68
|
+
*
|
|
69
|
+
* Omitting this dependency is deprecated and falls back to the process-global
|
|
70
|
+
* authoring registry for backward compatibility with existing consumers.
|
|
71
|
+
*/
|
|
72
|
+
workflowResolver?: WorkflowResolver
|
|
61
73
|
/** Step handler override — defaults to in-process `handleStepRequest`. */
|
|
62
74
|
handler?: StepHandler
|
|
63
75
|
/** Schedule runner tick interval. Defaults to 1_000 ms. */
|
|
@@ -72,6 +84,10 @@ const DEFAULT_TENANT_META: RunRecord["tenantMeta"] = {
|
|
|
72
84
|
organizationId: "default",
|
|
73
85
|
}
|
|
74
86
|
|
|
87
|
+
const legacyWorkflowResolver: WorkflowResolver = {
|
|
88
|
+
resolve: getWorkflow,
|
|
89
|
+
}
|
|
90
|
+
|
|
75
91
|
/**
|
|
76
92
|
* Build an in-memory driver factory. The factory closes over its
|
|
77
93
|
* options and returns a fresh `WorkflowDriver` when `createApp()`
|
|
@@ -91,13 +107,14 @@ export function createInMemoryDriver(opts: InMemoryDriverOptions = {}): DriverFa
|
|
|
91
107
|
const now = opts.now ?? deps.now ?? (() => Date.now())
|
|
92
108
|
const tenantMeta = opts.tenantMeta ?? DEFAULT_TENANT_META
|
|
93
109
|
const defaultEnv: EnvironmentName = opts.defaultEnvironment ?? "development"
|
|
110
|
+
const workflowResolver = opts.workflowResolver ?? legacyWorkflowResolver
|
|
94
111
|
// Wire the framework-supplied service container through to step bodies.
|
|
95
112
|
// The handler closes over `deps.services` so every step invocation
|
|
96
113
|
// surfaces it as `ctx.services` inside the workflow body.
|
|
97
114
|
const handler: StepHandler =
|
|
98
115
|
opts.handler ??
|
|
99
116
|
(async (req: WorkflowStepRequest, stepOpts) =>
|
|
100
|
-
handleStepRequest(req, { services: deps.services }, stepOpts))
|
|
117
|
+
handleStepRequest(req, { workflowResolver, services: deps.services }, stepOpts))
|
|
101
118
|
|
|
102
119
|
let shuttingDown = false
|
|
103
120
|
const concurrency = createInProcessConcurrencyCoordinator({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createServer } from "node:http"
|
|
2
2
|
import { resolve as resolvePath } from "node:path"
|
|
3
|
-
import { handleStepRequest } from "@voyant-travel/workflows/handler"
|
|
3
|
+
import { handleStepRequest, type WorkflowResolver } from "@voyant-travel/workflows/handler"
|
|
4
4
|
import { createInMemoryRateLimiter } from "@voyant-travel/workflows/rate-limit"
|
|
5
5
|
import {
|
|
6
6
|
createInMemoryRunStore,
|
|
@@ -94,17 +94,22 @@ export async function createSelfHostDeps(
|
|
|
94
94
|
await loadEntryFile(entryAbs, { cacheBust: opts.cacheBustEntry })
|
|
95
95
|
|
|
96
96
|
const _handlerMod = await import("@voyant-travel/workflows/handler")
|
|
97
|
+
const workflowDefinitions = wfMod.__listRegisteredWorkflows()
|
|
98
|
+
const workflowsById = new Map(workflowDefinitions.map((workflow) => [workflow.id, workflow]))
|
|
99
|
+
const workflowResolver: WorkflowResolver = {
|
|
100
|
+
resolve: (workflowId) => workflowsById.get(workflowId),
|
|
101
|
+
}
|
|
97
102
|
const rateLimiter = createInMemoryRateLimiter()
|
|
98
103
|
const chunkBus = createChunkBus()
|
|
99
104
|
|
|
100
105
|
const stepHandler: StepHandler = async (req, stepOpts) =>
|
|
101
|
-
handleStepRequest(req, { rateLimiter, services: opts.services }, stepOpts)
|
|
106
|
+
handleStepRequest(req, { workflowResolver, rateLimiter, services: opts.services }, stepOpts)
|
|
102
107
|
|
|
103
108
|
const wakeupStore = pg ? createPostgresWakeupStore({ db: pg.db }) : createFsWakeupStore()
|
|
104
109
|
const leaseOwner = opts.wakeupLeaseOwner ?? createDefaultWakeupLeaseOwner()
|
|
105
110
|
|
|
106
111
|
const listWorkflows = () =>
|
|
107
|
-
|
|
112
|
+
workflowDefinitions.map((workflow) => ({
|
|
108
113
|
id: workflow.id,
|
|
109
114
|
description: workflow.config.description,
|
|
110
115
|
}))
|
|
@@ -227,7 +232,7 @@ export async function createSelfHostDeps(
|
|
|
227
232
|
tags,
|
|
228
233
|
triggeredByUserId,
|
|
229
234
|
}) => {
|
|
230
|
-
const workflow =
|
|
235
|
+
const workflow = workflowResolver.resolve(workflowId)
|
|
231
236
|
if (!workflow) {
|
|
232
237
|
return {
|
|
233
238
|
ok: false,
|
|
@@ -309,7 +314,7 @@ export async function createSelfHostDeps(
|
|
|
309
314
|
}
|
|
310
315
|
|
|
311
316
|
const workflowId = parent?.workflowId ?? requestedWorkflowId!
|
|
312
|
-
const workflow =
|
|
317
|
+
const workflow = workflowResolver.resolve(workflowId)
|
|
313
318
|
if (!workflow) {
|
|
314
319
|
return {
|
|
315
320
|
ok: false,
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
RunSummary,
|
|
26
26
|
TriggerOptions,
|
|
27
27
|
} from "@voyant-travel/workflows"
|
|
28
|
+
import { getWorkflow } from "@voyant-travel/workflows"
|
|
28
29
|
import type {
|
|
29
30
|
DriverFactory,
|
|
30
31
|
DriverFactoryDeps,
|
|
@@ -35,7 +36,11 @@ import type {
|
|
|
35
36
|
WorkflowDriver,
|
|
36
37
|
} from "@voyant-travel/workflows/driver"
|
|
37
38
|
import { deriveStableEventId } from "@voyant-travel/workflows/events"
|
|
38
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
handleStepRequest,
|
|
41
|
+
type WorkflowResolver,
|
|
42
|
+
type WorkflowStepRequest,
|
|
43
|
+
} from "@voyant-travel/workflows/handler"
|
|
39
44
|
import type { WorkflowManifest } from "@voyant-travel/workflows/protocol"
|
|
40
45
|
import type { drizzle } from "drizzle-orm/node-postgres"
|
|
41
46
|
import {
|
|
@@ -74,6 +79,13 @@ export interface StandaloneDriverOptions {
|
|
|
74
79
|
tenantMeta?: RunRecord["tenantMeta"]
|
|
75
80
|
/** Injectable clock; defaults to `Date.now`. */
|
|
76
81
|
now?: () => number
|
|
82
|
+
/**
|
|
83
|
+
* Executable workflow lookup for this driver instance.
|
|
84
|
+
*
|
|
85
|
+
* Omitting this dependency is deprecated and falls back to the process-global
|
|
86
|
+
* authoring registry for backward compatibility with existing consumers.
|
|
87
|
+
*/
|
|
88
|
+
workflowResolver?: WorkflowResolver
|
|
77
89
|
/**
|
|
78
90
|
* Step handler override. Defaults to in-process `handleStepRequest`
|
|
79
91
|
* with the framework-supplied `services` container plumbed through
|
|
@@ -126,6 +138,10 @@ const DEFAULT_TENANT_META: RunRecord["tenantMeta"] = {
|
|
|
126
138
|
|
|
127
139
|
const DEFAULT_MANIFEST_KEEP = 3
|
|
128
140
|
|
|
141
|
+
const legacyWorkflowResolver: WorkflowResolver = {
|
|
142
|
+
resolve: getWorkflow,
|
|
143
|
+
}
|
|
144
|
+
|
|
129
145
|
function serializeWorkflowManifest(manifest: WorkflowManifest): Record<string, unknown> {
|
|
130
146
|
return { ...manifest }
|
|
131
147
|
}
|
|
@@ -238,6 +254,7 @@ export function createStandaloneDriver(opts: StandaloneDriverOptions): DriverFac
|
|
|
238
254
|
const defaultEnv = opts.defaultEnvironment ?? "development"
|
|
239
255
|
const keep = opts.manifestVersionsToKeep ?? DEFAULT_MANIFEST_KEEP
|
|
240
256
|
const leaseOwner = opts.wakeupLeaseOwner ?? `selfhost-standalone-${randomToken()}`
|
|
257
|
+
const workflowResolver = opts.workflowResolver ?? legacyWorkflowResolver
|
|
241
258
|
|
|
242
259
|
// Wire the framework-supplied service container through to step bodies.
|
|
243
260
|
// The handler closes over `deps.services` so every step invocation
|
|
@@ -245,7 +262,7 @@ export function createStandaloneDriver(opts: StandaloneDriverOptions): DriverFac
|
|
|
245
262
|
const handler: StepHandler =
|
|
246
263
|
opts.handler ??
|
|
247
264
|
(async (req: WorkflowStepRequest, stepOpts) =>
|
|
248
|
-
handleStepRequest(req, { services: deps.services }, stepOpts))
|
|
265
|
+
handleStepRequest(req, { workflowResolver, services: deps.services }, stepOpts))
|
|
249
266
|
|
|
250
267
|
// Persistent wakeup manager — polls `voyant_wakeups` for runs
|
|
251
268
|
// parked on DATETIME waitpoints and resumes them via the orchestrator's
|