@sonamu-kit/tasks 0.1.3 → 0.3.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 (215) hide show
  1. package/.oxlintrc.json +3 -0
  2. package/AGENTS.md +21 -0
  3. package/dist/backend.d.ts +126 -103
  4. package/dist/backend.d.ts.map +1 -1
  5. package/dist/backend.js +4 -1
  6. package/dist/backend.js.map +1 -1
  7. package/dist/client.d.ts +145 -132
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +220 -212
  10. package/dist/client.js.map +1 -1
  11. package/dist/config.d.ts +15 -8
  12. package/dist/config.d.ts.map +1 -1
  13. package/dist/config.js +22 -17
  14. package/dist/config.js.map +1 -1
  15. package/dist/core/duration.d.ts +5 -4
  16. package/dist/core/duration.d.ts.map +1 -1
  17. package/dist/core/duration.js +54 -59
  18. package/dist/core/duration.js.map +1 -1
  19. package/dist/core/error.d.ts +10 -7
  20. package/dist/core/error.d.ts.map +1 -1
  21. package/dist/core/error.js +21 -21
  22. package/dist/core/error.js.map +1 -1
  23. package/dist/core/json.d.ts +8 -3
  24. package/dist/core/json.d.ts.map +1 -1
  25. package/dist/core/result.d.ts +10 -14
  26. package/dist/core/result.d.ts.map +1 -1
  27. package/dist/core/result.js +21 -16
  28. package/dist/core/result.js.map +1 -1
  29. package/dist/core/retry.d.ts +42 -20
  30. package/dist/core/retry.d.ts.map +1 -1
  31. package/dist/core/retry.js +49 -20
  32. package/dist/core/retry.js.map +1 -1
  33. package/dist/core/schema.d.ts +57 -53
  34. package/dist/core/schema.d.ts.map +1 -1
  35. package/dist/core/step.d.ts +28 -78
  36. package/dist/core/step.d.ts.map +1 -1
  37. package/dist/core/step.js +53 -63
  38. package/dist/core/step.js.map +1 -1
  39. package/dist/core/workflow.d.ts +33 -61
  40. package/dist/core/workflow.d.ts.map +1 -1
  41. package/dist/core/workflow.js +31 -41
  42. package/dist/core/workflow.js.map +1 -1
  43. package/dist/database/backend.d.ts +53 -46
  44. package/dist/database/backend.d.ts.map +1 -1
  45. package/dist/database/backend.js +544 -545
  46. package/dist/database/backend.js.map +1 -1
  47. package/dist/database/base.js +48 -25
  48. package/dist/database/base.js.map +1 -1
  49. package/dist/database/migrations/20251212000000_0_init.d.ts +10 -0
  50. package/dist/database/migrations/20251212000000_0_init.d.ts.map +1 -0
  51. package/dist/database/migrations/20251212000000_0_init.js +8 -4
  52. package/dist/database/migrations/20251212000000_0_init.js.map +1 -1
  53. package/dist/database/migrations/20251212000000_1_tables.d.ts +10 -0
  54. package/dist/database/migrations/20251212000000_1_tables.d.ts.map +1 -0
  55. package/dist/database/migrations/20251212000000_1_tables.js +81 -83
  56. package/dist/database/migrations/20251212000000_1_tables.js.map +1 -1
  57. package/dist/database/migrations/20251212000000_2_fk.d.ts +10 -0
  58. package/dist/database/migrations/20251212000000_2_fk.d.ts.map +1 -0
  59. package/dist/database/migrations/20251212000000_2_fk.js +20 -43
  60. package/dist/database/migrations/20251212000000_2_fk.js.map +1 -1
  61. package/dist/database/migrations/20251212000000_3_indexes.d.ts +10 -0
  62. package/dist/database/migrations/20251212000000_3_indexes.d.ts.map +1 -0
  63. package/dist/database/migrations/20251212000000_3_indexes.js +88 -102
  64. package/dist/database/migrations/20251212000000_3_indexes.js.map +1 -1
  65. package/dist/database/pubsub.d.ts +7 -16
  66. package/dist/database/pubsub.d.ts.map +1 -1
  67. package/dist/database/pubsub.js +75 -73
  68. package/dist/database/pubsub.js.map +1 -1
  69. package/dist/execution.d.ts +20 -57
  70. package/dist/execution.d.ts.map +1 -1
  71. package/dist/execution.js +175 -174
  72. package/dist/execution.js.map +1 -1
  73. package/dist/index.d.ts +5 -8
  74. package/dist/index.js +5 -5
  75. package/dist/internal.d.ts +12 -12
  76. package/dist/internal.js +4 -4
  77. package/dist/registry.d.ts +33 -27
  78. package/dist/registry.d.ts.map +1 -1
  79. package/dist/registry.js +58 -49
  80. package/dist/registry.js.map +1 -1
  81. package/dist/worker.d.ts +57 -50
  82. package/dist/worker.d.ts.map +1 -1
  83. package/dist/worker.js +194 -198
  84. package/dist/worker.js.map +1 -1
  85. package/dist/workflow.d.ts +26 -27
  86. package/dist/workflow.d.ts.map +1 -1
  87. package/dist/workflow.js +20 -15
  88. package/dist/workflow.js.map +1 -1
  89. package/nodemon.json +1 -1
  90. package/package.json +18 -20
  91. package/src/backend.ts +28 -8
  92. package/src/chaos.test.ts +3 -1
  93. package/src/client.test.ts +2 -0
  94. package/src/client.ts +32 -8
  95. package/src/config.test.ts +1 -0
  96. package/src/config.ts +3 -2
  97. package/src/core/duration.test.ts +2 -1
  98. package/src/core/duration.ts +1 -1
  99. package/src/core/error.test.ts +1 -0
  100. package/src/core/error.ts +1 -1
  101. package/src/core/result.test.ts +1 -0
  102. package/src/core/retry.test.ts +181 -11
  103. package/src/core/retry.ts +95 -19
  104. package/src/core/schema.ts +2 -2
  105. package/src/core/step.test.ts +2 -1
  106. package/src/core/step.ts +4 -3
  107. package/src/core/workflow.test.ts +2 -1
  108. package/src/core/workflow.ts +4 -3
  109. package/src/database/backend.test.ts +1 -0
  110. package/src/database/backend.testsuite.ts +162 -39
  111. package/src/database/backend.ts +271 -35
  112. package/src/database/base.test.ts +41 -0
  113. package/src/database/base.ts +51 -2
  114. package/src/database/migrations/20251212000000_0_init.ts +2 -1
  115. package/src/database/migrations/20251212000000_1_tables.ts +2 -1
  116. package/src/database/migrations/20251212000000_2_fk.ts +2 -1
  117. package/src/database/migrations/20251212000000_3_indexes.ts +2 -1
  118. package/src/database/pubsub.test.ts +6 -3
  119. package/src/database/pubsub.ts +55 -33
  120. package/src/execution.test.ts +117 -0
  121. package/src/execution.ts +65 -10
  122. package/src/internal.ts +21 -1
  123. package/src/practices/01-remote-workflow.ts +1 -0
  124. package/src/registry.test.ts +1 -0
  125. package/src/registry.ts +1 -1
  126. package/src/testing/connection.ts +3 -1
  127. package/src/worker.test.ts +2 -0
  128. package/src/worker.ts +31 -9
  129. package/src/workflow.test.ts +1 -0
  130. package/src/workflow.ts +5 -2
  131. package/templates/openworkflow.config.ts +2 -1
  132. package/tsdown.config.ts +31 -0
  133. package/.swcrc +0 -17
  134. package/dist/chaos.test.d.ts +0 -2
  135. package/dist/chaos.test.d.ts.map +0 -1
  136. package/dist/chaos.test.js +0 -92
  137. package/dist/chaos.test.js.map +0 -1
  138. package/dist/client.test.d.ts +0 -2
  139. package/dist/client.test.d.ts.map +0 -1
  140. package/dist/client.test.js +0 -340
  141. package/dist/client.test.js.map +0 -1
  142. package/dist/config.test.d.ts +0 -2
  143. package/dist/config.test.d.ts.map +0 -1
  144. package/dist/config.test.js +0 -24
  145. package/dist/config.test.js.map +0 -1
  146. package/dist/core/duration.test.d.ts +0 -2
  147. package/dist/core/duration.test.d.ts.map +0 -1
  148. package/dist/core/duration.test.js +0 -265
  149. package/dist/core/duration.test.js.map +0 -1
  150. package/dist/core/error.test.d.ts +0 -2
  151. package/dist/core/error.test.d.ts.map +0 -1
  152. package/dist/core/error.test.js +0 -63
  153. package/dist/core/error.test.js.map +0 -1
  154. package/dist/core/json.js +0 -3
  155. package/dist/core/json.js.map +0 -1
  156. package/dist/core/result.test.d.ts +0 -2
  157. package/dist/core/result.test.d.ts.map +0 -1
  158. package/dist/core/result.test.js +0 -19
  159. package/dist/core/result.test.js.map +0 -1
  160. package/dist/core/retry.test.d.ts +0 -2
  161. package/dist/core/retry.test.d.ts.map +0 -1
  162. package/dist/core/retry.test.js +0 -37
  163. package/dist/core/retry.test.js.map +0 -1
  164. package/dist/core/schema.js +0 -4
  165. package/dist/core/schema.js.map +0 -1
  166. package/dist/core/step.test.d.ts +0 -2
  167. package/dist/core/step.test.d.ts.map +0 -1
  168. package/dist/core/step.test.js +0 -356
  169. package/dist/core/step.test.js.map +0 -1
  170. package/dist/core/workflow.test.d.ts +0 -2
  171. package/dist/core/workflow.test.d.ts.map +0 -1
  172. package/dist/core/workflow.test.js +0 -172
  173. package/dist/core/workflow.test.js.map +0 -1
  174. package/dist/database/backend.test.d.ts +0 -2
  175. package/dist/database/backend.test.d.ts.map +0 -1
  176. package/dist/database/backend.test.js +0 -19
  177. package/dist/database/backend.test.js.map +0 -1
  178. package/dist/database/backend.testsuite.d.ts +0 -20
  179. package/dist/database/backend.testsuite.d.ts.map +0 -1
  180. package/dist/database/backend.testsuite.js +0 -1174
  181. package/dist/database/backend.testsuite.js.map +0 -1
  182. package/dist/database/base.d.ts +0 -12
  183. package/dist/database/base.d.ts.map +0 -1
  184. package/dist/database/pubsub.test.d.ts +0 -2
  185. package/dist/database/pubsub.test.d.ts.map +0 -1
  186. package/dist/database/pubsub.test.js +0 -86
  187. package/dist/database/pubsub.test.js.map +0 -1
  188. package/dist/execution.test.d.ts +0 -2
  189. package/dist/execution.test.d.ts.map +0 -1
  190. package/dist/execution.test.js +0 -558
  191. package/dist/execution.test.js.map +0 -1
  192. package/dist/index.d.ts.map +0 -1
  193. package/dist/index.js.map +0 -1
  194. package/dist/internal.d.ts.map +0 -1
  195. package/dist/internal.js.map +0 -1
  196. package/dist/practices/01-remote-workflow.d.ts +0 -2
  197. package/dist/practices/01-remote-workflow.d.ts.map +0 -1
  198. package/dist/practices/01-remote-workflow.js +0 -70
  199. package/dist/practices/01-remote-workflow.js.map +0 -1
  200. package/dist/registry.test.d.ts +0 -2
  201. package/dist/registry.test.d.ts.map +0 -1
  202. package/dist/registry.test.js +0 -95
  203. package/dist/registry.test.js.map +0 -1
  204. package/dist/testing/connection.d.ts +0 -7
  205. package/dist/testing/connection.d.ts.map +0 -1
  206. package/dist/testing/connection.js +0 -39
  207. package/dist/testing/connection.js.map +0 -1
  208. package/dist/worker.test.d.ts +0 -2
  209. package/dist/worker.test.d.ts.map +0 -1
  210. package/dist/worker.test.js +0 -1164
  211. package/dist/worker.test.js.map +0 -1
  212. package/dist/workflow.test.d.ts +0 -2
  213. package/dist/workflow.test.d.ts.map +0 -1
  214. package/dist/workflow.test.js +0 -73
  215. package/dist/workflow.test.js.map +0 -1
