openworkflow 0.4.1 → 0.6.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/README.md +43 -345
- package/dist/backend-test/backend.testsuite.d.ts +20 -0
- package/dist/backend-test/backend.testsuite.d.ts.map +1 -0
- package/dist/{core → backend-test}/backend.testsuite.js +191 -59
- package/dist/backend-test/index.d.ts +2 -0
- package/dist/backend-test/index.d.ts.map +1 -0
- package/dist/backend-test/index.js +1 -0
- package/dist/{core/backend.d.ts → backend.d.ts} +7 -5
- package/dist/backend.d.ts.map +1 -0
- package/dist/{core/backend.js → backend.js} +0 -1
- package/dist/backend.testsuite.d.ts +20 -0
- package/dist/backend.testsuite.d.ts.map +1 -0
- package/dist/{core/backend-test-suite.js → backend.testsuite.js} +301 -171
- package/dist/bin/openworkflow.d.ts +3 -0
- package/dist/bin/openworkflow.d.ts.map +1 -0
- package/dist/bin/openworkflow.js +43 -0
- package/dist/chaos.test.d.ts +2 -0
- package/dist/chaos.test.d.ts.map +1 -0
- package/dist/chaos.test.js +88 -0
- package/dist/client.d.ts +141 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/{sdk/sdk.js → client.js} +43 -71
- package/dist/client.test.d.ts +2 -0
- package/dist/client.test.d.ts.map +1 -0
- package/dist/{sdk/sdk.test.js → client.test.js} +130 -14
- package/dist/core/duration.d.ts +4 -2
- package/dist/core/duration.d.ts.map +1 -1
- package/dist/core/duration.js +3 -2
- package/dist/core/duration.test.js +0 -1
- package/dist/core/error.d.ts +14 -0
- package/dist/core/error.d.ts.map +1 -0
- package/dist/core/error.js +17 -0
- package/dist/core/error.test.d.ts +2 -0
- package/dist/core/error.test.d.ts.map +1 -0
- package/dist/core/error.test.js +60 -0
- package/dist/core/json.js +0 -1
- package/dist/core/result.d.ts +14 -4
- package/dist/core/result.d.ts.map +1 -1
- package/dist/core/result.js +10 -1
- package/dist/core/result.test.js +2 -2
- package/dist/core/retry.d.ts +0 -9
- package/dist/core/retry.d.ts.map +1 -1
- package/dist/core/retry.js +0 -15
- package/dist/core/schema.js +0 -1
- package/dist/core/step.d.ts +1 -32
- package/dist/core/step.d.ts.map +1 -1
- package/dist/core/step.js +0 -36
- package/dist/core/step.test.js +1 -75
- package/dist/core/workflow.d.ts +2 -47
- package/dist/core/workflow.d.ts.map +1 -1
- package/dist/core/workflow.js +0 -45
- package/dist/core/workflow.test.js +1 -104
- package/dist/driver.d.ts +116 -0
- package/dist/driver.d.ts.map +1 -0
- package/dist/driver.js +1 -0
- package/dist/{execution/execution.d.ts → execution.d.ts} +4 -26
- package/dist/execution.d.ts.map +1 -0
- package/dist/{execution/execution.js → execution.js} +4 -5
- package/dist/execution.test.d.ts.map +1 -0
- package/dist/{execution/execution.test.js → execution.test.js} +4 -5
- package/dist/factory.d.ts +74 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +72 -0
- package/dist/index.d.ts +6 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -5
- package/dist/internal.d.ts +7 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +2 -0
- package/dist/node-sqlite/backend.d.ts +52 -0
- package/dist/node-sqlite/backend.d.ts.map +1 -0
- package/dist/node-sqlite/backend.js +673 -0
- package/dist/node-sqlite/index.d.ts +11 -0
- package/dist/node-sqlite/index.d.ts.map +1 -0
- package/dist/node-sqlite/index.js +7 -0
- package/dist/node-sqlite/sqlite.d.ts +60 -0
- package/dist/node-sqlite/sqlite.d.ts.map +1 -0
- package/dist/{backend-sqlite → node-sqlite}/sqlite.js +20 -3
- package/dist/postgres/backend.d.ts +44 -0
- package/dist/postgres/backend.d.ts.map +1 -0
- package/dist/postgres/backend.js +534 -0
- package/dist/postgres/backend.test.d.ts +2 -0
- package/dist/postgres/backend.test.d.ts.map +1 -0
- package/dist/postgres/backend.test.js +19 -0
- package/dist/postgres/driver.d.ts +81 -0
- package/dist/postgres/driver.d.ts.map +1 -0
- package/dist/postgres/driver.js +63 -0
- package/dist/postgres/index.d.ts +11 -0
- package/dist/postgres/index.d.ts.map +1 -0
- package/dist/postgres/index.js +7 -0
- package/dist/postgres/internal.d.ts +2 -0
- package/dist/postgres/internal.d.ts.map +1 -0
- package/dist/postgres/internal.js +1 -0
- package/dist/postgres/postgres.d.ts +42 -0
- package/dist/postgres/postgres.d.ts.map +1 -0
- package/dist/postgres/postgres.js +233 -0
- package/dist/postgres/postgres.test.d.ts +2 -0
- package/dist/postgres/postgres.test.d.ts.map +1 -0
- package/dist/postgres/postgres.test.js +45 -0
- package/dist/postgres/scripts/db-migrate.d.ts +2 -0
- package/dist/postgres/scripts/db-migrate.d.ts.map +1 -0
- package/dist/postgres/scripts/db-migrate.js +4 -0
- package/dist/postgres/scripts/db-reset.d.ts +2 -0
- package/dist/postgres/scripts/db-reset.d.ts.map +1 -0
- package/dist/postgres/scripts/db-reset.js +5 -0
- package/dist/postgres/scripts/squawk.d.ts +2 -0
- package/dist/postgres/scripts/squawk.d.ts.map +1 -0
- package/dist/postgres/scripts/squawk.js +16 -0
- package/dist/postgres/vitest.global-setup.d.ts +3 -0
- package/dist/postgres/vitest.global-setup.d.ts.map +1 -0
- package/dist/postgres/vitest.global-setup.js +7 -0
- package/dist/postgres.d.ts +2 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/postgres.js +1 -0
- package/dist/registry.d.ts +27 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +48 -0
- package/dist/registry.test.d.ts +2 -0
- package/dist/registry.test.d.ts.map +1 -0
- package/dist/registry.test.js +109 -0
- package/dist/{backend-sqlite → sqlite}/backend.d.ts +8 -4
- package/dist/sqlite/backend.d.ts.map +1 -0
- package/dist/{backend-sqlite → sqlite}/backend.js +35 -9
- package/dist/sqlite/backend.test.d.ts +2 -0
- package/dist/sqlite/backend.test.d.ts.map +1 -0
- package/dist/sqlite/backend.test.js +50 -0
- package/dist/sqlite/driver.d.ts +79 -0
- package/dist/sqlite/driver.d.ts.map +1 -0
- package/dist/sqlite/driver.js +62 -0
- package/dist/sqlite/index.d.ts +13 -0
- package/dist/sqlite/index.d.ts.map +1 -0
- package/dist/sqlite/index.js +11 -0
- package/dist/sqlite/internal.d.ts +2 -0
- package/dist/sqlite/internal.d.ts.map +1 -0
- package/dist/sqlite/internal.js +1 -0
- package/dist/{backend-sqlite → sqlite}/sqlite.d.ts +18 -2
- package/dist/sqlite/sqlite.d.ts.map +1 -0
- package/dist/sqlite/sqlite.js +246 -0
- package/dist/sqlite/sqlite.test.d.ts +2 -0
- package/dist/sqlite/sqlite.test.d.ts.map +1 -0
- package/dist/sqlite/sqlite.test.js +171 -0
- package/dist/sqlite.d.ts +2 -0
- package/dist/sqlite.d.ts.map +1 -0
- package/dist/sqlite.js +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/{worker/worker.d.ts → worker.d.ts} +11 -4
- package/dist/worker.d.ts.map +1 -0
- package/dist/{worker/worker.js → worker.js} +20 -11
- package/dist/{worker/worker.test.d.ts.map → worker.test.d.ts.map} +1 -1
- package/dist/{worker/worker.test.js → worker.test.js} +136 -22
- package/dist/workflow.d.ts +60 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +48 -0
- package/dist/workflow.test.d.ts +2 -0
- package/dist/workflow.test.d.ts.map +1 -0
- package/dist/workflow.test.js +84 -0
- package/package.json +28 -4
- package/dist/backend-sqlite/backend.d.ts.map +0 -1
- package/dist/backend-sqlite/backend.js.map +0 -1
- package/dist/backend-sqlite/index.d.ts +0 -2
- package/dist/backend-sqlite/index.d.ts.map +0 -1
- package/dist/backend-sqlite/index.js +0 -2
- package/dist/backend-sqlite/index.js.map +0 -1
- package/dist/backend-sqlite/sqlite.d.ts.map +0 -1
- package/dist/backend-sqlite/sqlite.js.map +0 -1
- package/dist/config/config.d.ts +0 -102
- package/dist/config/config.d.ts.map +0 -1
- package/dist/config/config.js +0 -29
- package/dist/config/config.js.map +0 -1
- package/dist/config/index.d.ts +0 -3
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/index.js +0 -2
- package/dist/config/index.js.map +0 -1
- package/dist/config.d.ts +0 -28
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -41
- package/dist/config.js.map +0 -1
- package/dist/core/backend-test-suite.d.ts +0 -22
- package/dist/core/backend-test-suite.d.ts.map +0 -1
- package/dist/core/backend-test-suite.js.map +0 -1
- package/dist/core/backend.d.ts.map +0 -1
- package/dist/core/backend.js.map +0 -1
- package/dist/core/backend.testsuite.d.ts +0 -21
- package/dist/core/backend.testsuite.d.ts.map +0 -1
- package/dist/core/backend.testsuite.js.map +0 -1
- package/dist/core/duration.js.map +0 -1
- package/dist/core/duration.test.js.map +0 -1
- package/dist/core/json.js.map +0 -1
- package/dist/core/result.js.map +0 -1
- package/dist/core/result.test.js.map +0 -1
- package/dist/core/retry.js.map +0 -1
- package/dist/core/retry.test.d.ts +0 -2
- package/dist/core/retry.test.d.ts.map +0 -1
- package/dist/core/retry.test.js +0 -36
- package/dist/core/retry.test.js.map +0 -1
- package/dist/core/schema.js.map +0 -1
- package/dist/core/step.js.map +0 -1
- package/dist/core/step.test.js.map +0 -1
- package/dist/core/workflow.js.map +0 -1
- package/dist/core/workflow.test.js.map +0 -1
- package/dist/execution/execution.d.ts.map +0 -1
- package/dist/execution/execution.js.map +0 -1
- package/dist/execution/execution.test.d.ts.map +0 -1
- package/dist/execution/execution.test.js.map +0 -1
- package/dist/global.d.ts +0 -62
- package/dist/global.d.ts.map +0 -1
- package/dist/global.js +0 -78
- package/dist/global.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/sdk/sdk.d.ts +0 -182
- package/dist/sdk/sdk.d.ts.map +0 -1
- package/dist/sdk/sdk.js.map +0 -1
- package/dist/sdk/sdk.test.d.ts +0 -2
- package/dist/sdk/sdk.test.d.ts.map +0 -1
- package/dist/sdk/sdk.test.js.map +0 -1
- package/dist/worker/worker.d.ts.map +0 -1
- package/dist/worker/worker.js.map +0 -1
- package/dist/worker/worker.test.js.map +0 -1
- /package/dist/{execution/execution.test.d.ts → execution.test.d.ts} +0 -0
- /package/dist/{worker/worker.test.d.ts → worker.test.d.ts} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { executeWorkflow } from "
|
|
2
|
-
import {
|
|
1
|
+
import { executeWorkflow } from "./execution.js";
|
|
2
|
+
import { WorkflowRegistry } from "./registry.js";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
const DEFAULT_LEASE_DURATION_MS = 30 * 1000; // 30s
|
|
5
5
|
const DEFAULT_POLL_INTERVAL_MS = 100; // 100ms
|
|
@@ -11,22 +11,22 @@ const DEFAULT_CONCURRENCY = 1;
|
|
|
11
11
|
export class Worker {
|
|
12
12
|
backend;
|
|
13
13
|
workerIds;
|
|
14
|
-
|
|
14
|
+
registry = new WorkflowRegistry();
|
|
15
15
|
activeExecutions = new Set();
|
|
16
16
|
running = false;
|
|
17
17
|
loopPromise = null;
|
|
18
18
|
constructor(options) {
|
|
19
19
|
this.backend = options.backend;
|
|
20
|
+
for (const workflow of options.workflows) {
|
|
21
|
+
this.registry.register(workflow);
|
|
22
|
+
}
|
|
20
23
|
const concurrency = Math.max(DEFAULT_CONCURRENCY, options.concurrency ?? DEFAULT_CONCURRENCY);
|
|
21
24
|
// generate worker IDs for every concurrency slot
|
|
22
25
|
this.workerIds = Array.from({ length: concurrency }, () => randomUUID());
|
|
23
|
-
// register workflows
|
|
24
|
-
for (const [name, workflow] of options.workflows) {
|
|
25
|
-
this.registeredWorkflows.set(name, workflow);
|
|
26
|
-
}
|
|
27
26
|
}
|
|
28
27
|
/**
|
|
29
28
|
* Start the worker. It will begin polling for and executing workflows.
|
|
29
|
+
* @returns Promise resolved when started
|
|
30
30
|
*/
|
|
31
31
|
async start() {
|
|
32
32
|
if (this.running)
|
|
@@ -38,6 +38,7 @@ export class Worker {
|
|
|
38
38
|
/**
|
|
39
39
|
* Stop the worker gracefully. Waits for all active workflow runs to complete
|
|
40
40
|
* before returning.
|
|
41
|
+
* @returns Promise resolved when stopped
|
|
41
42
|
*/
|
|
42
43
|
async stop() {
|
|
43
44
|
this.running = false;
|
|
@@ -51,6 +52,7 @@ export class Worker {
|
|
|
51
52
|
/**
|
|
52
53
|
* Processes one round of work claims and execution. Exposed for testing.
|
|
53
54
|
* Returns the number of workflow runs claimed.
|
|
55
|
+
* @returns Number of workflow runs claimed
|
|
54
56
|
*/
|
|
55
57
|
async tick() {
|
|
56
58
|
const availableSlots = this.concurrency - this.activeExecutions.size;
|
|
@@ -68,6 +70,7 @@ export class Worker {
|
|
|
68
70
|
}
|
|
69
71
|
/**
|
|
70
72
|
* Get the configured concurrency limit.
|
|
73
|
+
* @returns Concurrency limit
|
|
71
74
|
*/
|
|
72
75
|
get concurrency() {
|
|
73
76
|
return this.workerIds.length;
|
|
@@ -92,7 +95,7 @@ export class Worker {
|
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
/*
|
|
95
|
-
*
|
|
98
|
+
* Claim and process a workflow run for the given worker ID. Do not await the
|
|
96
99
|
* processing here to avoid blocking the caller.
|
|
97
100
|
* Returns the claimed workflow run, or null if none was available.
|
|
98
101
|
*/
|
|
@@ -104,8 +107,7 @@ export class Worker {
|
|
|
104
107
|
});
|
|
105
108
|
if (!workflowRun)
|
|
106
109
|
return null;
|
|
107
|
-
const
|
|
108
|
-
const workflow = this.registeredWorkflows.get(key);
|
|
110
|
+
const workflow = this.registry.get(workflowRun.workflowName, workflowRun.version);
|
|
109
111
|
if (!workflow) {
|
|
110
112
|
const versionStr = workflowRun.version
|
|
111
113
|
? ` (version: ${workflowRun.version})`
|
|
@@ -139,6 +141,9 @@ export class Worker {
|
|
|
139
141
|
/**
|
|
140
142
|
* Process a workflow execution, handling heartbeats, step execution, and
|
|
141
143
|
* marking success or failure.
|
|
144
|
+
* @param execution - Workflow execution
|
|
145
|
+
* @param workflow - Workflow to execute
|
|
146
|
+
* @returns Promise resolved when processing completes
|
|
142
147
|
*/
|
|
143
148
|
async processExecutionInBackground(execution, workflow) {
|
|
144
149
|
// start heartbeating
|
|
@@ -202,7 +207,11 @@ class WorkflowExecution {
|
|
|
202
207
|
}
|
|
203
208
|
}
|
|
204
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Sleep for a given duration.
|
|
212
|
+
* @param ms - Milliseconds to sleep
|
|
213
|
+
* @returns Promise resolved after sleeping
|
|
214
|
+
*/
|
|
205
215
|
function sleep(ms) {
|
|
206
216
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
207
217
|
}
|
|
208
|
-
//# sourceMappingURL=worker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.test.d.ts","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"worker.test.d.ts","sourceRoot":"","sources":["../worker.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { OpenWorkflow } from "./client.js";
|
|
2
|
+
import { BackendPostgres } from "./postgres.js";
|
|
3
|
+
import { DEFAULT_POSTGRES_URL } from "./postgres/postgres.js";
|
|
4
|
+
import { defineWorkflowSpec } from "./workflow.js";
|
|
4
5
|
import { randomUUID } from "node:crypto";
|
|
5
6
|
import { describe, expect, test } from "vitest";
|
|
6
7
|
describe("Worker", () => {
|
|
7
|
-
test("passes workflow input to handlers
|
|
8
|
+
test("passes workflow input to handlers", async () => {
|
|
8
9
|
const backend = await createBackend();
|
|
9
10
|
const client = new OpenWorkflow({ backend });
|
|
10
11
|
const workflow = client.defineWorkflow({ name: "context" }, ({ input }) => input);
|
|
@@ -15,7 +16,7 @@ describe("Worker", () => {
|
|
|
15
16
|
const result = await handle.result();
|
|
16
17
|
expect(result).toEqual(payload);
|
|
17
18
|
});
|
|
18
|
-
test("processes workflow runs to completion
|
|
19
|
+
test("processes workflow runs to completion", async () => {
|
|
19
20
|
const backend = await createBackend();
|
|
20
21
|
const client = new OpenWorkflow({ backend });
|
|
21
22
|
const workflow = client.defineWorkflow({ name: "process" }, ({ input }) => input.value * 2);
|
|
@@ -25,7 +26,7 @@ describe("Worker", () => {
|
|
|
25
26
|
const result = await handle.result();
|
|
26
27
|
expect(result).toBe(42);
|
|
27
28
|
});
|
|
28
|
-
test("step.run reuses cached results
|
|
29
|
+
test("step.run reuses cached results", async () => {
|
|
29
30
|
const backend = await createBackend();
|
|
30
31
|
const client = new OpenWorkflow({ backend });
|
|
31
32
|
let executionCount = 0;
|
|
@@ -69,7 +70,7 @@ describe("Worker", () => {
|
|
|
69
70
|
expect(updated?.error).toBeDefined();
|
|
70
71
|
expect(updated?.availableAt).not.toBeNull();
|
|
71
72
|
});
|
|
72
|
-
test("retries failed workflows automatically
|
|
73
|
+
test("retries failed workflows automatically", async () => {
|
|
73
74
|
const backend = await createBackend();
|
|
74
75
|
const client = new OpenWorkflow({ backend });
|
|
75
76
|
let attemptCount = 0;
|
|
@@ -102,7 +103,7 @@ describe("Worker", () => {
|
|
|
102
103
|
const worker = client.newWorker();
|
|
103
104
|
await worker.tick(); // no runs queued
|
|
104
105
|
});
|
|
105
|
-
test("handles step functions that return undefined
|
|
106
|
+
test("handles step functions that return undefined", async () => {
|
|
106
107
|
const backend = await createBackend();
|
|
107
108
|
const client = new OpenWorkflow({ backend });
|
|
108
109
|
const workflow = client.defineWorkflow({ name: "undefined-steps" }, async ({ step }) => {
|
|
@@ -120,7 +121,7 @@ describe("Worker", () => {
|
|
|
120
121
|
const result = await handle.result();
|
|
121
122
|
expect(result).toEqual({ success: true });
|
|
122
123
|
});
|
|
123
|
-
test("executes steps synchronously within workflow
|
|
124
|
+
test("executes steps synchronously within workflow", async () => {
|
|
124
125
|
const backend = await createBackend();
|
|
125
126
|
const client = new OpenWorkflow({ backend });
|
|
126
127
|
const executionOrder = [];
|
|
@@ -144,7 +145,7 @@ describe("Worker", () => {
|
|
|
144
145
|
const result = await handle.result();
|
|
145
146
|
expect(result).toEqual(["start", "step1", "between", "step2", "end"]);
|
|
146
147
|
});
|
|
147
|
-
test("executes parallel steps with Promise.all
|
|
148
|
+
test("executes parallel steps with Promise.all", async () => {
|
|
148
149
|
const backend = await createBackend();
|
|
149
150
|
const client = new OpenWorkflow({ backend });
|
|
150
151
|
const executionTimes = {};
|
|
@@ -205,7 +206,7 @@ describe("Worker", () => {
|
|
|
205
206
|
}
|
|
206
207
|
expect(completed).toBe(2);
|
|
207
208
|
});
|
|
208
|
-
test("worker starts, processes work, and stops gracefully
|
|
209
|
+
test("worker starts, processes work, and stops gracefully", async () => {
|
|
209
210
|
const backend = await createBackend();
|
|
210
211
|
const client = new OpenWorkflow({ backend });
|
|
211
212
|
const workflow = client.defineWorkflow({ name: "lifecycle" }, () => {
|
|
@@ -219,7 +220,7 @@ describe("Worker", () => {
|
|
|
219
220
|
const result = await handle.result();
|
|
220
221
|
expect(result).toBe("complete");
|
|
221
222
|
});
|
|
222
|
-
test("recovers from crashes during parallel step execution
|
|
223
|
+
test("recovers from crashes during parallel step execution", async () => {
|
|
223
224
|
const backend = await createBackend();
|
|
224
225
|
const client = new OpenWorkflow({ backend });
|
|
225
226
|
let attemptCount = 0;
|
|
@@ -254,7 +255,7 @@ describe("Worker", () => {
|
|
|
254
255
|
expect(result).toEqual({ a: "a", b: "b", attempts: 2 });
|
|
255
256
|
expect(attemptCount).toBe(2);
|
|
256
257
|
});
|
|
257
|
-
test("reclaims workflow run when heartbeat stops
|
|
258
|
+
test("reclaims workflow run when heartbeat stops", async () => {
|
|
258
259
|
const backend = await createBackend();
|
|
259
260
|
const client = new OpenWorkflow({ backend });
|
|
260
261
|
const workflow = client.defineWorkflow({ name: "heartbeat-test" }, () => "done");
|
|
@@ -310,7 +311,7 @@ describe("Worker", () => {
|
|
|
310
311
|
expect(claimedAgain).toBe(0);
|
|
311
312
|
await worker.stop();
|
|
312
313
|
});
|
|
313
|
-
test("worker only sleeps between claims when no work is available
|
|
314
|
+
test("worker only sleeps between claims when no work is available", async () => {
|
|
314
315
|
const backend = await createBackend();
|
|
315
316
|
const client = new OpenWorkflow({ backend });
|
|
316
317
|
const workflow = client.defineWorkflow({ name: "adaptive-test" }, async ({ step }) => {
|
|
@@ -333,7 +334,7 @@ describe("Worker", () => {
|
|
|
333
334
|
// without it (with 100ms sleep between ticks), it would take much longer
|
|
334
335
|
expect(duration).toBeLessThan(3000); // should complete in under 3 seconds
|
|
335
336
|
});
|
|
336
|
-
test("only failed steps re-execute on retry
|
|
337
|
+
test("only failed steps re-execute on retry", async () => {
|
|
337
338
|
const backend = await createBackend();
|
|
338
339
|
const client = new OpenWorkflow({ backend });
|
|
339
340
|
const executionCounts = {
|
|
@@ -388,7 +389,7 @@ describe("Worker", () => {
|
|
|
388
389
|
c: "c-result",
|
|
389
390
|
});
|
|
390
391
|
});
|
|
391
|
-
test("step.sleep postpones workflow execution
|
|
392
|
+
test("step.sleep postpones workflow execution", async () => {
|
|
392
393
|
const backend = await createBackend();
|
|
393
394
|
const client = new OpenWorkflow({ backend });
|
|
394
395
|
let stepCount = 0;
|
|
@@ -494,10 +495,9 @@ describe("Worker", () => {
|
|
|
494
495
|
});
|
|
495
496
|
expect(failed?.status).toBe("pending"); // should be retrying
|
|
496
497
|
expect(failed?.error).toBeDefined();
|
|
497
|
-
// @ts-expect-error - test suite
|
|
498
498
|
expect(failed?.error?.message).toContain("Invalid duration format");
|
|
499
499
|
});
|
|
500
|
-
test("step.sleep handles multiple sequential sleeps
|
|
500
|
+
test("step.sleep handles multiple sequential sleeps", async () => {
|
|
501
501
|
const backend = await createBackend();
|
|
502
502
|
const client = new OpenWorkflow({ backend });
|
|
503
503
|
let executionCount = 0;
|
|
@@ -579,7 +579,7 @@ describe("Worker", () => {
|
|
|
579
579
|
expect(claimed?.status).toBe("running");
|
|
580
580
|
expect(claimed?.workerId).toBe("test-worker");
|
|
581
581
|
});
|
|
582
|
-
test("sleep is not skipped when worker crashes after creating sleep step but before marking workflow as sleeping
|
|
582
|
+
test("sleep is not skipped when worker crashes after creating sleep step but before marking workflow as sleeping", async () => {
|
|
583
583
|
const backend = await createBackend();
|
|
584
584
|
const client = new OpenWorkflow({ backend });
|
|
585
585
|
let executionCount = 0;
|
|
@@ -631,7 +631,7 @@ describe("Worker", () => {
|
|
|
631
631
|
const result = await handle.result();
|
|
632
632
|
expect(result.afterSleepCount).toBe(1);
|
|
633
633
|
});
|
|
634
|
-
test("version enables conditional code paths
|
|
634
|
+
test("version enables conditional code paths", async () => {
|
|
635
635
|
const backend = await createBackend();
|
|
636
636
|
const client = new OpenWorkflow({ backend });
|
|
637
637
|
const workflow = client.defineWorkflow({ name: "conditional-workflow", version: "v2" }, async ({ version, step }) => {
|
|
@@ -774,13 +774,127 @@ describe("Worker", () => {
|
|
|
774
774
|
await handle.cancel();
|
|
775
775
|
await expect(handle.result()).rejects.toThrow(/Workflow cancel-result was canceled/);
|
|
776
776
|
});
|
|
777
|
+
describe("version matching", () => {
|
|
778
|
+
test("worker matches workflow runs by version", async () => {
|
|
779
|
+
const backend = await createBackend();
|
|
780
|
+
const client = new OpenWorkflow({ backend });
|
|
781
|
+
client.defineWorkflow({ name: "versioned-workflow", version: "v1" }, async ({ step }) => {
|
|
782
|
+
return await step.run({ name: "compute" }, () => "v1-result");
|
|
783
|
+
});
|
|
784
|
+
client.defineWorkflow({ name: "versioned-workflow", version: "v2" }, async ({ step }) => {
|
|
785
|
+
return await step.run({ name: "compute" }, () => "v2-result");
|
|
786
|
+
});
|
|
787
|
+
const worker = client.newWorker({ concurrency: 2 });
|
|
788
|
+
const v1Spec = defineWorkflowSpec({
|
|
789
|
+
name: "versioned-workflow",
|
|
790
|
+
version: "v1",
|
|
791
|
+
});
|
|
792
|
+
const v2Spec = defineWorkflowSpec({
|
|
793
|
+
name: "versioned-workflow",
|
|
794
|
+
version: "v2",
|
|
795
|
+
});
|
|
796
|
+
const handleV1 = await client.runWorkflow(v1Spec);
|
|
797
|
+
const handleV2 = await client.runWorkflow(v2Spec);
|
|
798
|
+
await worker.tick();
|
|
799
|
+
await sleep(100); // wait for background execution
|
|
800
|
+
const resultV1 = await handleV1.result();
|
|
801
|
+
const resultV2 = await handleV2.result();
|
|
802
|
+
expect(resultV1).toBe("v1-result");
|
|
803
|
+
expect(resultV2).toBe("v2-result");
|
|
804
|
+
});
|
|
805
|
+
test("worker fails workflow run when version is not registered", async () => {
|
|
806
|
+
const backend = await createBackend();
|
|
807
|
+
const client = new OpenWorkflow({ backend });
|
|
808
|
+
client.defineWorkflow({ name: "version-check", version: "v1" }, () => "v1-result");
|
|
809
|
+
const worker = client.newWorker();
|
|
810
|
+
const workflowRun = await backend.createWorkflowRun({
|
|
811
|
+
workflowName: "version-check",
|
|
812
|
+
version: "v2",
|
|
813
|
+
idempotencyKey: null,
|
|
814
|
+
config: {},
|
|
815
|
+
context: null,
|
|
816
|
+
input: null,
|
|
817
|
+
availableAt: null,
|
|
818
|
+
deadlineAt: null,
|
|
819
|
+
});
|
|
820
|
+
await worker.tick();
|
|
821
|
+
const updated = await backend.getWorkflowRun({
|
|
822
|
+
workflowRunId: workflowRun.id,
|
|
823
|
+
});
|
|
824
|
+
expect(updated?.status).toBe("pending");
|
|
825
|
+
expect(updated?.error).toEqual({
|
|
826
|
+
message: 'Workflow "version-check" (version: v2) is not registered',
|
|
827
|
+
});
|
|
828
|
+
});
|
|
829
|
+
test("unversioned workflow does not match versioned run", async () => {
|
|
830
|
+
const backend = await createBackend();
|
|
831
|
+
const client = new OpenWorkflow({ backend });
|
|
832
|
+
client.defineWorkflow({ name: "version-mismatch" }, () => "unversioned-result");
|
|
833
|
+
const worker = client.newWorker();
|
|
834
|
+
const workflowRun = await backend.createWorkflowRun({
|
|
835
|
+
workflowName: "version-mismatch",
|
|
836
|
+
version: "v1",
|
|
837
|
+
idempotencyKey: null,
|
|
838
|
+
config: {},
|
|
839
|
+
context: null,
|
|
840
|
+
input: null,
|
|
841
|
+
availableAt: null,
|
|
842
|
+
deadlineAt: null,
|
|
843
|
+
});
|
|
844
|
+
await worker.tick();
|
|
845
|
+
const updated = await backend.getWorkflowRun({
|
|
846
|
+
workflowRunId: workflowRun.id,
|
|
847
|
+
});
|
|
848
|
+
expect(updated?.status).toBe("pending");
|
|
849
|
+
expect(updated?.error).toEqual({
|
|
850
|
+
message: 'Workflow "version-mismatch" (version: v1) is not registered',
|
|
851
|
+
});
|
|
852
|
+
});
|
|
853
|
+
test("versioned workflow does not match unversioned run", async () => {
|
|
854
|
+
const backend = await createBackend();
|
|
855
|
+
const client = new OpenWorkflow({ backend });
|
|
856
|
+
client.defineWorkflow({ name: "version-required", version: "v1" }, () => "v1-result");
|
|
857
|
+
const worker = client.newWorker();
|
|
858
|
+
const workflowRun = await backend.createWorkflowRun({
|
|
859
|
+
workflowName: "version-required",
|
|
860
|
+
version: null,
|
|
861
|
+
idempotencyKey: null,
|
|
862
|
+
config: {},
|
|
863
|
+
context: null,
|
|
864
|
+
input: null,
|
|
865
|
+
availableAt: null,
|
|
866
|
+
deadlineAt: null,
|
|
867
|
+
});
|
|
868
|
+
await worker.tick();
|
|
869
|
+
const updated = await backend.getWorkflowRun({
|
|
870
|
+
workflowRunId: workflowRun.id,
|
|
871
|
+
});
|
|
872
|
+
expect(updated?.status).toBe("pending");
|
|
873
|
+
expect(updated?.error).toEqual({
|
|
874
|
+
message: 'Workflow "version-required" is not registered',
|
|
875
|
+
});
|
|
876
|
+
});
|
|
877
|
+
test("workflow receives run's version, not registered version", async () => {
|
|
878
|
+
// this test verifies that the version passed to the workflow function
|
|
879
|
+
// is the one from the workflow run, not the registered workflow
|
|
880
|
+
const backend = await createBackend();
|
|
881
|
+
const client = new OpenWorkflow({ backend });
|
|
882
|
+
const workflow = client.defineWorkflow({ name: "version-in-handler", version: "v1" }, async ({ version, step }) => {
|
|
883
|
+
return await step.run({ name: "get-version" }, () => version);
|
|
884
|
+
});
|
|
885
|
+
const worker = client.newWorker();
|
|
886
|
+
const handle = await workflow.run();
|
|
887
|
+
await worker.tick();
|
|
888
|
+
const result = await handle.result();
|
|
889
|
+
expect(result).toBe("v1");
|
|
890
|
+
});
|
|
891
|
+
});
|
|
777
892
|
});
|
|
778
893
|
async function createBackend() {
|
|
779
|
-
return await BackendPostgres.connect(
|
|
894
|
+
return await BackendPostgres.connect(DEFAULT_POSTGRES_URL, {
|
|
780
895
|
namespaceId: randomUUID(), // unique namespace per test
|
|
781
896
|
});
|
|
782
897
|
}
|
|
783
898
|
function sleep(ms) {
|
|
784
899
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
785
900
|
}
|
|
786
|
-
//# sourceMappingURL=worker.test.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from "./core/schema.js";
|
|
2
|
+
import { WorkflowFunction } from "./execution.js";
|
|
3
|
+
/**
|
|
4
|
+
* A workflow spec.
|
|
5
|
+
*/
|
|
6
|
+
export interface WorkflowSpec<Input, Output, RawInput> {
|
|
7
|
+
/** The name of the workflow. */
|
|
8
|
+
readonly name: string;
|
|
9
|
+
/** The version of the workflow. */
|
|
10
|
+
readonly version?: string;
|
|
11
|
+
/** The schema used to validate inputs. */
|
|
12
|
+
readonly schema?: StandardSchemaV1<RawInput, Input>;
|
|
13
|
+
/** Phantom type carrier - won't exist at runtime. */
|
|
14
|
+
readonly __types?: {
|
|
15
|
+
output: Output;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Define a workflow spec.
|
|
20
|
+
* @param spec - The workflow spec
|
|
21
|
+
* @returns The workflow spec
|
|
22
|
+
*/
|
|
23
|
+
export declare function defineWorkflowSpec<Input, Output = unknown, RawInput = Input>(spec: WorkflowSpec<Input, Output, RawInput>): WorkflowSpec<Input, Output, RawInput>;
|
|
24
|
+
/**
|
|
25
|
+
* Define a workflow spec.
|
|
26
|
+
* @param spec - The workflow spec
|
|
27
|
+
* @returns The workflow spec
|
|
28
|
+
* @deprecated use `defineWorkflowSpec` instead
|
|
29
|
+
*/
|
|
30
|
+
export declare const declareWorkflow: typeof defineWorkflowSpec;
|
|
31
|
+
/**
|
|
32
|
+
* A workflow spec and implementation.
|
|
33
|
+
*/
|
|
34
|
+
export interface Workflow<Input, Output, RawInput> {
|
|
35
|
+
/** The workflow spec. */
|
|
36
|
+
readonly spec: WorkflowSpec<Input, Output, RawInput>;
|
|
37
|
+
/** The workflow implementation function. */
|
|
38
|
+
readonly fn: WorkflowFunction<Input, Output>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Define a workflow.
|
|
42
|
+
* @param spec - The workflow spec
|
|
43
|
+
* @param fn - The workflow implementation function
|
|
44
|
+
* @returns The workflow
|
|
45
|
+
*/
|
|
46
|
+
export declare function defineWorkflow<Input, Output, RawInput = Input>(spec: WorkflowSpec<Input, Output, RawInput>, fn: WorkflowFunction<Input, Output>): Workflow<Input, Output, RawInput>;
|
|
47
|
+
/**
|
|
48
|
+
* Define a workflow.
|
|
49
|
+
* @param spec - The workflow spec
|
|
50
|
+
* @param fn - The workflow implementation function
|
|
51
|
+
* @returns The workflow
|
|
52
|
+
*/
|
|
53
|
+
export declare function defineWorkflow<Input, WorkflowFn extends WorkflowFunction<Input, unknown> = WorkflowFunction<Input, unknown>, RawInput = Input>(spec: WorkflowSpec<Input, Awaited<ReturnType<WorkflowFn>>, RawInput>, fn: WorkflowFn): Workflow<Input, Awaited<ReturnType<WorkflowFn>>, RawInput>;
|
|
54
|
+
/**
|
|
55
|
+
* Type guard to check if a value is a Workflow object.
|
|
56
|
+
* @param value - The value to check
|
|
57
|
+
* @returns True if the value is a Workflow
|
|
58
|
+
*/
|
|
59
|
+
export declare function isWorkflow(value: unknown): boolean;
|
|
60
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../workflow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ;IACnD,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mCAAmC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACpD,qDAAqD;IACrD,QAAQ,CAAC,OAAO,CAAC,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,GAAG,KAAK,EAC1E,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,GAC1C,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAEvC;AAED;;;;;GAKG;AACH,eAAO,MAAM,eAAe,2BAAqB,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ;IAC/C,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrD,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;CAC9C;AAED;;;;;GAKG;AAIH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,GAAG,KAAK,EAC5D,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAC3C,EAAE,EAAE,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,GAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAErC;;;;;GAKG;AAGH,wBAAgB,cAAc,CAC5B,KAAK,EACL,UAAU,SAAS,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,gBAAgB,CACpE,KAAK,EACL,OAAO,CACR,EACD,QAAQ,GAAG,KAAK,EAEhB,IAAI,EAAE,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,EACpE,EAAE,EAAE,UAAU,GACb,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAmB9D;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,WAkBxC"}
|
package/dist/workflow.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define a workflow spec.
|
|
3
|
+
* @param spec - The workflow spec
|
|
4
|
+
* @returns The workflow spec
|
|
5
|
+
*/
|
|
6
|
+
export function defineWorkflowSpec(spec) {
|
|
7
|
+
return spec;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Define a workflow spec.
|
|
11
|
+
* @param spec - The workflow spec
|
|
12
|
+
* @returns The workflow spec
|
|
13
|
+
* @deprecated use `defineWorkflowSpec` instead
|
|
14
|
+
*/
|
|
15
|
+
export const declareWorkflow = defineWorkflowSpec;
|
|
16
|
+
/**
|
|
17
|
+
* Define a workflow.
|
|
18
|
+
* @internal
|
|
19
|
+
* @param spec - The workflow spec
|
|
20
|
+
* @param fn - The workflow implementation function
|
|
21
|
+
* @returns The workflow
|
|
22
|
+
*/
|
|
23
|
+
export function defineWorkflow(spec, fn) {
|
|
24
|
+
return {
|
|
25
|
+
spec,
|
|
26
|
+
fn,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Type guard to check if a value is a Workflow object.
|
|
31
|
+
* @param value - The value to check
|
|
32
|
+
* @returns True if the value is a Workflow
|
|
33
|
+
*/
|
|
34
|
+
export function isWorkflow(value) {
|
|
35
|
+
if (typeof value !== "object" || value === null) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
const maybeWorkflow = value;
|
|
39
|
+
if (!("spec" in maybeWorkflow) || !("fn" in maybeWorkflow)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const { spec, fn } = maybeWorkflow;
|
|
43
|
+
return (typeof spec === "object" &&
|
|
44
|
+
spec !== null &&
|
|
45
|
+
"name" in spec &&
|
|
46
|
+
typeof spec.name === "string" &&
|
|
47
|
+
typeof fn === "function");
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.test.d.ts","sourceRoot":"","sources":["../workflow.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { defineWorkflow, defineWorkflowSpec, isWorkflow } from "./workflow.js";
|
|
2
|
+
import { describe, expect, test } from "vitest";
|
|
3
|
+
describe("defineWorkflowSpec", () => {
|
|
4
|
+
test("returns spec (passthrough)", () => {
|
|
5
|
+
const spec = { name: "test-workflow" };
|
|
6
|
+
const definedSpec = defineWorkflowSpec(spec);
|
|
7
|
+
expect(definedSpec).toStrictEqual(spec);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
describe("defineWorkflow", () => {
|
|
11
|
+
test("returns workflow with spec and fn", () => {
|
|
12
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
13
|
+
function fn() {
|
|
14
|
+
return { result: "done" };
|
|
15
|
+
}
|
|
16
|
+
const spec = { name: "test-workflow" };
|
|
17
|
+
const workflow = defineWorkflow(spec, fn);
|
|
18
|
+
expect(workflow).toStrictEqual({
|
|
19
|
+
spec,
|
|
20
|
+
fn,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe("isWorkflow", () => {
|
|
25
|
+
test("returns true for valid workflow objects", () => {
|
|
26
|
+
const workflow = defineWorkflow({ name: "test" }, () => "done");
|
|
27
|
+
expect(isWorkflow(workflow)).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
test("returns false for null", () => {
|
|
30
|
+
expect(isWorkflow(null)).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
test("returns false for undefined", () => {
|
|
33
|
+
// eslint-disable-next-line unicorn/no-useless-undefined
|
|
34
|
+
expect(isWorkflow(undefined)).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
test("returns false for primitives", () => {
|
|
37
|
+
expect(isWorkflow("string")).toBe(false);
|
|
38
|
+
expect(isWorkflow(123)).toBe(false);
|
|
39
|
+
expect(isWorkflow(true)).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
test("returns false for objects without spec", () => {
|
|
42
|
+
expect(isWorkflow({ fn: () => "result" })).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
test("returns false for objects without fn", () => {
|
|
45
|
+
expect(isWorkflow({ spec: { name: "test" } })).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
test("returns false for objects with invalid spec", () => {
|
|
48
|
+
expect(isWorkflow({ spec: null, fn: () => "result" })).toBe(false);
|
|
49
|
+
expect(isWorkflow({ spec: "invalid", fn: () => "result" })).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
test("returns false for objects with invalid fn", () => {
|
|
52
|
+
expect(isWorkflow({ spec: { name: "test" }, fn: "not-a-function" })).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
// --- type checks below -------------------------------------------------------
|
|
56
|
+
// they're unused but useful to ensure that the types work as expected for both
|
|
57
|
+
// defineWorkflowSpec and defineWorkflow
|
|
58
|
+
const inferredTypesSpec = defineWorkflowSpec({
|
|
59
|
+
name: "inferred-types",
|
|
60
|
+
});
|
|
61
|
+
defineWorkflow(inferredTypesSpec, async ({ step }) => {
|
|
62
|
+
await step.run({ name: "step-1" }, () => {
|
|
63
|
+
return "success";
|
|
64
|
+
});
|
|
65
|
+
return { result: "done" };
|
|
66
|
+
});
|
|
67
|
+
const explicitInputTypeSpec = defineWorkflowSpec({
|
|
68
|
+
name: "explicit-input-type",
|
|
69
|
+
});
|
|
70
|
+
defineWorkflow(explicitInputTypeSpec, async ({ step }) => {
|
|
71
|
+
await step.run({ name: "step-1" }, () => {
|
|
72
|
+
return "success";
|
|
73
|
+
});
|
|
74
|
+
return { result: "done" };
|
|
75
|
+
});
|
|
76
|
+
const explicitInputAndOutputTypesSpec = defineWorkflowSpec({
|
|
77
|
+
name: "explicit-input-and-output-types",
|
|
78
|
+
});
|
|
79
|
+
defineWorkflow(explicitInputAndOutputTypesSpec, async ({ step }) => {
|
|
80
|
+
await step.run({ name: "step-1" }, () => {
|
|
81
|
+
return "success";
|
|
82
|
+
});
|
|
83
|
+
return { result: "done" };
|
|
84
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openworkflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Open-source TypeScript framework for building durable, resumable workflows",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"durable execution",
|
|
@@ -28,10 +28,25 @@
|
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
30
30
|
"types": "./dist/index.d.ts",
|
|
31
|
-
"development": "./index.ts",
|
|
32
31
|
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./internal": {
|
|
34
|
+
"types": "./dist/internal.d.ts",
|
|
35
|
+
"default": "./dist/internal.js"
|
|
36
|
+
},
|
|
37
|
+
"./postgres": {
|
|
38
|
+
"types": "./dist/postgres.d.ts",
|
|
39
|
+
"default": "./dist/postgres.js"
|
|
40
|
+
},
|
|
41
|
+
"./sqlite": {
|
|
42
|
+
"types": "./dist/sqlite.d.ts",
|
|
43
|
+
"default": "./dist/sqlite.js"
|
|
33
44
|
}
|
|
34
45
|
},
|
|
46
|
+
"bin": {
|
|
47
|
+
"openworkflow": "./dist/bin/openworkflow.js",
|
|
48
|
+
"ow": "./dist/bin/openworkflow.js"
|
|
49
|
+
},
|
|
35
50
|
"files": [
|
|
36
51
|
"dist"
|
|
37
52
|
],
|
|
@@ -40,10 +55,19 @@
|
|
|
40
55
|
"prepublishOnly": "npm run build"
|
|
41
56
|
},
|
|
42
57
|
"devDependencies": {
|
|
43
|
-
"arktype": "^2.1.
|
|
58
|
+
"arktype": "^2.1.29",
|
|
44
59
|
"valibot": "^1.2.0",
|
|
60
|
+
"vitest": "^4.0.18",
|
|
45
61
|
"yup": "^1.7.1",
|
|
46
|
-
"zod": "^4.
|
|
62
|
+
"zod": "^4.3.6"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"postgres": ">=3"
|
|
66
|
+
},
|
|
67
|
+
"peerDependenciesMeta": {
|
|
68
|
+
"postgres": {
|
|
69
|
+
"optional": true
|
|
70
|
+
}
|
|
47
71
|
},
|
|
48
72
|
"engines": {
|
|
49
73
|
"node": ">=20"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../backend-sqlite/backend.ts"],"names":[],"mappings":"AAaA,OAAO,EAEL,OAAO,EACP,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACpB,4BAA4B,EAC5B,sBAAsB,EACtB,sBAAsB,EACtB,iBAAiB,EACjB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,EACzB,sBAAsB,EACtB,WAAW,EACX,WAAW,EAGZ,MAAM,aAAa,CAAC;AAErB,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD,UAAU,oBAAoB;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,aAAc,YAAW,OAAO;IAC3C,OAAO,CAAC,EAAE,CAAW;IACrB,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO;IAKP;;;;OAIG;IACH,MAAM,CAAC,OAAO,CACZ,IAAI,GAAE,MAA8B,EACpC,OAAO,CAAC,EAAE,oBAAoB,GAC7B,aAAa;IAgBhB,IAAI,IAAI,IAAI;IAIN,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAgDvB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAenE,gBAAgB,CACpB,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA0FxB,sBAAsB,CAC1B,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC,WAAW,CAAC;IAmCjB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,WAAW,CAAC;IAoCtE,mBAAmB,CACvB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,WAAW,CAAC;IAyCjB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;IA+DpE,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAuDvB,gBAAgB,CACd,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAgE1C,gBAAgB,CACd,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAmE1C,OAAO,CAAC,wBAAwB;IAyC1B,iBAAiB,CACrB,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,WAAW,CAAC;IAwCvB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAenE,mBAAmB,CACvB,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,WAAW,CAAC;IA0DjB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC;CAyD3E"}
|