@voyantjs/workflows-orchestrator-node 0.107.5 → 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.
- package/dist/dashboard-chunks.d.ts +17 -0
- package/dist/dashboard-chunks.d.ts.map +1 -0
- package/dist/dashboard-chunks.js +19 -0
- package/dist/dashboard-http-server.d.ts +6 -0
- package/dist/dashboard-http-server.d.ts.map +1 -0
- package/dist/dashboard-http-server.js +99 -0
- package/dist/dashboard-metrics.d.ts +3 -0
- package/dist/dashboard-metrics.d.ts.map +1 -0
- package/dist/dashboard-metrics.js +26 -0
- package/dist/dashboard-request.d.ts +7 -0
- package/dist/dashboard-request.d.ts.map +1 -0
- package/dist/dashboard-request.js +436 -0
- package/dist/dashboard-server.d.ts +9 -171
- package/dist/dashboard-server.d.ts.map +1 -1
- package/dist/dashboard-server.js +7 -1229
- package/dist/dashboard-sse.d.ts +7 -0
- package/dist/dashboard-sse.d.ts.map +1 -0
- package/dist/dashboard-sse.js +134 -0
- package/dist/dashboard-static.d.ts +7 -0
- package/dist/dashboard-static.d.ts.map +1 -0
- package/dist/dashboard-static.js +89 -0
- package/dist/dashboard-types.d.ts +134 -0
- package/dist/dashboard-types.d.ts.map +1 -0
- package/dist/dashboard-types.js +1 -0
- package/dist/node-selfhost-defaults.d.ts +7 -0
- package/dist/node-selfhost-defaults.d.ts.map +1 -0
- package/dist/node-selfhost-defaults.js +8 -0
- package/dist/node-selfhost-deps.d.ts +4 -0
- package/dist/node-selfhost-deps.d.ts.map +1 -0
- package/dist/node-selfhost-deps.js +403 -0
- package/dist/node-selfhost-resume-input.d.ts +4 -0
- package/dist/node-selfhost-resume-input.d.ts.map +1 -0
- package/dist/node-selfhost-resume-input.js +20 -0
- package/dist/node-standalone-driver.d.ts.map +1 -1
- package/dist/node-standalone-driver.js +40 -3
- package/dist/node-step-runner.d.ts +3 -0
- package/dist/node-step-runner.d.ts.map +1 -0
- package/dist/node-step-runner.js +26 -0
- package/dist/postgres-manifest-store.d.ts.map +1 -1
- package/dist/postgres-manifest-store.js +6 -2
- package/dist/postgres-run-record-store.js +1 -1
- package/dist/postgres-schema.d.ts.map +1 -1
- package/dist/postgres-schema.js +2 -0
- package/dist/sleep-alarm-manager.d.ts.map +1 -1
- package/dist/sleep-alarm-manager.js +9 -1
- package/dist/store-stream.d.ts.map +1 -1
- package/dist/store-stream.js +9 -1
- package/dist/wakeup-poller.d.ts.map +1 -1
- package/dist/wakeup-poller.js +9 -1
- package/package.json +3 -3
- package/src/dashboard-chunks.ts +35 -0
- package/src/dashboard-http-server.ts +118 -0
- package/src/dashboard-metrics.ts +39 -0
- package/src/dashboard-request.ts +488 -0
- package/src/dashboard-server.ts +17 -1535
- package/src/dashboard-sse.ts +150 -0
- package/src/dashboard-static.ts +88 -0
- package/src/dashboard-types.ts +106 -0
- package/src/node-selfhost-defaults.ts +9 -0
- package/src/node-selfhost-deps.ts +495 -0
- package/src/node-selfhost-resume-input.ts +27 -0
- package/src/node-standalone-driver.ts +59 -3
- package/src/node-step-runner.ts +28 -0
- package/src/postgres-manifest-store.ts +2 -0
- package/src/postgres-run-record-store.ts +1 -1
- package/src/postgres-schema.ts +2 -0
- package/src/sleep-alarm-manager.ts +12 -1
- package/src/store-stream.ts +12 -1
- package/src/wakeup-poller.ts +12 -1
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { resolve as resolvePath } from "node:path";
|
|
3
|
+
import { handleStepRequest } from "@voyantjs/workflows/handler";
|
|
4
|
+
import { createInMemoryRateLimiter } from "@voyantjs/workflows/rate-limit";
|
|
5
|
+
import { createInMemoryRunStore, resume, resumeDueAlarms, trigger, } from "@voyantjs/workflows-orchestrator";
|
|
6
|
+
import { createChunkBus } from "./dashboard-chunks.js";
|
|
7
|
+
import { startServer } from "./dashboard-http-server.js";
|
|
8
|
+
import { renderMetrics } from "./dashboard-metrics.js";
|
|
9
|
+
import { assertReadableDirectory, assertReadableFile, findDashboardDir, } from "./dashboard-static.js";
|
|
10
|
+
import { loadEntryFile } from "./entry-loader.js";
|
|
11
|
+
import { durationToMs, generateLocalRunId } from "./local-runtime.js";
|
|
12
|
+
import { createDefaultWakeupLeaseOwner, localTenantMeta } from "./node-selfhost-defaults.js";
|
|
13
|
+
import { mergeTags, requireExternalResumeFromStep, requireExternalSeedResults, } from "./node-selfhost-resume-input.js";
|
|
14
|
+
import { nodeStepRunner } from "./node-step-runner.js";
|
|
15
|
+
import { createPersistentWakeupManager } from "./persistent-wakeup-manager.js";
|
|
16
|
+
import { createPostgresConnection } from "./postgres.js";
|
|
17
|
+
import { createPostgresSnapshotRunStore } from "./postgres-snapshot-run-store.js";
|
|
18
|
+
import { createPostgresWakeupStore } from "./postgres-wakeup-store.js";
|
|
19
|
+
import { buildResumeJournal, buildSeededResumeJournal } from "./resume-run.js";
|
|
20
|
+
import { recordToSnapshot, snapshotToRecord } from "./run-record-snapshot.js";
|
|
21
|
+
import { createScheduler } from "./scheduler.js";
|
|
22
|
+
import { createFsSnapshotRunStore } from "./snapshot-run-store.js";
|
|
23
|
+
import { createFsWakeupStore } from "./wakeup-store.js";
|
|
24
|
+
export async function startNodeSelfHostServer(opts) {
|
|
25
|
+
const deps = await createNodeSelfHostDeps(opts);
|
|
26
|
+
return startServer({
|
|
27
|
+
port: opts.port ?? 3232,
|
|
28
|
+
host: opts.host ?? "127.0.0.1",
|
|
29
|
+
}, deps);
|
|
30
|
+
}
|
|
31
|
+
export async function createNodeSelfHostDeps(opts) {
|
|
32
|
+
let staticDir = opts.staticDir;
|
|
33
|
+
if (!staticDir)
|
|
34
|
+
staticDir = await findDashboardDir(process.cwd());
|
|
35
|
+
if (!staticDir && typeof import.meta.url === "string") {
|
|
36
|
+
const here = resolvePath(new URL(".", import.meta.url).pathname);
|
|
37
|
+
staticDir = await findDashboardDir(here);
|
|
38
|
+
}
|
|
39
|
+
if (staticDir) {
|
|
40
|
+
await assertReadableDirectory(staticDir, "dashboard static dir");
|
|
41
|
+
}
|
|
42
|
+
const databaseUrl = opts.databaseUrl ?? process.env.DATABASE_URL;
|
|
43
|
+
const pg = databaseUrl ? createPostgresConnection({ databaseUrl }) : undefined;
|
|
44
|
+
const store = opts.store ?? (pg ? createPostgresSnapshotRunStore({ db: pg.db }) : createFsSnapshotRunStore());
|
|
45
|
+
const wfMod = await import("@voyantjs/workflows");
|
|
46
|
+
wfMod.__resetRegistry();
|
|
47
|
+
const entryAbs = resolvePath(process.cwd(), opts.entryFile);
|
|
48
|
+
await assertReadableFile(entryAbs, "workflow entry");
|
|
49
|
+
await loadEntryFile(entryAbs, { cacheBust: opts.cacheBustEntry });
|
|
50
|
+
const _handlerMod = await import("@voyantjs/workflows/handler");
|
|
51
|
+
const rateLimiter = createInMemoryRateLimiter();
|
|
52
|
+
const chunkBus = createChunkBus();
|
|
53
|
+
const stepHandler = async (req, stepOpts) => handleStepRequest(req, { rateLimiter, nodeStepRunner, services: opts.services }, stepOpts);
|
|
54
|
+
const wakeupStore = pg ? createPostgresWakeupStore({ db: pg.db }) : createFsWakeupStore();
|
|
55
|
+
const leaseOwner = opts.wakeupLeaseOwner ?? createDefaultWakeupLeaseOwner();
|
|
56
|
+
const listWorkflows = () => wfMod.__listRegisteredWorkflows().map((workflow) => ({
|
|
57
|
+
id: workflow.id,
|
|
58
|
+
description: workflow.config.description,
|
|
59
|
+
}));
|
|
60
|
+
const registeredWorkflows = listWorkflows();
|
|
61
|
+
if (registeredWorkflows.length === 0) {
|
|
62
|
+
throw new Error("voyant workflows selfhost: workflow entry registered no workflows. " +
|
|
63
|
+
`Check "${entryAbs}" and ensure it calls workflow(...).`);
|
|
64
|
+
}
|
|
65
|
+
const healthCheck = () => ({
|
|
66
|
+
ok: true,
|
|
67
|
+
service: "voyant-workflows-selfhost",
|
|
68
|
+
});
|
|
69
|
+
const readinessCheck = async () => {
|
|
70
|
+
const checks = {
|
|
71
|
+
workflowEntry: "ok",
|
|
72
|
+
};
|
|
73
|
+
const details = {};
|
|
74
|
+
if (pg) {
|
|
75
|
+
try {
|
|
76
|
+
await pg.pool.query("select 1");
|
|
77
|
+
checks.database = "ok";
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
checks.database = "error";
|
|
81
|
+
details.database = err instanceof Error ? err.message : String(err);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
ok: Object.values(checks).every((status) => status === "ok"),
|
|
86
|
+
service: "voyant-workflows-selfhost",
|
|
87
|
+
checks,
|
|
88
|
+
details: Object.keys(details).length > 0 ? details : undefined,
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
const collectMetrics = async () => {
|
|
92
|
+
const runs = await store.list();
|
|
93
|
+
const wakeups = await wakeupStore.list();
|
|
94
|
+
const runsByStatus = runs.reduce((acc, run) => {
|
|
95
|
+
acc[run.status] = (acc[run.status] ?? 0) + 1;
|
|
96
|
+
return acc;
|
|
97
|
+
}, {});
|
|
98
|
+
return renderMetrics({
|
|
99
|
+
workflowsRegistered: listWorkflows().length,
|
|
100
|
+
schedulesRegistered: listSchedules ? listSchedules().length : 0,
|
|
101
|
+
runsTotal: runs.length,
|
|
102
|
+
wakeupsTotal: wakeups.length,
|
|
103
|
+
runsByStatus,
|
|
104
|
+
generatedAtMs: Date.now(),
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const wakeupManager = createPersistentWakeupManager({
|
|
108
|
+
wakeupStore,
|
|
109
|
+
listRuns: () => store.list(),
|
|
110
|
+
getRun: (runId) => store.get(runId),
|
|
111
|
+
saveRun: async (stored) => {
|
|
112
|
+
if (!store.update) {
|
|
113
|
+
throw new Error("snapshot run store does not support update");
|
|
114
|
+
}
|
|
115
|
+
return store.update(stored);
|
|
116
|
+
},
|
|
117
|
+
toRecord: (stored) => snapshotToRecord(stored),
|
|
118
|
+
fromRecord: (record, base) => recordToSnapshot(record, base),
|
|
119
|
+
handler: stepHandler,
|
|
120
|
+
onStreamChunk: ({ runId, chunk }) => chunkBus.publish({ runId, chunk }),
|
|
121
|
+
logger: (level, message, data) => {
|
|
122
|
+
const error = typeof data === "object" && data !== null && "error" in data ? data.error : undefined;
|
|
123
|
+
const details = error ? `: ${String(error)}` : "";
|
|
124
|
+
if (level === "error")
|
|
125
|
+
console.error(`[voyant] ${message}${details}`);
|
|
126
|
+
else
|
|
127
|
+
console.warn(`[voyant] ${message}${details}`);
|
|
128
|
+
},
|
|
129
|
+
createRunStore: createInMemoryRunStore,
|
|
130
|
+
resumeDueAlarmsImpl: resumeDueAlarms,
|
|
131
|
+
leaseOwner,
|
|
132
|
+
intervalMs: opts.wakeupPollIntervalMs,
|
|
133
|
+
leaseMs: opts.wakeupLeaseMs,
|
|
134
|
+
});
|
|
135
|
+
const cancelRun = async ({ runId }) => {
|
|
136
|
+
const existing = await store.get(runId);
|
|
137
|
+
if (!existing)
|
|
138
|
+
return { ok: false, message: `run "${runId}" not found`, exitCode: 1 };
|
|
139
|
+
if (existing.status !== "waiting") {
|
|
140
|
+
return {
|
|
141
|
+
ok: false,
|
|
142
|
+
message: `run "${runId}" is not parked (status: ${existing.status})`,
|
|
143
|
+
exitCode: 2,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (!store.update) {
|
|
147
|
+
return { ok: false, message: "snapshot run store does not support update", exitCode: 1 };
|
|
148
|
+
}
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
const updated = {
|
|
151
|
+
...existing,
|
|
152
|
+
status: "cancelled",
|
|
153
|
+
completedAt: now,
|
|
154
|
+
durationMs: now - existing.startedAt,
|
|
155
|
+
result: {
|
|
156
|
+
...existing.result,
|
|
157
|
+
status: "cancelled",
|
|
158
|
+
cancelledAt: now,
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
const saved = await store.update(updated);
|
|
162
|
+
await wakeupManager.clear(runId);
|
|
163
|
+
return { ok: true, saved };
|
|
164
|
+
};
|
|
165
|
+
const triggerRun = async ({ workflowId, input, runId, tags, triggeredByUserId, }) => {
|
|
166
|
+
const workflow = wfMod.__listRegisteredWorkflows().find((entry) => entry.id === workflowId);
|
|
167
|
+
if (!workflow) {
|
|
168
|
+
return {
|
|
169
|
+
ok: false,
|
|
170
|
+
message: `workflow "${workflowId}" is not registered in ${entryAbs}.`,
|
|
171
|
+
exitCode: 2,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
const nextRunId = runId ?? generateLocalRunId();
|
|
175
|
+
const memStore = createInMemoryRunStore();
|
|
176
|
+
let record;
|
|
177
|
+
try {
|
|
178
|
+
record = await trigger({
|
|
179
|
+
runId: nextRunId,
|
|
180
|
+
workflowId,
|
|
181
|
+
workflowVersion: "local",
|
|
182
|
+
input,
|
|
183
|
+
tenantMeta: localTenantMeta,
|
|
184
|
+
tags,
|
|
185
|
+
triggeredBy: triggeredByUserId === undefined || triggeredByUserId === null
|
|
186
|
+
? { kind: "api" }
|
|
187
|
+
: { kind: "api", actor: triggeredByUserId },
|
|
188
|
+
timeoutMs: durationToMs(workflow.config.timeout),
|
|
189
|
+
}, {
|
|
190
|
+
store: memStore,
|
|
191
|
+
handler: stepHandler,
|
|
192
|
+
onStreamChunk: (chunk) => chunkBus.publish({ runId: nextRunId, chunk }),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
return {
|
|
197
|
+
ok: false,
|
|
198
|
+
message: err instanceof Error ? err.message : String(err),
|
|
199
|
+
exitCode: 1,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if (!store.update) {
|
|
203
|
+
return { ok: false, message: "snapshot run store does not support update", exitCode: 1 };
|
|
204
|
+
}
|
|
205
|
+
const stored = recordToSnapshot(record);
|
|
206
|
+
stored.entryFile = entryAbs;
|
|
207
|
+
const saved = await store.update(stored);
|
|
208
|
+
await wakeupManager.syncStoredRun(saved);
|
|
209
|
+
return { ok: true, saved };
|
|
210
|
+
};
|
|
211
|
+
const resumeRun = async ({ parentRunId, workflowId: requestedWorkflowId, input, resumeFromStep, seedResults, runId, tags, triggeredByUserId, }) => {
|
|
212
|
+
const existing = await store.get(parentRunId);
|
|
213
|
+
let parent;
|
|
214
|
+
if (existing) {
|
|
215
|
+
try {
|
|
216
|
+
parent = snapshotToRecord(existing);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
return {
|
|
220
|
+
ok: false,
|
|
221
|
+
message: err instanceof Error ? err.message : String(err),
|
|
222
|
+
exitCode: 1,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (!requestedWorkflowId) {
|
|
227
|
+
return {
|
|
228
|
+
ok: false,
|
|
229
|
+
message: `parent run "${parentRunId}" not found; pass workflowId, resumeFromStep, ` +
|
|
230
|
+
"and seedResults to resume from an external workflow-runs parent",
|
|
231
|
+
exitCode: 1,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const workflowId = parent?.workflowId ?? requestedWorkflowId;
|
|
235
|
+
const workflow = wfMod.__listRegisteredWorkflows().find((entry) => entry.id === workflowId);
|
|
236
|
+
if (!workflow) {
|
|
237
|
+
return {
|
|
238
|
+
ok: false,
|
|
239
|
+
message: `workflow "${workflowId}" is not registered in ${entryAbs}.`,
|
|
240
|
+
exitCode: 2,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
let resumeSeed;
|
|
244
|
+
try {
|
|
245
|
+
resumeSeed = parent
|
|
246
|
+
? buildResumeJournal({
|
|
247
|
+
parent,
|
|
248
|
+
resumeFromStep,
|
|
249
|
+
seedResults,
|
|
250
|
+
})
|
|
251
|
+
: buildSeededResumeJournal({
|
|
252
|
+
parentRunId,
|
|
253
|
+
resumeFromStep: requireExternalResumeFromStep(resumeFromStep),
|
|
254
|
+
seedResults: requireExternalSeedResults(seedResults),
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
catch (err) {
|
|
258
|
+
return {
|
|
259
|
+
ok: false,
|
|
260
|
+
message: err instanceof Error ? err.message : String(err),
|
|
261
|
+
exitCode: 2,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
const memStore = createInMemoryRunStore();
|
|
265
|
+
const nextRunId = runId ?? generateLocalRunId();
|
|
266
|
+
let record;
|
|
267
|
+
try {
|
|
268
|
+
record = await trigger({
|
|
269
|
+
runId: nextRunId,
|
|
270
|
+
workflowId,
|
|
271
|
+
workflowVersion: parent?.workflowVersion ?? "local",
|
|
272
|
+
input: input === undefined ? parent?.input : input,
|
|
273
|
+
tenantMeta: parent?.tenantMeta ?? localTenantMeta,
|
|
274
|
+
environment: parent?.environment,
|
|
275
|
+
triggeredBy: triggeredByUserId === undefined || triggeredByUserId === null
|
|
276
|
+
? { kind: "api" }
|
|
277
|
+
: { kind: "api", actor: triggeredByUserId },
|
|
278
|
+
tags: mergeTags(parent?.tags, [
|
|
279
|
+
"resume:true",
|
|
280
|
+
`parentRunId:${parent?.id ?? parentRunId}`,
|
|
281
|
+
...(tags ?? []),
|
|
282
|
+
]),
|
|
283
|
+
timeoutMs: durationToMs(workflow.config.timeout),
|
|
284
|
+
initialJournal: resumeSeed.journal,
|
|
285
|
+
initialMetadataAppliedCount: resumeSeed.metadataAppliedCount,
|
|
286
|
+
}, {
|
|
287
|
+
store: memStore,
|
|
288
|
+
handler: stepHandler,
|
|
289
|
+
onStreamChunk: (chunk) => chunkBus.publish({ runId: nextRunId, chunk }),
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
return {
|
|
294
|
+
ok: false,
|
|
295
|
+
message: err instanceof Error ? err.message : String(err),
|
|
296
|
+
exitCode: 1,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
if (!store.update) {
|
|
300
|
+
return { ok: false, message: "snapshot run store does not support update", exitCode: 1 };
|
|
301
|
+
}
|
|
302
|
+
const stored = recordToSnapshot(record, {
|
|
303
|
+
entryFile: entryAbs,
|
|
304
|
+
replayOf: parent?.id ?? parentRunId,
|
|
305
|
+
});
|
|
306
|
+
const saved = await store.update(stored);
|
|
307
|
+
await wakeupManager.syncStoredRun(saved);
|
|
308
|
+
return {
|
|
309
|
+
ok: true,
|
|
310
|
+
saved,
|
|
311
|
+
parentRunId: parent?.id ?? parentRunId,
|
|
312
|
+
resumeFromStep: resumeSeed.resumeFromStep,
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
const injectWaitpoint = async ({ runId, injection }) => {
|
|
316
|
+
const existing = await store.get(runId);
|
|
317
|
+
if (!existing) {
|
|
318
|
+
return { ok: false, message: `run "${runId}" not found`, exitCode: 1 };
|
|
319
|
+
}
|
|
320
|
+
if (existing.status !== "waiting") {
|
|
321
|
+
return {
|
|
322
|
+
ok: false,
|
|
323
|
+
message: `run "${runId}" is not parked (status: ${existing.status})`,
|
|
324
|
+
exitCode: 2,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const record = snapshotToRecord(existing);
|
|
328
|
+
if (!record) {
|
|
329
|
+
return { ok: false, message: `run "${runId}" has no resumable snapshot`, exitCode: 1 };
|
|
330
|
+
}
|
|
331
|
+
const memStore = createInMemoryRunStore();
|
|
332
|
+
await memStore.save(record);
|
|
333
|
+
const out = await resume({ runId, injection }, {
|
|
334
|
+
store: memStore,
|
|
335
|
+
handler: stepHandler,
|
|
336
|
+
onStreamChunk: (chunk) => chunkBus.publish({ runId, chunk }),
|
|
337
|
+
});
|
|
338
|
+
if (!out.ok) {
|
|
339
|
+
const exitCode = out.status === "no_match" || out.status === "not_parked" ? 2 : 1;
|
|
340
|
+
return { ok: false, message: out.message, exitCode };
|
|
341
|
+
}
|
|
342
|
+
if (!store.update) {
|
|
343
|
+
return { ok: false, message: "snapshot run store does not support update", exitCode: 1 };
|
|
344
|
+
}
|
|
345
|
+
const saved = await store.update(recordToSnapshot(out.record, existing));
|
|
346
|
+
await wakeupManager.syncStoredRun(saved);
|
|
347
|
+
return { ok: true, saved };
|
|
348
|
+
};
|
|
349
|
+
try {
|
|
350
|
+
await wakeupManager.bootstrap();
|
|
351
|
+
}
|
|
352
|
+
catch (err) {
|
|
353
|
+
console.warn(`[voyant] failed to bootstrap wakeup leases from run store: ${err instanceof Error ? err.message : String(err)}`);
|
|
354
|
+
}
|
|
355
|
+
wakeupManager.start();
|
|
356
|
+
let scheduler;
|
|
357
|
+
let listSchedules;
|
|
358
|
+
const sources = [];
|
|
359
|
+
for (const workflow of wfMod.__listRegisteredWorkflows()) {
|
|
360
|
+
const decl = workflow.config.schedule;
|
|
361
|
+
if (!decl)
|
|
362
|
+
continue;
|
|
363
|
+
const decls = Array.isArray(decl) ? decl : [decl];
|
|
364
|
+
for (const source of decls) {
|
|
365
|
+
sources.push({ workflowId: workflow.id, decl: source });
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (sources.length > 0) {
|
|
369
|
+
scheduler = createScheduler({
|
|
370
|
+
sources,
|
|
371
|
+
onFire: async ({ workflowId, input }) => {
|
|
372
|
+
await triggerRun({ workflowId, input });
|
|
373
|
+
},
|
|
374
|
+
logger: (level, message) => {
|
|
375
|
+
if (level === "error")
|
|
376
|
+
console.error(`[scheduler] ${message}`);
|
|
377
|
+
else if (level === "warn")
|
|
378
|
+
console.warn(`[scheduler] ${message}`);
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
listSchedules = () => scheduler.nextFirings();
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
store,
|
|
385
|
+
createServer,
|
|
386
|
+
healthCheck,
|
|
387
|
+
readinessCheck,
|
|
388
|
+
collectMetrics,
|
|
389
|
+
shutdown: async () => {
|
|
390
|
+
wakeupManager.stop();
|
|
391
|
+
await pg?.close();
|
|
392
|
+
},
|
|
393
|
+
staticDir,
|
|
394
|
+
triggerRun,
|
|
395
|
+
resumeRun,
|
|
396
|
+
listWorkflows,
|
|
397
|
+
injectWaitpoint,
|
|
398
|
+
scheduler,
|
|
399
|
+
listSchedules,
|
|
400
|
+
cancelRun,
|
|
401
|
+
chunkBus,
|
|
402
|
+
};
|
|
403
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function mergeTags(...groups: ReadonlyArray<ReadonlyArray<string> | undefined>): string[];
|
|
2
|
+
export declare function requireExternalResumeFromStep(resumeFromStep: string | undefined): string;
|
|
3
|
+
export declare function requireExternalSeedResults(seedResults: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
4
|
+
//# sourceMappingURL=node-selfhost-resume-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-selfhost-resume-input.d.ts","sourceRoot":"","sources":["../src/node-selfhost-resume-input.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,GAAG,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,MAAM,EAAE,CAM/F;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAOxF;AAED,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC/C,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function mergeTags(...groups) {
|
|
2
|
+
const tags = new Set();
|
|
3
|
+
for (const group of groups) {
|
|
4
|
+
for (const tag of group ?? [])
|
|
5
|
+
tags.add(tag);
|
|
6
|
+
}
|
|
7
|
+
return Array.from(tags);
|
|
8
|
+
}
|
|
9
|
+
export function requireExternalResumeFromStep(resumeFromStep) {
|
|
10
|
+
if (!resumeFromStep) {
|
|
11
|
+
throw new Error("resumeFromStep is required when the parent run is not stored by this self-host server");
|
|
12
|
+
}
|
|
13
|
+
return resumeFromStep;
|
|
14
|
+
}
|
|
15
|
+
export function requireExternalSeedResults(seedResults) {
|
|
16
|
+
if (!seedResults) {
|
|
17
|
+
throw new Error("seedResults is required when the parent run is not stored by this self-host server");
|
|
18
|
+
}
|
|
19
|
+
return seedResults;
|
|
20
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-standalone-driver.d.ts","sourceRoot":"","sources":["../src/node-standalone-driver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"node-standalone-driver.d.ts","sourceRoot":"","sources":["../src/node-standalone-driver.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EACV,aAAa,EAOd,MAAM,4BAA4B,CAAA;AAInC,OAAO,EAML,KAAK,SAAS,EAId,KAAK,WAAW,EAEjB,MAAM,kCAAkC,CAAA;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAWxD,KAAK,EAAE,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAA;AAIpC,MAAM,WAAW,2BAA2B;IAC1C,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;;;;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;AAiED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,2BAA2B,GAAG,aAAa,CAuX3F"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Mode 2 driver — pure Node, Postgres-backed.
|
|
2
|
+
// agent-quality: file-size exception -- Public driver factory currently owns manifest, trigger, event-ingest, schedule, and admin wiring; split only with a dedicated driver-surface refactor.
|
|
2
3
|
//
|
|
3
4
|
// Returns a `DriverFactory` (per architecture doc §6.3) that the framework
|
|
4
5
|
// invokes after `createApp()` has assembled its `ModuleContainer`. Composes:
|
|
@@ -30,6 +31,42 @@ const DEFAULT_TENANT_META = {
|
|
|
30
31
|
organizationId: "default",
|
|
31
32
|
};
|
|
32
33
|
const DEFAULT_MANIFEST_KEEP = 3;
|
|
34
|
+
function serializeWorkflowManifest(manifest) {
|
|
35
|
+
return { ...manifest };
|
|
36
|
+
}
|
|
37
|
+
function deserializeWorkflowManifest(manifest) {
|
|
38
|
+
const { schemaVersion, projectId, versionId, builtAt, builderVersion, capabilities, workflows, eventFilters, bindings, environments, } = manifest;
|
|
39
|
+
if (schemaVersion !== 1 ||
|
|
40
|
+
typeof projectId !== "string" ||
|
|
41
|
+
typeof versionId !== "string" ||
|
|
42
|
+
typeof builtAt !== "number" ||
|
|
43
|
+
typeof builderVersion !== "string" ||
|
|
44
|
+
!isStringArray(capabilities) ||
|
|
45
|
+
!Array.isArray(workflows) ||
|
|
46
|
+
!Array.isArray(eventFilters) ||
|
|
47
|
+
!isRecord(bindings) ||
|
|
48
|
+
!isRecord(environments)) {
|
|
49
|
+
throw new Error("stored workflow manifest has an invalid shape");
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
schemaVersion,
|
|
53
|
+
projectId,
|
|
54
|
+
versionId,
|
|
55
|
+
builtAt,
|
|
56
|
+
builderVersion,
|
|
57
|
+
capabilities,
|
|
58
|
+
workflows: workflows,
|
|
59
|
+
eventFilters: eventFilters,
|
|
60
|
+
bindings: bindings,
|
|
61
|
+
environments: environments,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function isRecord(value) {
|
|
65
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
66
|
+
}
|
|
67
|
+
function isStringArray(value) {
|
|
68
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
69
|
+
}
|
|
33
70
|
/**
|
|
34
71
|
* Build the Mode 2 driver factory. The factory closes over its options
|
|
35
72
|
* and returns a fresh `WorkflowDriver` when `createApp()` (or a test)
|
|
@@ -114,7 +151,7 @@ export function createNodeStandaloneDriver(opts) {
|
|
|
114
151
|
const result = await manifestStore.registerManifest({
|
|
115
152
|
environment: args.environment,
|
|
116
153
|
versionId: args.manifest.versionId,
|
|
117
|
-
manifest: args.manifest,
|
|
154
|
+
manifest: serializeWorkflowManifest(args.manifest),
|
|
118
155
|
});
|
|
119
156
|
// Best-effort prune; failures here shouldn't fail boot.
|
|
120
157
|
try {
|
|
@@ -133,7 +170,7 @@ export function createNodeStandaloneDriver(opts) {
|
|
|
133
170
|
const envelope = await manifestStore.getCurrent(args.environment);
|
|
134
171
|
if (!envelope)
|
|
135
172
|
return null;
|
|
136
|
-
return envelope.manifest;
|
|
173
|
+
return deserializeWorkflowManifest(envelope.manifest);
|
|
137
174
|
}
|
|
138
175
|
async function trigger(workflow, input, triggerOpts) {
|
|
139
176
|
assertNotShutdown(shuttingDown);
|
|
@@ -167,7 +204,7 @@ export function createNodeStandaloneDriver(opts) {
|
|
|
167
204
|
};
|
|
168
205
|
}
|
|
169
206
|
const eventId = await ensureEventId(args.envelope);
|
|
170
|
-
const manifest = stored.manifest;
|
|
207
|
+
const manifest = deserializeWorkflowManifest(stored.manifest);
|
|
171
208
|
const routed = routeEvent({
|
|
172
209
|
manifest,
|
|
173
210
|
envelope: args.envelope,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-step-runner.d.ts","sourceRoot":"","sources":["../src/node-step-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAE7D,eAAO,MAAM,cAAc,EAAE,UAyB5B,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const nodeStepRunner = async ({ attempt, fn, stepCtx }) => {
|
|
2
|
+
const startedAt = Date.now();
|
|
3
|
+
try {
|
|
4
|
+
const output = await fn(stepCtx);
|
|
5
|
+
return { attempt, status: "ok", output, startedAt, finishedAt: Date.now() };
|
|
6
|
+
}
|
|
7
|
+
catch (err) {
|
|
8
|
+
const error = err;
|
|
9
|
+
const code = typeof err.code === "string"
|
|
10
|
+
? err.code
|
|
11
|
+
: "UNKNOWN";
|
|
12
|
+
return {
|
|
13
|
+
attempt,
|
|
14
|
+
status: "err",
|
|
15
|
+
error: {
|
|
16
|
+
category: "USER_ERROR",
|
|
17
|
+
code,
|
|
18
|
+
message: error?.message ?? String(err),
|
|
19
|
+
name: error?.name,
|
|
20
|
+
stack: error?.stack,
|
|
21
|
+
},
|
|
22
|
+
startedAt,
|
|
23
|
+
finishedAt: Date.now(),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-manifest-store.d.ts","sourceRoot":"","sources":["../src/postgres-manifest-store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAIxD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAE5E,iEAAiE;IACjE,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAEjE,uEAAuE;IACvE,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACjF;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,UAAU,CAAA;CACf;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,4BAA4B,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"postgres-manifest-store.d.ts","sourceRoot":"","sources":["../src/postgres-manifest-store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAIxD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAA;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAE5E,iEAAiE;IACjE,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IAEjE,uEAAuE;IACvE,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACjF;AAED,MAAM,WAAW,4BAA4B;IAC3C,EAAE,EAAE,UAAU,CAAA;CACf;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,4BAA4B,GAAG,aAAa,CAgG7F"}
|
|
@@ -73,9 +73,13 @@ export function createPostgresManifestStore(opts) {
|
|
|
73
73
|
const keepIds = newest.map((r) => r.versionId);
|
|
74
74
|
if (keepIds.length === 0)
|
|
75
75
|
return { deleted: 0 };
|
|
76
|
-
const result = await db.execute(
|
|
76
|
+
const result = await db.execute(
|
|
77
|
+
// agent-quality: raw-sql reviewed -- owner: workflows-orchestrator-node; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
|
|
78
|
+
sql `DELETE FROM ${workflowManifestsTable}
|
|
77
79
|
WHERE environment = ${environment}
|
|
78
|
-
AND version_id NOT IN (${sql.join(
|
|
80
|
+
AND version_id NOT IN (${sql.join(
|
|
81
|
+
// agent-quality: raw-sql reviewed -- owner: workflows-orchestrator-node; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
|
|
82
|
+
keepIds.map((id) => sql `${id}`), sql `, `)})`);
|
|
79
83
|
return { deleted: result.rowCount ?? 0 };
|
|
80
84
|
},
|
|
81
85
|
};
|
|
@@ -134,7 +134,7 @@ function recordToValues(record) {
|
|
|
134
134
|
completedAt: record.completedAt,
|
|
135
135
|
}),
|
|
136
136
|
input: normalizeJson(record.input),
|
|
137
|
-
runRecord: normalizeRequiredJson(record),
|
|
137
|
+
runRecord: normalizeRequiredJson({ ...record }),
|
|
138
138
|
entryFile: null,
|
|
139
139
|
replayOf: null,
|
|
140
140
|
idempotencyKey: record.idempotencyKey ?? null,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres-schema.d.ts","sourceRoot":"","sources":["../src/postgres-schema.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"postgres-schema.d.ts","sourceRoot":"","sources":["../src/postgres-schema.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2C7B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcxB,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBlC,CAAA"}
|
package/dist/postgres-schema.js
CHANGED
|
@@ -31,6 +31,7 @@ export const snapshotRunsTable = pgTable("voyant_snapshot_runs", {
|
|
|
31
31
|
*/
|
|
32
32
|
idempotencyIdx: uniqueIndex("voyant_snapshot_runs_idempotency_idx")
|
|
33
33
|
.on(table.workflowId, table.idempotencyKey)
|
|
34
|
+
// agent-quality: raw-sql reviewed -- owner: workflows-orchestrator-node; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
|
|
34
35
|
.where(sql `${table.idempotencyKey} IS NOT NULL`),
|
|
35
36
|
}));
|
|
36
37
|
export const wakeupsTable = pgTable("voyant_wakeups", {
|
|
@@ -64,5 +65,6 @@ export const workflowManifestsTable = pgTable("voyant_workflow_manifests", {
|
|
|
64
65
|
pk: primaryKey({ columns: [table.environment, table.versionId] }),
|
|
65
66
|
currentIdx: uniqueIndex("voyant_workflow_manifests_current_idx")
|
|
66
67
|
.on(table.environment)
|
|
68
|
+
// agent-quality: raw-sql reviewed -- owner: workflows-orchestrator-node; dynamic SQL interpolation uses Drizzle parameter binding or vetted SQL identifiers.
|
|
67
69
|
.where(sql `${table.isCurrent}`),
|
|
68
70
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sleep-alarm-manager.d.ts","sourceRoot":"","sources":["../src/sleep-alarm-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,SAAS,EACd,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,kCAAkC,CAAA;AAEzC,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAqB,CAAC,OAAO,SAAS,mBAAmB;IACxE,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAClC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAA;IACvD,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,CAAA;IACxC,UAAU,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAA;IAC1D,OAAO,EAAE,WAAW,CAAA;IACpB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAA;IACtE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,UAAU,CAAA;IAC9B,YAAY,CAAC,EAAE,OAAO,YAAY,CAAA;IAClC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1E,cAAc,CAAC,EAAE,OAAO,sBAAsB,CAAA;IAC9C,mBAAmB,CAAC,EAAE,OAAO,eAAe,CAAA;CAC7C;AAED,MAAM,WAAW,iBAAiB,CAAC,OAAO,SAAS,mBAAmB;IACpE,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACnC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;
|
|
1
|
+
{"version":3,"file":"sleep-alarm-manager.d.ts","sourceRoot":"","sources":["../src/sleep-alarm-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,KAAK,SAAS,EACd,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,kCAAkC,CAAA;AAEzC,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAqB,CAAC,OAAO,SAAS,mBAAmB;IACxE,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;IAClC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAA;IACvD,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9C,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,CAAA;IACxC,UAAU,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAA;IAC1D,OAAO,EAAE,WAAW,CAAA;IACpB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,WAAW,CAAA;KAAE,KAAK,IAAI,CAAA;IACtE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,OAAO,UAAU,CAAA;IAC9B,YAAY,CAAC,EAAE,OAAO,YAAY,CAAA;IAClC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1E,cAAc,CAAC,EAAE,OAAO,sBAAsB,CAAA;IAC9C,mBAAmB,CAAC,EAAE,OAAO,eAAe,CAAA;CAC7C;AAED,MAAM,WAAW,iBAAiB,CAAC,OAAO,SAAS,mBAAmB;IACpE,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;IACnC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAaD,wBAAgB,uBAAuB,CAAC,OAAO,SAAS,mBAAmB,EACzE,IAAI,EAAE,qBAAqB,CAAC,OAAO,CAAC,GACnC,iBAAiB,CAAC,OAAO,CAAC,CAmF5B;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CASxE"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { createInMemoryRunStore, resumeDueAlarms, } from "@voyantjs/workflows-orchestrator";
|
|
2
|
+
function unrefTimer(timer) {
|
|
3
|
+
if (typeof timer === "object" &&
|
|
4
|
+
timer !== null &&
|
|
5
|
+
"unref" in timer &&
|
|
6
|
+
typeof timer.unref === "function") {
|
|
7
|
+
timer.unref();
|
|
8
|
+
}
|
|
9
|
+
}
|
|
2
10
|
export function createSleepAlarmManager(deps) {
|
|
3
11
|
const now = deps.now ?? (() => Date.now());
|
|
4
12
|
const setTimeoutImpl = deps.setTimeout ?? setTimeout;
|
|
@@ -59,7 +67,7 @@ export function createSleepAlarmManager(deps) {
|
|
|
59
67
|
});
|
|
60
68
|
});
|
|
61
69
|
}, delay);
|
|
62
|
-
timer
|
|
70
|
+
unrefTimer(timer);
|
|
63
71
|
timers.set(stored.id, timer);
|
|
64
72
|
};
|
|
65
73
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-stream.d.ts","sourceRoot":"","sources":["../src/store-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAE1E,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,SAAS,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtC,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AAEvD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,MAAM,IAAI,CAAA;IAClD,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,eAAe,EAAE,MAAM,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,WAAW,CAAA;IAChC,aAAa,CAAC,EAAE,OAAO,aAAa,CAAA;CACrC;
|
|
1
|
+
{"version":3,"file":"store-stream.d.ts","sourceRoot":"","sources":["../src/store-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAE1E,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,SAAS,SAAS,EAAE,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,SAAS,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,SAAS,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtC,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;AAEvD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,MAAM,IAAI,CAAA;IAClD,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,IAAI,EAAE,MAAM,IAAI,CAAA;IAChB,eAAe,EAAE,MAAM,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,WAAW,CAAA;IAChC,aAAa,CAAC,EAAE,OAAO,aAAa,CAAA;CACrC;AAaD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,SAAS,SAAS,EAAE,EAC1B,IAAI,EAAE,SAAS,SAAS,EAAE,GACzB,UAAU,EAAE,CAuBd;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,gBAAgB,EACvB,IAAI,GAAE,kBAAuB,GAC5B,WAAW,CA8Db"}
|