package/src/core/step.ts CHANGED
@@ -1,7 +1,7 @@
1
- import type { DurationString } from "./duration";
1
+ import { type DurationString } from "./duration";
2
2
  import { parseDuration } from "./duration";
3
- import type { JsonValue } from "./json";
4
- import type { Result } from "./result";
3
+ import { type JsonValue } from "./json";
4
+ import { type Result } from "./result";
5
5
  import { err, ok } from "./result";
6
6
 
7
7
  /**
@@ -14,6 +14,7 @@ export type StepKind = "function" | "sleep";
14
14
  */
15
15
  export type StepAttemptStatus =
16
16
  | "running"
17
+ | "paused"
17
18
  | "succeeded" // deprecated in favor of 'completed'
18
19
  | "completed"
19
20
  | "failed";
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, test } from "vitest";
2
- import type { StandardSchemaV1 } from "./schema";
2
+
3
+ import { type StandardSchemaV1 } from "./schema";
3
4
  import { DEFAULT_WORKFLOW_RESULT_CONFIG, isTerminalStatus, validateInput } from "./workflow";
4
5
 
5
6
  describe("validateInput", () => {
@@ -1,6 +1,6 @@
1
- import type { SerializedError } from "./error";
2
- import type { JsonValue } from "./json";
3
- import type { StandardSchemaV1 } from "./schema";
1
+ import { type SerializedError } from "./error";
2
+ import { type JsonValue } from "./json";
3
+ import { type StandardSchemaV1 } from "./schema";
4
4
 
5
5
  /**
6
6
  * Status of a workflow run through its lifecycle.
@@ -9,6 +9,7 @@ export type WorkflowRunStatus =
9
9
  | "pending"
10
10
  | "running"
11
11
  | "sleeping"
12
+ | "paused"
12
13
  | "succeeded" // deprecated in favor of 'completed'
13
14
  | "completed"
14
15
  | "failed"
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from "node:crypto";
2
+
2
3
  import { KNEX_GLOBAL_CONFIG } from "../testing/connection";
3
4
  import { BackendPostgres } from "./backend";
4
5
  import { testBackend } from "./backend.testsuite";
@@ -1,8 +1,11 @@
1
1
  import { randomUUID } from "node:crypto";
2
+
2
3
  import { afterAll, beforeAll, describe, expect, test } from "vitest";
3
- import type { Backend } from "..//backend";
4
- import type { StepAttempt } from "../core/step";
5
- import type { WorkflowRun } from "../core/workflow";
4
+
5
+ import { type Backend } from "..//backend";
6
+ import { type SerializableRetryPolicy } from "../core/retry";
7
+ import { type StepAttempt } from "../core/step";
8
+ import { type WorkflowRun } from "../core/workflow";
6
9
 
7
10
  /**
8
11
  * Options for the Backend test suite.
@@ -137,7 +140,7 @@ export function testBackend(options: TestBackendOptions): void {
137
140
  // p2
138
141
  const page2 = await backend.listWorkflowRuns({
139
142
  limit: 2,
140
- // biome-ignore lint/style/noNonNullAssertion: for test
143
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
141
144
  after: page1.pagination.next!,
142
145
  });
143
146
  expect(page2.data).toHaveLength(2);
@@ -149,7 +152,7 @@ export function testBackend(options: TestBackendOptions): void {
149
152
  // p3
150
153
  const page3 = await backend.listWorkflowRuns({
151
154
  limit: 2,
152
- // biome-ignore lint/style/noNonNullAssertion: for test
155
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
153
156
  after: page2.pagination.next!,
154
157
  });
155
158
  expect(page3.data).toHaveLength(1);
@@ -160,7 +163,7 @@ export function testBackend(options: TestBackendOptions): void {
160
163
  // p2 again
161
164
  const page2Back = await backend.listWorkflowRuns({
162
165
  limit: 2,
163
- // biome-ignore lint/style/noNonNullAssertion: for test
166
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
164
167
  before: page3.pagination.prev!,
165
168
  });
166
169
  expect(page2Back.data).toHaveLength(2);
@@ -202,7 +205,7 @@ export function testBackend(options: TestBackendOptions): void {
202
205
 
203
206
  const page2 = await backend.listWorkflowRuns({
204
207
  limit: 2,
205
- // biome-ignore lint/style/noNonNullAssertion: for test
208
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
206
209
  after: page1.pagination.next!,
207
210
  });
208
211
  expect(page2.data).toHaveLength(2);
@@ -212,7 +215,7 @@ export function testBackend(options: TestBackendOptions): void {
212
215
 
213
216
  const page3 = await backend.listWorkflowRuns({
214
217
  limit: 2,
215
- // biome-ignore lint/style/noNonNullAssertion: for test
218
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
216
219
  after: page2.pagination.next!,
217
220
  });
218
221
  expect(page3.data).toHaveLength(1);
@@ -221,7 +224,7 @@ export function testBackend(options: TestBackendOptions): void {
221
224
 
222
225
  const page2Back = await backend.listWorkflowRuns({
223
226
  limit: 2,
224
- // biome-ignore lint/style/noNonNullAssertion: for test
227
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
225
228
  before: page3.pagination.prev!,
226
229
  });
227
230
  expect(page2Back.data).toHaveLength(2);
@@ -532,6 +535,124 @@ export function testBackend(options: TestBackendOptions): void {
532
535
 
533
536
  await teardown(backend);
534
537
  });
538
+
539
+ test("marks workflow run as failed when maxAttempts is reached", async () => {
540
+ const backend = await setup();
541
+
542
+ // retryPolicy에 maxAttempts: 2를 지정하여 생성
543
+ const retryPolicy: SerializableRetryPolicy = {
544
+ maxAttempts: 2,
545
+ initialIntervalMs: 100,
546
+ };
547
+ await backend.createWorkflowRun({
548
+ workflowName: randomUUID(),
549
+ version: null,
550
+ idempotencyKey: null,
551
+ input: null,
552
+ config: {},
553
+ context: null,
554
+ availableAt: null,
555
+ deadlineAt: null,
556
+ retryPolicy,
557
+ });
558
+
559
+ // 첫 번째 시도 - 실패하면 pending으로 스케줄링
560
+ let workerId = randomUUID();
561
+ let claimed = await backend.claimWorkflowRun({
562
+ workerId,
563
+ leaseDurationMs: 100,
564
+ });
565
+ if (!claimed) throw new Error("Expected workflow run to be claimed");
566
+ expect(claimed.attempts).toBe(1);
567
+
568
+ const firstFailed = await backend.failWorkflowRun({
569
+ workflowRunId: claimed.id,
570
+ workerId,
571
+ error: { message: "first failure" },
572
+ });
573
+ expect(firstFailed.status).toBe("pending"); // 아직 maxAttempts(2) 미달
574
+
575
+ await sleep(150); // 100ms backoff 대기
576
+
577
+ // 두 번째 시도 - maxAttempts에 도달하면 failed로 종료
578
+ workerId = randomUUID();
579
+ claimed = await backend.claimWorkflowRun({
580
+ workerId,
581
+ leaseDurationMs: 100,
582
+ });
583
+ if (!claimed) throw new Error("Expected workflow run to be claimed");
584
+ expect(claimed.attempts).toBe(2);
585
+
586
+ const secondFailed = await backend.failWorkflowRun({
587
+ workflowRunId: claimed.id,
588
+ workerId,
589
+ error: { message: "second failure" },
590
+ });
591
+
592
+ // maxAttempts에 도달했으므로 failed로 종료
593
+ expect(secondFailed.status).toBe("failed");
594
+ expect(secondFailed.availableAt).toBeNull();
595
+ expect(secondFailed.finishedAt).not.toBeNull();
596
+
597
+ await teardown(backend);
598
+ });
599
+
600
+ test("marks workflow run as failed immediately when forceComplete is true", async () => {
601
+ const backend = await setup();
602
+
603
+ await createPendingWorkflowRun(backend);
604
+
605
+ const workerId = randomUUID();
606
+ const claimed = await backend.claimWorkflowRun({
607
+ workerId,
608
+ leaseDurationMs: 100,
609
+ });
610
+ if (!claimed) throw new Error("Expected workflow run to be claimed");
611
+
612
+ // forceComplete: true로 호출하면 재시도 없이 즉시 failed
613
+ const failed = await backend.failWorkflowRun({
614
+ workflowRunId: claimed.id,
615
+ workerId,
616
+ error: { message: "forced failure" },
617
+ forceComplete: true,
618
+ });
619
+
620
+ expect(failed.status).toBe("failed");
621
+ expect(failed.availableAt).toBeNull();
622
+ expect(failed.finishedAt).not.toBeNull();
623
+
624
+ await teardown(backend);
625
+ });
626
+
627
+ test("stores retryPolicy in config when creating workflow run", async () => {
628
+ const backend = await setup();
629
+
630
+ const retryPolicy: SerializableRetryPolicy = {
631
+ maxAttempts: 10,
632
+ initialIntervalMs: 500,
633
+ backoffCoefficient: 1.5,
634
+ maximumIntervalMs: 30000,
635
+ };
636
+
637
+ const created = await backend.createWorkflowRun({
638
+ workflowName: randomUUID(),
639
+ version: null,
640
+ idempotencyKey: null,
641
+ input: null,
642
+ config: { existingKey: "existingValue" },
643
+ context: null,
644
+ availableAt: null,
645
+ deadlineAt: null,
646
+ retryPolicy,
647
+ });
648
+
649
+ // config에 retryPolicy가 저장되어 있는지 확인
650
+ const config = created.config as Record<string, unknown>;
651
+ expect(config.existingKey).toBe("existingValue");
652
+ expect(config.retryPolicy).toEqual(retryPolicy);
653
+
654
+ await teardown(backend);
655
+ });
535
656
  });
536
657
 
537
658
  describe("createStepAttempt()", () => {
@@ -559,7 +680,7 @@ export function testBackend(options: TestBackendOptions): void {
559
680
 
560
681
  const created = await backend.createStepAttempt({
561
682
  workflowRunId: expected.workflowRunId,
562
- // biome-ignore lint/style/noNonNullAssertion: for test
683
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
563
684
  workerId: workflowRun.workerId!,
564
685
  stepName: expected.stepName,
565
686
  kind: expected.kind,
@@ -585,7 +706,7 @@ export function testBackend(options: TestBackendOptions): void {
585
706
 
586
707
  const created = await backend.createStepAttempt({
587
708
  workflowRunId: claimed.id,
588
- // biome-ignore lint/style/noNonNullAssertion: for test
709
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
589
710
  workerId: claimed.workerId!,
590
711
  stepName: randomUUID(),
591
712
  kind: "function",
@@ -614,7 +735,7 @@ export function testBackend(options: TestBackendOptions): void {
614
735
 
615
736
  const first = await backend.createStepAttempt({
616
737
  workflowRunId: claimed.id,
617
- // biome-ignore lint/style/noNonNullAssertion: for test
738
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
618
739
  workerId: claimed.workerId!,
619
740
  stepName: randomUUID(),
620
741
  kind: "function",
@@ -624,7 +745,7 @@ export function testBackend(options: TestBackendOptions): void {
624
745
  await backend.completeStepAttempt({
625
746
  workflowRunId: claimed.id,
626
747
  stepAttemptId: first.id,
627
- // biome-ignore lint/style/noNonNullAssertion: for test
748
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
628
749
  workerId: claimed.workerId!,
629
750
  output: { ok: true },
630
751
  });
@@ -633,7 +754,7 @@ export function testBackend(options: TestBackendOptions): void {
633
754
 
634
755
  const second = await backend.createStepAttempt({
635
756
  workflowRunId: claimed.id,
636
- // biome-ignore lint/style/noNonNullAssertion: for test
757
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
637
758
  workerId: claimed.workerId!,
638
759
  stepName: randomUUID(),
639
760
  kind: "function",
@@ -654,7 +775,7 @@ export function testBackend(options: TestBackendOptions): void {
654
775
  for (let i = 0; i < 5; i++) {
655
776
  await backend.createStepAttempt({
656
777
  workflowRunId: claimed.id,
657
- // biome-ignore lint/style/noNonNullAssertion: for test
778
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
658
779
  workerId: claimed.workerId!,
659
780
  stepName: `step-${String(i)}`,
660
781
  kind: "function",
@@ -680,7 +801,7 @@ export function testBackend(options: TestBackendOptions): void {
680
801
  const page2 = await backend.listStepAttempts({
681
802
  workflowRunId: claimed.id,
682
803
  limit: 2,
683
- // biome-ignore lint/style/noNonNullAssertion: for test
804
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
684
805
  after: page1.pagination.next!,
685
806
  });
686
807
  expect(page2.data).toHaveLength(2);
@@ -693,7 +814,7 @@ export function testBackend(options: TestBackendOptions): void {
693
814
  const page3 = await backend.listStepAttempts({
694
815
  workflowRunId: claimed.id,
695
816
  limit: 2,
696
- // biome-ignore lint/style/noNonNullAssertion: for test
817
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
697
818
  after: page2.pagination.next!,
698
819
  });
699
820
  expect(page3.data).toHaveLength(1);
@@ -705,7 +826,7 @@ export function testBackend(options: TestBackendOptions): void {
705
826
  const page2Back = await backend.listStepAttempts({
706
827
  workflowRunId: claimed.id,
707
828
  limit: 2,
708
- // biome-ignore lint/style/noNonNullAssertion: for test
829
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
709
830
  before: page3.pagination.prev!,
710
831
  });
711
832
  expect(page2Back.data).toHaveLength(2);
@@ -729,7 +850,7 @@ export function testBackend(options: TestBackendOptions): void {
729
850
  const claimed = await createClaimedWorkflowRun(backend);
730
851
  await backend.createStepAttempt({
731
852
  workflowRunId: claimed.id,
732
- // biome-ignore lint/style/noNonNullAssertion: for test
853
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
733
854
  workerId: claimed.workerId!,
734
855
  stepName: "step-1",
735
856
  kind: "function",
@@ -761,7 +882,7 @@ export function testBackend(options: TestBackendOptions): void {
761
882
 
762
883
  const created = await backend.createStepAttempt({
763
884
  workflowRunId: claimed.id,
764
- // biome-ignore lint/style/noNonNullAssertion: for test
885
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
765
886
  workerId: claimed.workerId!,
766
887
  stepName: randomUUID(),
767
888
  kind: "function",
@@ -773,15 +894,16 @@ export function testBackend(options: TestBackendOptions): void {
773
894
  const completed = await backend.completeStepAttempt({
774
895
  workflowRunId: claimed.id,
775
896
  stepAttemptId: created.id,
776
- // biome-ignore lint/style/noNonNullAssertion: for test
897
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
777
898
  workerId: claimed.workerId!,
778
899
  output,
779
900
  });
780
901
 
781
- expect(completed.status).toBe("completed");
782
- expect(completed.output).toEqual(output);
783
- expect(completed.error).toBeNull();
784
- expect(completed.finishedAt).not.toBeNull();
902
+ expect(completed).not.toBeNull();
903
+ expect(completed?.status).toBe("completed");
904
+ expect(completed?.output).toEqual(output);
905
+ expect(completed?.error).toBeNull();
906
+ expect(completed?.finishedAt).not.toBeNull();
785
907
 
786
908
  const fetched = await backend.getStepAttempt({
787
909
  stepAttemptId: created.id,
@@ -805,7 +927,7 @@ export function testBackend(options: TestBackendOptions): void {
805
927
 
806
928
  const stepAttempt = await backend.createStepAttempt({
807
929
  workflowRunId: claimed.id,
808
- // biome-ignore lint/style/noNonNullAssertion: for test
930
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
809
931
  workerId: claimed.workerId!,
810
932
  stepName: randomUUID(),
811
933
  kind: "function",
@@ -816,7 +938,7 @@ export function testBackend(options: TestBackendOptions): void {
816
938
  // complete the workflow so it's no longer running
817
939
  await backend.completeWorkflowRun({
818
940
  workflowRunId: claimed.id,
819
- // biome-ignore lint/style/noNonNullAssertion: for test
941
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
820
942
  workerId: claimed.workerId!,
821
943
  output: null,
822
944
  });
@@ -826,7 +948,7 @@ export function testBackend(options: TestBackendOptions): void {
826
948
  backend.completeStepAttempt({
827
949
  workflowRunId: claimed.id,
828
950
  stepAttemptId: stepAttempt.id,
829
- // biome-ignore lint/style/noNonNullAssertion: for test
951
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
830
952
  workerId: claimed.workerId!,
831
953
  output: { foo: "bar" },
832
954
  }),
@@ -843,7 +965,7 @@ export function testBackend(options: TestBackendOptions): void {
843
965
  backend.completeStepAttempt({
844
966
  workflowRunId: claimed.id,
845
967
  stepAttemptId: randomUUID(),
846
- // biome-ignore lint/style/noNonNullAssertion: for test
968
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
847
969
  workerId: claimed.workerId!,
848
970
  output: { foo: "bar" },
849
971
  }),
@@ -867,7 +989,7 @@ export function testBackend(options: TestBackendOptions): void {
867
989
 
868
990
  const created = await backend.createStepAttempt({
869
991
  workflowRunId: claimed.id,
870
- // biome-ignore lint/style/noNonNullAssertion: for test
992
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
871
993
  workerId: claimed.workerId!,
872
994
  stepName: randomUUID(),
873
995
  kind: "function",
@@ -879,15 +1001,16 @@ export function testBackend(options: TestBackendOptions): void {
879
1001
  const failed = await backend.failStepAttempt({
880
1002
  workflowRunId: claimed.id,
881
1003
  stepAttemptId: created.id,
882
- // biome-ignore lint/style/noNonNullAssertion: for test
1004
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
883
1005
  workerId: claimed.workerId!,
884
1006
  error,
885
1007
  });
886
1008
 
887
- expect(failed.status).toBe("failed");
888
- expect(failed.error).toEqual(error);
889
- expect(failed.output).toBeNull();
890
- expect(failed.finishedAt).not.toBeNull();
1009
+ expect(failed).not.toBeNull();
1010
+ expect(failed?.status).toBe("failed");
1011
+ expect(failed?.error).toEqual(error);
1012
+ expect(failed?.output).toBeNull();
1013
+ expect(failed?.finishedAt).not.toBeNull();
891
1014
 
892
1015
  const fetched = await backend.getStepAttempt({
893
1016
  stepAttemptId: created.id,
@@ -911,7 +1034,7 @@ export function testBackend(options: TestBackendOptions): void {
911
1034
 
912
1035
  const stepAttempt = await backend.createStepAttempt({
913
1036
  workflowRunId: claimed.id,
914
- // biome-ignore lint/style/noNonNullAssertion: for test
1037
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
915
1038
  workerId: claimed.workerId!,
916
1039
  stepName: randomUUID(),
917
1040
  kind: "function",
@@ -922,7 +1045,7 @@ export function testBackend(options: TestBackendOptions): void {
922
1045
  // complete the workflow so it's no longer running
923
1046
  await backend.completeWorkflowRun({
924
1047
  workflowRunId: claimed.id,
925
- // biome-ignore lint/style/noNonNullAssertion: for test
1048
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
926
1049
  workerId: claimed.workerId!,
927
1050
  output: null,
928
1051
  });
@@ -932,7 +1055,7 @@ export function testBackend(options: TestBackendOptions): void {
932
1055
  backend.failStepAttempt({
933
1056
  workflowRunId: claimed.id,
934
1057
  stepAttemptId: stepAttempt.id,
935
- // biome-ignore lint/style/noNonNullAssertion: for test
1058
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
936
1059
  workerId: claimed.workerId!,
937
1060
  error: { message: "nope" },
938
1061
  }),
@@ -949,7 +1072,7 @@ export function testBackend(options: TestBackendOptions): void {
949
1072
  backend.failStepAttempt({
950
1073
  workflowRunId: claimed.id,
951
1074
  stepAttemptId: randomUUID(),
952
- // biome-ignore lint/style/noNonNullAssertion: for test
1075
+ // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion -- for test
953
1076
  workerId: claimed.workerId!,
954
1077
  error: { message: "nope" },
955
1078
  }),