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.
Files changed (220) hide show
  1. package/README.md +43 -345
  2. package/dist/backend-test/backend.testsuite.d.ts +20 -0
  3. package/dist/backend-test/backend.testsuite.d.ts.map +1 -0
  4. package/dist/{core → backend-test}/backend.testsuite.js +191 -59
  5. package/dist/backend-test/index.d.ts +2 -0
  6. package/dist/backend-test/index.d.ts.map +1 -0
  7. package/dist/backend-test/index.js +1 -0
  8. package/dist/{core/backend.d.ts → backend.d.ts} +7 -5
  9. package/dist/backend.d.ts.map +1 -0
  10. package/dist/{core/backend.js → backend.js} +0 -1
  11. package/dist/backend.testsuite.d.ts +20 -0
  12. package/dist/backend.testsuite.d.ts.map +1 -0
  13. package/dist/{core/backend-test-suite.js → backend.testsuite.js} +301 -171
  14. package/dist/bin/openworkflow.d.ts +3 -0
  15. package/dist/bin/openworkflow.d.ts.map +1 -0
  16. package/dist/bin/openworkflow.js +43 -0
  17. package/dist/chaos.test.d.ts +2 -0
  18. package/dist/chaos.test.d.ts.map +1 -0
  19. package/dist/chaos.test.js +88 -0
  20. package/dist/client.d.ts +141 -0
  21. package/dist/client.d.ts.map +1 -0
  22. package/dist/{sdk/sdk.js → client.js} +43 -71
  23. package/dist/client.test.d.ts +2 -0
  24. package/dist/client.test.d.ts.map +1 -0
  25. package/dist/{sdk/sdk.test.js → client.test.js} +130 -14
  26. package/dist/core/duration.d.ts +4 -2
  27. package/dist/core/duration.d.ts.map +1 -1
  28. package/dist/core/duration.js +3 -2
  29. package/dist/core/duration.test.js +0 -1
  30. package/dist/core/error.d.ts +14 -0
  31. package/dist/core/error.d.ts.map +1 -0
  32. package/dist/core/error.js +17 -0
  33. package/dist/core/error.test.d.ts +2 -0
  34. package/dist/core/error.test.d.ts.map +1 -0
  35. package/dist/core/error.test.js +60 -0
  36. package/dist/core/json.js +0 -1
  37. package/dist/core/result.d.ts +14 -4
  38. package/dist/core/result.d.ts.map +1 -1
  39. package/dist/core/result.js +10 -1
  40. package/dist/core/result.test.js +2 -2
  41. package/dist/core/retry.d.ts +0 -9
  42. package/dist/core/retry.d.ts.map +1 -1
  43. package/dist/core/retry.js +0 -15
  44. package/dist/core/schema.js +0 -1
  45. package/dist/core/step.d.ts +1 -32
  46. package/dist/core/step.d.ts.map +1 -1
  47. package/dist/core/step.js +0 -36
  48. package/dist/core/step.test.js +1 -75
  49. package/dist/core/workflow.d.ts +2 -47
  50. package/dist/core/workflow.d.ts.map +1 -1
  51. package/dist/core/workflow.js +0 -45
  52. package/dist/core/workflow.test.js +1 -104
  53. package/dist/driver.d.ts +116 -0
  54. package/dist/driver.d.ts.map +1 -0
  55. package/dist/driver.js +1 -0
  56. package/dist/{execution/execution.d.ts → execution.d.ts} +4 -26
  57. package/dist/execution.d.ts.map +1 -0
  58. package/dist/{execution/execution.js → execution.js} +4 -5
  59. package/dist/execution.test.d.ts.map +1 -0
  60. package/dist/{execution/execution.test.js → execution.test.js} +4 -5
  61. package/dist/factory.d.ts +74 -0
  62. package/dist/factory.d.ts.map +1 -0
  63. package/dist/factory.js +72 -0
  64. package/dist/index.d.ts +6 -9
  65. package/dist/index.d.ts.map +1 -1
  66. package/dist/index.js +4 -5
  67. package/dist/internal.d.ts +7 -0
  68. package/dist/internal.d.ts.map +1 -0
  69. package/dist/internal.js +2 -0
  70. package/dist/node-sqlite/backend.d.ts +52 -0
  71. package/dist/node-sqlite/backend.d.ts.map +1 -0
  72. package/dist/node-sqlite/backend.js +673 -0
  73. package/dist/node-sqlite/index.d.ts +11 -0
  74. package/dist/node-sqlite/index.d.ts.map +1 -0
  75. package/dist/node-sqlite/index.js +7 -0
  76. package/dist/node-sqlite/sqlite.d.ts +60 -0
  77. package/dist/node-sqlite/sqlite.d.ts.map +1 -0
  78. package/dist/{backend-sqlite → node-sqlite}/sqlite.js +20 -3
  79. package/dist/postgres/backend.d.ts +44 -0
  80. package/dist/postgres/backend.d.ts.map +1 -0
  81. package/dist/postgres/backend.js +534 -0
  82. package/dist/postgres/backend.test.d.ts +2 -0
  83. package/dist/postgres/backend.test.d.ts.map +1 -0
  84. package/dist/postgres/backend.test.js +19 -0
  85. package/dist/postgres/driver.d.ts +81 -0
  86. package/dist/postgres/driver.d.ts.map +1 -0
  87. package/dist/postgres/driver.js +63 -0
  88. package/dist/postgres/index.d.ts +11 -0
  89. package/dist/postgres/index.d.ts.map +1 -0
  90. package/dist/postgres/index.js +7 -0
  91. package/dist/postgres/internal.d.ts +2 -0
  92. package/dist/postgres/internal.d.ts.map +1 -0
  93. package/dist/postgres/internal.js +1 -0
  94. package/dist/postgres/postgres.d.ts +42 -0
  95. package/dist/postgres/postgres.d.ts.map +1 -0
  96. package/dist/postgres/postgres.js +233 -0
  97. package/dist/postgres/postgres.test.d.ts +2 -0
  98. package/dist/postgres/postgres.test.d.ts.map +1 -0
  99. package/dist/postgres/postgres.test.js +45 -0
  100. package/dist/postgres/scripts/db-migrate.d.ts +2 -0
  101. package/dist/postgres/scripts/db-migrate.d.ts.map +1 -0
  102. package/dist/postgres/scripts/db-migrate.js +4 -0
  103. package/dist/postgres/scripts/db-reset.d.ts +2 -0
  104. package/dist/postgres/scripts/db-reset.d.ts.map +1 -0
  105. package/dist/postgres/scripts/db-reset.js +5 -0
  106. package/dist/postgres/scripts/squawk.d.ts +2 -0
  107. package/dist/postgres/scripts/squawk.d.ts.map +1 -0
  108. package/dist/postgres/scripts/squawk.js +16 -0
  109. package/dist/postgres/vitest.global-setup.d.ts +3 -0
  110. package/dist/postgres/vitest.global-setup.d.ts.map +1 -0
  111. package/dist/postgres/vitest.global-setup.js +7 -0
  112. package/dist/postgres.d.ts +2 -0
  113. package/dist/postgres.d.ts.map +1 -0
  114. package/dist/postgres.js +1 -0
  115. package/dist/registry.d.ts +27 -0
  116. package/dist/registry.d.ts.map +1 -0
  117. package/dist/registry.js +48 -0
  118. package/dist/registry.test.d.ts +2 -0
  119. package/dist/registry.test.d.ts.map +1 -0
  120. package/dist/registry.test.js +109 -0
  121. package/dist/{backend-sqlite → sqlite}/backend.d.ts +8 -4
  122. package/dist/sqlite/backend.d.ts.map +1 -0
  123. package/dist/{backend-sqlite → sqlite}/backend.js +35 -9
  124. package/dist/sqlite/backend.test.d.ts +2 -0
  125. package/dist/sqlite/backend.test.d.ts.map +1 -0
  126. package/dist/sqlite/backend.test.js +50 -0
  127. package/dist/sqlite/driver.d.ts +79 -0
  128. package/dist/sqlite/driver.d.ts.map +1 -0
  129. package/dist/sqlite/driver.js +62 -0
  130. package/dist/sqlite/index.d.ts +13 -0
  131. package/dist/sqlite/index.d.ts.map +1 -0
  132. package/dist/sqlite/index.js +11 -0
  133. package/dist/sqlite/internal.d.ts +2 -0
  134. package/dist/sqlite/internal.d.ts.map +1 -0
  135. package/dist/sqlite/internal.js +1 -0
  136. package/dist/{backend-sqlite → sqlite}/sqlite.d.ts +18 -2
  137. package/dist/sqlite/sqlite.d.ts.map +1 -0
  138. package/dist/sqlite/sqlite.js +246 -0
  139. package/dist/sqlite/sqlite.test.d.ts +2 -0
  140. package/dist/sqlite/sqlite.test.d.ts.map +1 -0
  141. package/dist/sqlite/sqlite.test.js +171 -0
  142. package/dist/sqlite.d.ts +2 -0
  143. package/dist/sqlite.d.ts.map +1 -0
  144. package/dist/sqlite.js +1 -0
  145. package/dist/tsconfig.tsbuildinfo +1 -1
  146. package/dist/{worker/worker.d.ts → worker.d.ts} +11 -4
  147. package/dist/worker.d.ts.map +1 -0
  148. package/dist/{worker/worker.js → worker.js} +20 -11
  149. package/dist/{worker/worker.test.d.ts.map → worker.test.d.ts.map} +1 -1
  150. package/dist/{worker/worker.test.js → worker.test.js} +136 -22
  151. package/dist/workflow.d.ts +60 -0
  152. package/dist/workflow.d.ts.map +1 -0
  153. package/dist/workflow.js +48 -0
  154. package/dist/workflow.test.d.ts +2 -0
  155. package/dist/workflow.test.d.ts.map +1 -0
  156. package/dist/workflow.test.js +84 -0
  157. package/package.json +28 -4
  158. package/dist/backend-sqlite/backend.d.ts.map +0 -1
  159. package/dist/backend-sqlite/backend.js.map +0 -1
  160. package/dist/backend-sqlite/index.d.ts +0 -2
  161. package/dist/backend-sqlite/index.d.ts.map +0 -1
  162. package/dist/backend-sqlite/index.js +0 -2
  163. package/dist/backend-sqlite/index.js.map +0 -1
  164. package/dist/backend-sqlite/sqlite.d.ts.map +0 -1
  165. package/dist/backend-sqlite/sqlite.js.map +0 -1
  166. package/dist/config/config.d.ts +0 -102
  167. package/dist/config/config.d.ts.map +0 -1
  168. package/dist/config/config.js +0 -29
  169. package/dist/config/config.js.map +0 -1
  170. package/dist/config/index.d.ts +0 -3
  171. package/dist/config/index.d.ts.map +0 -1
  172. package/dist/config/index.js +0 -2
  173. package/dist/config/index.js.map +0 -1
  174. package/dist/config.d.ts +0 -28
  175. package/dist/config.d.ts.map +0 -1
  176. package/dist/config.js +0 -41
  177. package/dist/config.js.map +0 -1
  178. package/dist/core/backend-test-suite.d.ts +0 -22
  179. package/dist/core/backend-test-suite.d.ts.map +0 -1
  180. package/dist/core/backend-test-suite.js.map +0 -1
  181. package/dist/core/backend.d.ts.map +0 -1
  182. package/dist/core/backend.js.map +0 -1
  183. package/dist/core/backend.testsuite.d.ts +0 -21
  184. package/dist/core/backend.testsuite.d.ts.map +0 -1
  185. package/dist/core/backend.testsuite.js.map +0 -1
  186. package/dist/core/duration.js.map +0 -1
  187. package/dist/core/duration.test.js.map +0 -1
  188. package/dist/core/json.js.map +0 -1
  189. package/dist/core/result.js.map +0 -1
  190. package/dist/core/result.test.js.map +0 -1
  191. package/dist/core/retry.js.map +0 -1
  192. package/dist/core/retry.test.d.ts +0 -2
  193. package/dist/core/retry.test.d.ts.map +0 -1
  194. package/dist/core/retry.test.js +0 -36
  195. package/dist/core/retry.test.js.map +0 -1
  196. package/dist/core/schema.js.map +0 -1
  197. package/dist/core/step.js.map +0 -1
  198. package/dist/core/step.test.js.map +0 -1
  199. package/dist/core/workflow.js.map +0 -1
  200. package/dist/core/workflow.test.js.map +0 -1
  201. package/dist/execution/execution.d.ts.map +0 -1
  202. package/dist/execution/execution.js.map +0 -1
  203. package/dist/execution/execution.test.d.ts.map +0 -1
  204. package/dist/execution/execution.test.js.map +0 -1
  205. package/dist/global.d.ts +0 -62
  206. package/dist/global.d.ts.map +0 -1
  207. package/dist/global.js +0 -78
  208. package/dist/global.js.map +0 -1
  209. package/dist/index.js.map +0 -1
  210. package/dist/sdk/sdk.d.ts +0 -182
  211. package/dist/sdk/sdk.d.ts.map +0 -1
  212. package/dist/sdk/sdk.js.map +0 -1
  213. package/dist/sdk/sdk.test.d.ts +0 -2
  214. package/dist/sdk/sdk.test.d.ts.map +0 -1
  215. package/dist/sdk/sdk.test.js.map +0 -1
  216. package/dist/worker/worker.d.ts.map +0 -1
  217. package/dist/worker/worker.js.map +0 -1
  218. package/dist/worker/worker.test.js.map +0 -1
  219. /package/dist/{execution/execution.test.d.ts → execution.test.d.ts} +0 -0
  220. /package/dist/{worker/worker.test.d.ts → worker.test.d.ts} +0 -0
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=openworkflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openworkflow.d.ts","sourceRoot":"","sources":["../../bin/openworkflow.ts"],"names":[],"mappings":""}
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * This script is a zero-dependency entrypoint for the OpenWorkflow CLI. It
4
+ * allows users to run `npx openworkflow <command>` without requiring the core
5
+ * 'openworkflow' package to have any production dependencies (like commander,
6
+ * consola, etc).
7
+ *
8
+ * Note: This file is transpiled to `./dist/bin/openworkflow.js`. Relative paths
9
+ * below are calculated based on that runtime location.
10
+ */
11
+ import { spawnSync } from "node:child_process";
12
+ import { existsSync, readFileSync } from "node:fs";
13
+ import path from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ const __dirname = fileURLToPath(new URL(".", import.meta.url));
16
+ // get the version of the current package to ensure we call the matching CLI
17
+ const packageJsonPath = path.join(__dirname, "../../package.json");
18
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
19
+ const version = packageJson.version;
20
+ // capture all args passed to npx openworkflow (e.g., "init", "worker start")
21
+ const args = process.argv.slice(2);
22
+ // build the command, using tsx to run local TypeScript CLI if in dev and
23
+ // otherwise using npx to run the published CLI package
24
+ const cliScriptFilePath = path.resolve(__dirname, "../../../cli/cli.ts");
25
+ const isMonorepo = existsSync(cliScriptFilePath);
26
+ if (isMonorepo) {
27
+ console.log("⚠️ Running OpenWorkflow CLI from local source (monorepo development mode)\n");
28
+ }
29
+ const command = isMonorepo
30
+ ? // `npx tsx ../../../cli/cli.ts ...args`
31
+ ["tsx", cliScriptFilePath, ...args]
32
+ : // `npx -y @openworkflow/cli@<version> ...args`
33
+ // uses -y to skip the "Need to install @openworkflow/cli" prompt
34
+ ["-y", `@openworkflow/cli@${version}`, ...args];
35
+ // spawn the CLI the command to run the actual CLI package
36
+ const result = spawnSync(
37
+ // eslint-disable-next-line sonarjs/no-os-command-from-path
38
+ "npx", command, {
39
+ stdio: "inherit",
40
+ shell: true,
41
+ });
42
+ // exit with the same status code as the CLI
43
+ process.exit(result.status ?? 0);
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chaos.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chaos.test.d.ts","sourceRoot":"","sources":["../chaos.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import { OpenWorkflow } from "./client.js";
2
+ import { BackendPostgres } from "./postgres.js";
3
+ import { DEFAULT_POSTGRES_URL } from "./postgres/postgres.js";
4
+ import { randomInt, randomUUID } from "node:crypto";
5
+ import { describe, expect, test } from "vitest";
6
+ const TOTAL_STEPS = 50;
7
+ const WORKER_COUNT = 3;
8
+ const WORKER_CONCURRENCY = 2;
9
+ const STEP_DURATION_MS = 25;
10
+ const CHAOS_DURATION_MS = 5000;
11
+ const CHAOS_INTERVAL_MS = 200;
12
+ const TEST_TIMEOUT_MS = 30_000;
13
+ describe("chaos test", () => {
14
+ test("workflow completes despite random worker deaths", async () => {
15
+ const backend = await createBackend();
16
+ const client = new OpenWorkflow({ backend });
17
+ const workflow = client.defineWorkflow({ name: "chaos-workflow" }, async ({ step }) => {
18
+ const results = [];
19
+ for (let i = 0; i < TOTAL_STEPS; i++) {
20
+ const stepName = `step-${i.toString()}`;
21
+ const result = await step.run({ name: stepName }, async () => {
22
+ await sleep(STEP_DURATION_MS); // fake work
23
+ return i;
24
+ });
25
+ results.push(result);
26
+ }
27
+ return results;
28
+ });
29
+ const workers = await Promise.all(Array.from({ length: WORKER_COUNT }, () => createAndStartWorker(client)));
30
+ const handle = await workflow.run();
31
+ let workflowCompleted = false;
32
+ let chaosTask = null;
33
+ try {
34
+ chaosTask = runChaosTest({
35
+ client,
36
+ workers,
37
+ durationMs: CHAOS_DURATION_MS,
38
+ intervalMs: CHAOS_INTERVAL_MS,
39
+ shouldStop: () => workflowCompleted,
40
+ });
41
+ const result = await handle.result();
42
+ workflowCompleted = true;
43
+ const restarts = await chaosTask;
44
+ expect(result).toHaveLength(TOTAL_STEPS);
45
+ expect(result[TOTAL_STEPS - 1]).toBe(TOTAL_STEPS - 1);
46
+ expect(restarts).toBeGreaterThan(0);
47
+ }
48
+ finally {
49
+ workflowCompleted = true;
50
+ if (chaosTask)
51
+ await chaosTask;
52
+ await Promise.all(workers.map((worker) => worker.stop()));
53
+ await backend.stop();
54
+ }
55
+ }, TEST_TIMEOUT_MS);
56
+ });
57
+ async function runChaosTest(params) {
58
+ const { client, workers, durationMs, intervalMs, shouldStop } = params;
59
+ const chaosEndsAt = Date.now() + durationMs;
60
+ let restartCount = 0;
61
+ while (Date.now() < chaosEndsAt && !shouldStop()) {
62
+ await sleep(intervalMs);
63
+ if (workers.length === 0) {
64
+ workers.push(await createAndStartWorker(client));
65
+ continue;
66
+ }
67
+ const index = randomInt(workers.length);
68
+ const victim = workers.splice(index, 1)[0];
69
+ await victim?.stop();
70
+ const replacement = await createAndStartWorker(client);
71
+ workers.push(replacement);
72
+ restartCount++;
73
+ }
74
+ return restartCount;
75
+ }
76
+ async function createBackend() {
77
+ return await BackendPostgres.connect(DEFAULT_POSTGRES_URL, {
78
+ namespaceId: randomUUID(),
79
+ });
80
+ }
81
+ async function createAndStartWorker(client) {
82
+ const worker = client.newWorker({ concurrency: WORKER_CONCURRENCY });
83
+ await worker.start();
84
+ return worker;
85
+ }
86
+ function sleep(ms) {
87
+ return new Promise((resolve) => setTimeout(resolve, ms));
88
+ }
@@ -0,0 +1,141 @@
1
+ import type { Backend } from "./backend.js";
2
+ import type { StandardSchemaV1 } from "./core/schema.js";
3
+ import type { SchemaInput, SchemaOutput, WorkflowRun } from "./core/workflow.js";
4
+ import type { WorkflowFunction } from "./execution.js";
5
+ import { Worker } from "./worker.js";
6
+ import { type Workflow, type WorkflowSpec } from "./workflow.js";
7
+ type WorkflowHandlerInput<TSchema, Input> = SchemaOutput<TSchema, Input>;
8
+ type WorkflowRunInput<TSchema, Input> = SchemaInput<TSchema, Input>;
9
+ /**
10
+ * Options for the OpenWorkflow client.
11
+ */
12
+ export interface OpenWorkflowOptions {
13
+ backend: Backend;
14
+ }
15
+ /**
16
+ * Client used to register workflows and start runs.
17
+ */
18
+ export declare class OpenWorkflow {
19
+ private backend;
20
+ private registry;
21
+ constructor(options: OpenWorkflowOptions);
22
+ /**
23
+ * Create a new Worker with this client's backend and workflows.
24
+ * @param options - Worker options
25
+ * @param options.concurrency - Max concurrent workflow runs
26
+ * @returns Worker instance
27
+ */
28
+ newWorker(options?: {
29
+ concurrency?: number | undefined;
30
+ }): Worker;
31
+ /**
32
+ * Provide the implementation for a declared workflow. This links the workflow
33
+ * specification to its execution logic and registers it with this
34
+ * OpenWorkflow instance for worker execution.
35
+ * @param spec - Workflow spec
36
+ * @param fn - Workflow implementation
37
+ */
38
+ implementWorkflow<Input, Output, RunInput = Input>(spec: WorkflowSpec<Input, Output, RunInput>, fn: WorkflowFunction<Input, Output>): void;
39
+ /**
40
+ * Run a workflow from its specification. This is the primary way to schedule
41
+ * a workflow using only its WorkflowSpec.
42
+ * @param spec - Workflow spec
43
+ * @param input - Workflow input
44
+ * @param options - Run options
45
+ * @returns Handle for awaiting the result
46
+ * @example
47
+ * ```ts
48
+ * const handle = await ow.runWorkflow(emailWorkflow, { to: 'user@example.com' });
49
+ * const result = await handle.result();
50
+ * ```
51
+ */
52
+ runWorkflow<Input, Output, RunInput = Input>(spec: WorkflowSpec<Input, Output, RunInput>, input?: RunInput, options?: WorkflowRunOptions): Promise<WorkflowRunHandle<Output>>;
53
+ /**
54
+ * Define and register a new workflow.
55
+ * @param spec - Workflow spec
56
+ * @param fn - Workflow implementation
57
+ * @returns Runnable workflow
58
+ * @example
59
+ * ```ts
60
+ * const workflow = ow.defineWorkflow(
61
+ * { name: 'my-workflow' },
62
+ * async ({ input, step }) => {
63
+ * // workflow implementation
64
+ * },
65
+ * );
66
+ * ```
67
+ */
68
+ defineWorkflow<Input, Output, TSchema extends StandardSchemaV1 | undefined = undefined>(spec: WorkflowSpec<WorkflowHandlerInput<TSchema, Input>, Output, WorkflowRunInput<TSchema, Input>>, fn: WorkflowFunction<WorkflowHandlerInput<TSchema, Input>, Output>): RunnableWorkflow<WorkflowHandlerInput<TSchema, Input>, Output, WorkflowRunInput<TSchema, Input>>;
69
+ }
70
+ /**
71
+ * A fully defined workflow with its implementation. This class is returned by
72
+ * `client.defineWorkflow` and provides the `.run()` method for scheduling
73
+ * workflow runs.
74
+ */
75
+ export declare class RunnableWorkflow<Input, Output, RunInput = Input> {
76
+ private readonly ow;
77
+ readonly workflow: Workflow<Input, Output, RunInput>;
78
+ constructor(ow: OpenWorkflow, workflow: Workflow<Input, Output, RunInput>);
79
+ /**
80
+ * Starts a new workflow run.
81
+ * @param input - Workflow input
82
+ * @param options - Run options
83
+ * @returns Workflow run handle
84
+ */
85
+ run(input?: RunInput, options?: WorkflowRunOptions): Promise<WorkflowRunHandle<Output>>;
86
+ }
87
+ /**
88
+ * Options for creating a new workflow run from a runnable workflow when calling
89
+ * `workflowDef.run()`.
90
+ */
91
+ export interface WorkflowRunOptions {
92
+ /**
93
+ * Set a deadline for the workflow run. If the workflow exceeds this deadline,
94
+ * it will be marked as failed.
95
+ */
96
+ deadlineAt?: Date;
97
+ }
98
+ /**
99
+ * Options for WorkflowHandle.
100
+ */
101
+ export interface WorkflowHandleOptions {
102
+ backend: Backend;
103
+ workflowRun: WorkflowRun;
104
+ resultPollIntervalMs: number;
105
+ resultTimeoutMs: number;
106
+ }
107
+ /**
108
+ * Options for result() on a WorkflowRunHandle.
109
+ */
110
+ export interface WorkflowRunHandleResultOptions {
111
+ /**
112
+ * Time to wait for a workflow run to complete. Throws an error if the timeout
113
+ * is exceeded.
114
+ * @default 300000 (5 minutes)
115
+ */
116
+ timeoutMs?: number;
117
+ }
118
+ /**
119
+ * Represents a started workflow run and provides methods to await its result.
120
+ * Returned from `workflowDef.run()`.
121
+ */
122
+ export declare class WorkflowRunHandle<Output> {
123
+ private backend;
124
+ readonly workflowRun: WorkflowRun;
125
+ private resultPollIntervalMs;
126
+ private resultTimeoutMs;
127
+ constructor(options: WorkflowHandleOptions);
128
+ /**
129
+ * Waits for the workflow run to complete and returns the result.
130
+ * @param options - Options for waiting for the result
131
+ * @returns Workflow output
132
+ */
133
+ result(options?: WorkflowRunHandleResultOptions): Promise<Output>;
134
+ /**
135
+ * Cancels the workflow run. Only workflows in pending, running, or sleeping
136
+ * status can be canceled.
137
+ */
138
+ cancel(): Promise<void>;
139
+ }
140
+ export {};
141
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../client.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
- import { validateInput } from "../core/workflow.js";
2
- import { Worker } from "../worker/worker.js";
1
+ import { validateInput } from "./core/workflow.js";
2
+ import { WorkflowRegistry } from "./registry.js";
3
+ import { Worker } from "./worker.js";
4
+ import { defineWorkflow, } from "./workflow.js";
3
5
  const DEFAULT_RESULT_POLL_INTERVAL_MS = 1000; // 1s
