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
package/README.md CHANGED
@@ -8,40 +8,10 @@ OpenWorkflow is a TypeScript framework for building durable, resumable workflows
8
8
  that can pause for seconds or months, survive crashes and deploys, and resume
9
9
  exactly where they left off - all without extra servers to manage.
10
10
 
11
- > OpenWorkflow is in active development and moving quickly. Check out the
12
- > [Roadmap](#roadmap) for what’s coming next.
13
-
14
- ## Quick Start
15
-
16
- Prerequisites:
17
-
18
- - Node.js
19
- - PostgreSQL (and/or SQLite)
20
-
21
- ### 1. Install
22
-
23
- ```bash
24
- npm install openworkflow @openworkflow/backend-postgres @openworkflow/backend-sqlite
25
- ```
26
-
27
- You only need to install the backend package(s) for the database you plan to
28
- use.
29
-
30
- ### 2. Define a workflow
31
-
32
11
  ```ts
33
- import { BackendPostgres } from "@openworkflow/backend-postgres";
34
- import { BackendSqlite } from "@openworkflow/backend-sqlite";
35
- import { OpenWorkflow } from "openworkflow";
12
+ import { defineWorkflow } from "openworkflow";
36
13
 
37
- // use Postgres if DATABASE_URL is set, otherwise use SQLite
38
- const backend = process.env["DATABASE_URL"]
39
- ? await BackendPostgres.connect(process.env["DATABASE_URL"])
40
- : BackendSqlite.connect(); // optionally provide SQLite file path
41
-
42
- const ow = new OpenWorkflow({ backend });
43
-
44
- const sendWelcomeEmail = ow.defineWorkflow(
14
+ export const sendWelcomeEmail = defineWorkflow(
45
15
  { name: "send-welcome-email" },
46
16
  async ({ input, step }) => {
47
17
  const user = await step.run({ name: "fetch-user" }, async () => {
@@ -67,334 +37,62 @@ const sendWelcomeEmail = ow.defineWorkflow(
67
37
  );
68
38
  ```
69
39
 
70
- ### 3. Start a worker
71
-
72
- Workers are background processes that execute your workflows. Start one in a
73
- separate process or the same one as your app:
74
-
75
- ```ts
76
- const worker = ow.newWorker();
77
- await worker.start();
78
- ```
79
-
80
- ### 4. Run workflows from your app
81
-
82
- Trigger workflows from your web server, API, or any application code:
83
-
84
- ```ts
85
- // In your API route handler
86
- app.post("/users/:id/welcome", async (req, res) => {
87
- // Run the workflow async and do not wait for the result
88
- const runHandle = await sendWelcomeEmail.run({ userId: req.params.id });
89
- res.json({ runId: runHandle.workflowRun.id });
90
- });
91
- ```
92
-
93
- That's it. Your workflow is now durable, resumable, and fault-tolerant.
94
-
95
- ## Core Concepts
96
-
97
- ### Workflows
98
-
99
- Workflows are durable functions. They can contain multiple steps, make external
100
- API calls, query databases, and perform complex logic. If a workflow is
101
- interrupted (crash, deploy, server restart), it resumes from its last completed
102
- step.
103
-
104
- ```ts
105
- const workflow = ow.defineWorkflow(
106
- { name: "my-workflow" },
107
- async ({ input, step }) => {
108
- // Your workflow logic here
109
- return result;
110
- },
111
- );
112
- ```
113
-
114
- ### Steps
115
-
116
- Steps are the building blocks of workflows. Each step is executed exactly once
117
- and its result is memoized. Steps let you break workflows into checkpoints.
118
-
119
- ```ts
120
- const result = await step.run({ name: "step-name" }, async () => {
121
- // This function runs once. If the workflow restarts,
122
- // this returns the cached result instead of re-running.
123
- return await someAsyncWork();
124
- });
125
- ```
126
-
127
- **Why steps matter**: Imagine a workflow that charges a credit card, then sends
128
- an email. Without steps, if your server crashes after charging the card, the
129
- workflow would retry from the beginning and charge the customer twice. With
130
- steps, the charge is memoized. The retry skips it and goes straight to sending
131
- the email.
132
-
133
- ### Workers
134
-
135
- Workers are long-running processes that poll your database for pending workflows
136
- and execute them. You can run multiple workers for high availability and scale.
137
-
138
- ```ts
139
- const worker = ow.newWorker({ concurrency: 20 });
140
- await worker.start();
141
-
142
- // & to shut down...
143
- await worker.stop(); // waits for in-flight workflows to complete
144
- ```
145
-
146
- Workers are stateless. They can be started, stopped, and deployed independently.
147
- Your database is the source of truth.
148
-
149
- ### How it Works
150
-
151
- 1. **Your app starts a workflow**: A row is inserted into the `workflow_runs`
152
- table with status `pending`.
153
- 2. **A worker picks it up**: The worker polls the database, claims the workflow,
154
- and sets its status to `running`.
155
- 3. **The worker executes steps**: Each step is recorded in the `step_attempts`
156
- table. If a step succeeds, its result is cached.
157
- 4. **The workflow completes**: The worker updates the `workflow_run` status to
158
- `completed` or `failed`.
159
- 5. **If the worker crashes**: The workflow becomes visible to other workers via
160
- a heartbeat timeout. Another worker picks it up, loads the cached step
161
- results, and resumes from the next step.
162
-
163
- ## Advanced Patterns
164
-
165
- ### Parallel Steps
166
-
167
- Run multiple steps concurrently using `Promise.all`:
168
-
169
- ```ts
170
- const [user, subscription, settings] = await Promise.all([
171
- step.run({ name: "fetch-user" }, async () => {
172
- await db.users.findOne({ id: input.userId });
173
- }),
174
- step.run({ name: "fetch-subscription" }, async () => {
175
- await stripe.subscriptions.retrieve(input.subId);
176
- }),
177
- step.run({ name: "fetch-settings" }, async () => {
178
- await db.settings.findOne({ userId: input.userId });
179
- }),
180
- ]);
181
- ```
182
-
183
- Each step is still memoized individually. If the workflow crashes mid-execution,
184
- completed steps return instantly on resume.
185
-
186
- ### Automatic Retries
187
-
188
- Steps can retry automatically with exponential backoff:
189
-
190
- ```ts
191
- const data = await step.run({ name: "fetch-external-api" }, async () => {
192
- // If this throws, the step retries automatically
193
- return await externalAPI.getData();
194
- });
195
- ```
196
-
197
- Configure retry behavior at the workflow or step level (coming soon) or handle
198
- errors explicitly in your step functions.
199
-
200
- ### Sleeping (Pausing) Workflows
201
-
202
- You can pause a workflow until a future time and, because sleeping releases the
203
- worker slot, you can pause thousands of workflows without tying up compute:
204
-
205
- ```ts
206
- // Pause for 1 hour (durable, non-blocking)
207
- await step.sleep("wait-one-hour", "1h");
208
- ```
209
-
210
- The sleep step is memoized after it completes. If the workflow is replayed again
211
- (e.g. due to a later retry) the completed sleep is not re-applied.
212
-
213
- #### Duration Formats
214
-
215
- Durations accept a number followed by a unit:
216
-
217
- | Unit | Aliases | Examples |
218
- | ------------ | --------------------- | ---------------- |
219
- | milliseconds | `ms`, `msec`, `msecs` | `100ms`, `1.5ms` |
220
- | seconds | `s`, `sec`, `secs` | `5s`, `0.25s` |
221
- | minutes | `m`, `min`, `mins` | `2m`, `1.5m` |
222
- | hours | `h`, `hr`, `hrs` | `1h`, `0.25h` |
223
- | days | `d`, `day(s)` | `1d`, `0.5d` |
224
- | weeks | `w`, `week(s)` | `1w`, `2w` |
225
- | months | `mo`, `month(s)` | `1mo`, `2mo` |
226
- | years | `y`, `yr`, `yrs` | `1y`, `2yr` |
227
-
228
- See more examples of accepted duration formats and aliases in the
229
- [tests](https://github.com/openworkflowdev/openworkflow/blob/main/packages/openworkflow/core/duration.test.ts).
230
-
231
- ### Type Safety
232
-
233
- Workflows are fully typed. Define input and output types for compile-time
234
- safety:
235
-
236
- ```ts
237
- interface ProcessOrderInput {
238
- orderId: string;
239
- userId: string;
240
- }
241
-
242
- interface ProcessOrderOutput {
243
- paymentId: string;
244
- shipmentId: string;
245
- }
246
-
247
- const processOrder = ow.defineWorkflow<ProcessOrderInput, ProcessOrderOutput>(
248
- { name: "process-order" },
249
- async ({ input, step }) => {
250
- // input is typed as ProcessOrderInput
251
- // return type must match ProcessOrderOutput
252
- return { paymentId: "...", shipmentId: "..." };
253
- },
254
- );
255
- ```
256
-
257
- ### Waiting for Results
258
-
259
- You can wait for a workflow to complete and get its result:
260
-
261
- ```ts
262
- const run = await myWorkflow.run({ data: "..." });
263
-
264
- // Wait for the workflow to finish (polls the database)
265
- const result = await run.result();
266
- ```
267
-
268
- ### Canceling Workflows
269
-
270
- You can cancel a workflow that is pending, running, or sleeping to prevent a
271
- workflow from continuing on to the next step:
272
-
273
- ```ts
274
- const handle = await myWorkflow.run({ data: "..." });
275
-
276
- // Cancel the workflow
277
- await handle.cancel();
278
- ```
279
-
280
- ### Workflow Versioning
40
+ ## Quick Start
281
41
 
282
- When you need to change workflow logic, use versioning for backwards
283
- compatibility.
42
+ **Prerequisites:** Node.js & PostgreSQL (or SQLite)
284
43
 
285
- Define a workflow with an optional version:
44
+ ### Install
286
45
 
287
- ```ts
288
- const workflow = ow.defineWorkflow(
289
- { name: "my-workflow", version: "v2" },
290
- async ({ input, step, version }) => {
291
- if (version === "v2") {
292
- // v2 runs go here
293
- await step.run({ name: "new-step" }, async () => {
294
- // legacy logic
295
- });
296
- } else {
297
- // v1 runs go here
298
- await step.run({ name: "old-step" }, async () => {
299
- // ...
300
- });
301
- }
302
- },
303
- );
46
+ ```bash
47
+ npx @openworkflow/cli init
304
48
  ```
305
49
 
306
- ### Validating Workflow Inputs
307
-
308
- You can require `.run()` callers to provide specific inputs by supplying a
309
- `schema` when defining the workflow. The schema is evaluated before the run is
310
- enqueued, so invalid requests fail immediately.
311
-
312
- ```ts
313
- import { z } from "zod";
314
-
315
- const summarizeDoc = ow.defineWorkflow(
316
- {
317
- name: "summarize",
318
- schema: z.object({
319
- docUrl: z.string().url(),
320
- }),
321
- },
322
- async ({ input, step }) => {
323
- // `input` has type { docUrl: string }
324
- },
325
- );
326
-
327
- // Throws before enqueueing the workflow because the input isn't a URL
328
- await summarizeDoc.run({ docUrl: "not-a-url" });
329
- ```
50
+ The CLI will guide you through setup and generate everything you need to get
51
+ started.
330
52
 
331
- Any validator function works as long as it throws on invalid data (great for
332
- custom logic or lightweight checks). Libraries such as Zod, ArkType, Valibot,
333
- and Yup.
53
+ For more details, check out our [docs](https://openworkflow.dev/docs).
334
54
 
335
- ## Production Checklist
55
+ ## Features
336
56
 
337
- - **Database**: Use a production-ready Postgres instance
338
- - **Workers**: Run at lease one worker process
339
- - **Concurrency**: Start with `concurrency: 10` per worker and tune based on
340
- your workload
341
- - **Monitoring**: Log worker activity and set up alerts for failed workflows
342
- - **Graceful Shutdown**: Handle `SIGTERM` to ensure clean deploys:
343
- ```ts
344
- process.on("SIGTERM", async () => {
345
- await worker.stop();
346
- process.exit(0);
347
- });
348
- ```
349
- - **Namespaces** (optional): Use `namespaceId` in your backend configuration to
350
- isolate workflows per environment:
351
- ```ts
352
- const backend = await BackendPostgres.connect(postgresUrl, {
353
- namespaceId: "production",
354
- });
355
- ```
57
+ - **Durable** - Workflows survive crashes and deploys
58
+ - **Resumable** - Pick up exactly where you left off
59
+ - **Type-safe** - Full TypeScript support
60
+ - ✅ **Step memoization** - Never repeat completed work
61
+ - **Automatic retries** - Built-in exponential backoff
62
+ - **Long pauses** - Sleep for seconds or months
63
+ - ✅ **Parallel execution** - Run steps concurrently
64
+ - **No extra servers** - Uses your existing database
65
+ - ✅ **Dashboard included** - Monitor and debug workflows
66
+ - ✅ **Production ready** - PostgreSQL and SQLite support
356
67
 
357
- ## What's Next
68
+ ## Documentation
358
69
 
359
- - Read [ARCHITECTURE.md](./ARCHITECTURE.md) for a deep dive into how
360
- OpenWorkflow works
361
- - Check [examples/](./examples) for working examples
362
- - Star the repo and follow development on
363
- [GitHub](https://github.com/openworkflowdev/openworkflow)
70
+ - [Documentation](https://openworkflow.dev/docs)
71
+ - [Quick Start Guide](https://openworkflow.dev/docs/quickstart)
72
+ - [Core Concepts](https://openworkflow.dev/docs/core-concepts)
73
+ - [Advanced Patterns](https://openworkflow.dev/docs/advanced-patterns)
74
+ - [Production Checklist](https://openworkflow.dev/docs/production)
364
75
 
365
- ## Roadmap
76
+ ## Architecture
366
77
 
367
- **Live in current `npm` release:**
78
+ Read
79
+ [ARCHITECTURE.md](https://github.com/openworkflowdev/openworkflow/blob/main/ARCHITECTURE.md)
80
+ for a deep dive into how OpenWorkflow works under the hood.
368
81
 
369
- - ✅ PostgreSQL and SQLite backends
370
- - ✅ Worker with concurrency control
371
- - ✅ Step memoization & retries
372
- - ✅ Graceful shutdown
373
- - ✅ Parallel step execution
374
- - ✅ Sleeping (pausing) workflows
375
- - ✅ Workflow versioning
376
- - ✅ Workflow cancelation
82
+ ## Examples
377
83
 
378
- **Coming Soon:**
84
+ Check out
85
+ [examples/](https://github.com/openworkflowdev/openworkflow/tree/main/examples)
86
+ for working examples.
379
87
 
380
- > These releases don't yet include a dashboard UI or CLI. For now, you can
381
- > inspect workflow and step state directly in PostgreSQL or SQLite
382
- > (workflow_runs and step_runs tables). A CLI and dashboard are planned for an
383
- > upcoming release to make debugging and monitoring much easier.
88
+ ## Contributing
384
89
 
385
- - Improved local dev experience (coming in v0.5)
386
- - CLI (coming in v0.5)
387
- - Dashboard UI
388
- - Idempotency keys
389
- - Rollback / compensation functions
390
- - Configurable retry policies
391
- - Signals for external events
392
- - Native OpenTelemetry integration
393
- - Additional backends (Redis)
394
- - Additional languages (Go, Python)
90
+ We welcome contributions! Please read
91
+ [CONTRIBUTING.md](https://github.com/openworkflowdev/openworkflow/blob/main/CONTRIBUTING.md)
92
+ before submitting a pull request.
395
93
 
396
- ## Bugs & feature requests
94
+ ## Community
397
95
 
398
- Found a bug or have a feature request? Please open an issue on GitHub so we can
399
- track and prioritize it:
400
- https://github.com/openworkflowdev/openworkflow/issues/new
96
+ - [GitHub Issues](https://github.com/openworkflowdev/openworkflow/issues) -
97
+ Report bugs and request features
98
+ - [Roadmap](https://openworkflow.dev/docs/roadmap) - See what's coming next
@@ -0,0 +1,20 @@
1
+ import type { Backend } from "../backend.js";
2
+ /**
3
+ * Options for the Backend test suite.
4
+ */
5
+ export interface TestBackendOptions {
6
+ /**
7
+ * Creates a new isolated Backend instance.
8
+ */
9
+ setup: () => Promise<Backend>;
10
+ /**
11
+ * Cleans up a Backend instance.
12
+ */
13
+ teardown: (backend: Backend) => Promise<void>;
14
+ }
15
+ /**
16
+ * Runs the Backend test suite.
17
+ * @param options - Test suite options
18
+ */
19
+ export declare function testBackend(options: TestBackendOptions): void;
20
+ //# sourceMappingURL=backend.testsuite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.testsuite.d.ts","sourceRoot":"","sources":["../../backend-test/backend.testsuite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAM7C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B;;OAEG;IACH,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CA8sC7D"}