4
6
  const DEFAULT_RESULT_TIMEOUT_MS = 5 * 60 * 1000; // 5m
5
7
  /**
@@ -7,17 +9,20 @@ const DEFAULT_RESULT_TIMEOUT_MS = 5 * 60 * 1000; // 5m
7
9
  */
8
10
  export class OpenWorkflow {
9
11
  backend;
10
- registeredWorkflows = new Map();
12
+ registry = new WorkflowRegistry();
11
13
  constructor(options) {
12
14
  this.backend = options.backend;
13
15
  }
14
16
  /**
15
17
  * Create a new Worker with this client's backend and workflows.
18
+ * @param options - Worker options
19
+ * @param options.concurrency - Max concurrent workflow runs
20
+ * @returns Worker instance
16
21
  */
17
22
  newWorker(options) {
18
23
  return new Worker({
19
24
  backend: this.backend,
20
- workflows: this.registeredWorkflows,
25
+ workflows: this.registry.getAll(),
21
26
  concurrency: options?.concurrency,
22
27
  });
23
28
  }
@@ -25,20 +30,23 @@ export class OpenWorkflow {
25
30
  * Provide the implementation for a declared workflow. This links the workflow
26
31
  * specification to its execution logic and registers it with this
27
32
  * OpenWorkflow instance for worker execution.
33
+ * @param spec - Workflow spec
34
+ * @param fn - Workflow implementation
28
35
  */
29
36
  implementWorkflow(spec, fn) {
30
- const key = getWorkflowKey(spec.name, spec.version);
31
- if (this.registeredWorkflows.has(key)) {
32
- const versionStr = spec.version ? ` (version: ${spec.version})` : "";
33
- throw new Error(`Workflow "${spec.name}"${versionStr} is already registered`);
34
- }
35
- const definition = new WorkflowDefinition(this, spec, fn);
36
- this.registeredWorkflows.set(key, definition);
37
+ const workflow = {
38
+ spec,
39
+ fn,
40
+ };
41
+ this.registry.register(workflow);
37
42
  }
38
43
  /**
39
44
  * Run a workflow from its specification. This is the primary way to schedule
40
45
  * a workflow using only its WorkflowSpec.
41
- *
46
+ * @param spec - Workflow spec
47
+ * @param input - Workflow input
48
+ * @param options - Run options
49
+ * @returns Handle for awaiting the result
42
50
  * @example
43
51
  * ```ts
44
52
  * const handle = await ow.runWorkflow(emailWorkflow, { to: 'user@example.com' });
@@ -53,7 +61,7 @@ export class OpenWorkflow {
53
61
  const parsedInput = validationResult.value;
54
62
  const workflowRun = await this.backend.createWorkflowRun({
55
63
  workflowName: spec.name,
56
- version: spec.version,
64
+ version: spec.version ?? null,
57
65
  idempotencyKey: null,
58
66
  config: {},
59
67
  context: null,
@@ -70,12 +78,9 @@ export class OpenWorkflow {
70
78
  }
71
79
  /**
72
80
  * Define and register a new workflow.
73
- *
74
- * This is a convenience method that combines `declareWorkflow` and
75
- * `implementWorkflow` into a single call. For better code splitting and to
76
- * separate declaration from implementation, consider using those methods
77
- * separately.
78
- *
81
+ * @param spec - Workflow spec
82
+ * @param fn - Workflow implementation
83
+ * @returns Runnable workflow
79
84
  * @example
80
85
  * ```ts
81
86
  * const workflow = ow.defineWorkflow(
@@ -86,67 +91,32 @@ export class OpenWorkflow {
86
91
  * );
87
92
  * ```
88
93
  */
89
- defineWorkflow(config, fn) {
90
- const spec = declareWorkflow(config);
91
- const key = getWorkflowKey(spec.name, spec.version);
92
- const definition = new WorkflowDefinition(this, spec, fn);
93
- this.registeredWorkflows.set(key, definition);
94
- return definition;
94
+ defineWorkflow(spec, fn) {
95
+ const workflow = defineWorkflow(spec, fn);
96
+ this.registry.register(workflow);
97
+ return new RunnableWorkflow(this, workflow);
95
98
  }
96
99
  }
97
- /**
98
- * Declare a workflow without providing its implementation (which is provided
99
- * separately via `implementWorkflow`). Returns a lightweight WorkflowSpec
100
- * that can be used to schedule workflow runs.
101
- *
102
- * @example
103
- * ```ts
104
- * export const emailWorkflow = declareWorkflow({
105
- * name: 'send-email',
106
- * schema: z.object({ to: z.string().email() }),
107
- * });
108
- * ```
109
- */
110
- export function declareWorkflow(config) {
111
- return {
112
- name: config.name,
113
- version: config.version ?? null,
114
- schema: config.schema ?? null,
115
- };
116
- }
117
- /**
118
- * Generate a composite key for workflow registration that includes both name
119
- * and version.
120
- *
121
- * @param name - The workflow name
122
- * @param version - The workflow version (null for unversioned)
123
- * @returns A composite key string
124
- */
125
- export function getWorkflowKey(name, version) {
126
- return version ? `${name}@${version}` : name;
127
- }
128
- //
129
- // --- Workflow Definition
130
- //
131
100
  /**
132
101
  * A fully defined workflow with its implementation. This class is returned by
133
- * `defineWorkflow` and provides the `.run()` method for scheduling workflow
134
- * runs.
102
+ * `client.defineWorkflow` and provides the `.run()` method for scheduling
103
+ * workflow runs.
135
104
  */
136
- export class WorkflowDefinition {
105
+ export class RunnableWorkflow {
137
106
  ow;
138
- spec;
139
- fn;
140
- constructor(ow, spec, fn) {
107
+ workflow;
108
+ constructor(ow, workflow) {
141
109
  this.ow = ow;
142
- this.spec = spec;
143
- this.fn = fn;
110
+ this.workflow = workflow;
144
111
  }
145
112
  /**
146
113
  * Starts a new workflow run.
114
+ * @param input - Workflow input
115
+ * @param options - Run options
116
+ * @returns Workflow run handle
147
117
  */
148
118
  async run(input, options) {
149
- return this.ow.runWorkflow(this.spec, input, options);
119
+ return this.ow.runWorkflow(this.workflow.spec, input, options);
150
120
  }
151
121
  }
152
122
  /**
@@ -166,9 +136,12 @@ export class WorkflowRunHandle {
166
136
  }
167
137
  /**
168
138
  * Waits for the workflow run to complete and returns the result.
139
+ * @param options - Options for waiting for the result
140
+ * @returns Workflow output
169
141
  */
170
- async result() {
142
+ async result(options) {
171
143
  const start = Date.now();
144
+ const timeout = options?.timeoutMs ?? this.resultTimeoutMs;
172
145
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
173
146
  while (true) {
174
147
  const latest = await this.backend.getWorkflowRun({
@@ -187,7 +160,7 @@ export class WorkflowRunHandle {
187
160
  if (latest.status === "canceled") {
188
161
  throw new Error(`Workflow ${this.workflowRun.workflowName} was canceled`);
189
162
  }
190
- if (Date.now() - start > this.resultTimeoutMs) {
163
+ if (Date.now() - start > timeout) {
191
164
  throw new Error(`Timed out waiting for workflow run ${this.workflowRun.id} to finish`);
192
165
  }
193
166
  await new Promise((resolve) => {
@@ -205,4 +178,3 @@ export class WorkflowRunHandle {
205
178
  });
206
179
  }
207
180
  }
208
- //# sourceMappingURL=sdk.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../client.test.ts"],"names":[],"mappings":""}