@tstdl/base 0.93.140 → 0.93.141

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 (98) hide show
  1. package/application/application.d.ts +1 -1
  2. package/application/application.js +1 -1
  3. package/application/providers.d.ts +20 -2
  4. package/application/providers.js +34 -7
  5. package/audit/module.d.ts +5 -0
  6. package/audit/module.js +9 -1
  7. package/authentication/server/module.d.ts +5 -0
  8. package/authentication/server/module.js +9 -1
  9. package/authentication/tests/authentication.api-controller.test.js +1 -1
  10. package/authentication/tests/authentication.api-request-token.provider.test.js +1 -1
  11. package/authentication/tests/authentication.client-service.test.js +1 -1
  12. package/circuit-breaker/postgres/module.d.ts +1 -0
  13. package/circuit-breaker/postgres/module.js +5 -1
  14. package/document-management/server/configure.js +5 -1
  15. package/document-management/server/module.d.ts +1 -1
  16. package/document-management/server/module.js +1 -1
  17. package/document-management/server/services/document-management-ancillary.service.js +1 -1
  18. package/document-management/tests/ai-config-hierarchy.test.js +0 -5
  19. package/document-management/tests/document-management-ai-overrides.test.js +0 -1
  20. package/document-management/tests/document-validation-ai-overrides.test.js +0 -1
  21. package/examples/document-management/main.d.ts +1 -0
  22. package/examples/document-management/main.js +14 -11
  23. package/key-value-store/postgres/module.d.ts +1 -0
  24. package/key-value-store/postgres/module.js +5 -1
  25. package/lock/postgres/module.d.ts +1 -0
  26. package/lock/postgres/module.js +5 -1
  27. package/mail/module.d.ts +5 -1
  28. package/mail/module.js +11 -6
  29. package/module/modules/web-server.module.js +2 -3
  30. package/notification/server/module.d.ts +1 -0
  31. package/notification/server/module.js +5 -1
  32. package/notification/tests/notification-flow.test.js +2 -2
  33. package/orm/decorators.d.ts +5 -1
  34. package/orm/decorators.js +1 -1
  35. package/orm/server/drizzle/schema-converter.js +17 -30
  36. package/orm/server/encryption.d.ts +0 -1
  37. package/orm/server/encryption.js +1 -4
  38. package/orm/server/index.d.ts +1 -6
  39. package/orm/server/index.js +1 -6
  40. package/orm/server/migration.d.ts +19 -0
  41. package/orm/server/migration.js +72 -0
  42. package/orm/server/repository.d.ts +1 -1
  43. package/orm/server/transaction.d.ts +5 -10
  44. package/orm/server/transaction.js +22 -26
  45. package/orm/server/transactional.js +3 -3
  46. package/orm/tests/database-migration.test.d.ts +1 -0
  47. package/orm/tests/database-migration.test.js +82 -0
  48. package/orm/tests/encryption.test.js +3 -4
  49. package/orm/utils.d.ts +17 -2
  50. package/orm/utils.js +49 -1
  51. package/package.json +4 -3
  52. package/rate-limit/postgres/module.d.ts +1 -0
  53. package/rate-limit/postgres/module.js +5 -1
  54. package/reflection/decorator-data.js +11 -12
  55. package/task-queue/README.md +2 -9
  56. package/task-queue/postgres/drizzle/{0000_simple_invisible_woman.sql → 0000_wakeful_sunspot.sql} +22 -14
  57. package/task-queue/postgres/drizzle/meta/0000_snapshot.json +160 -82
  58. package/task-queue/postgres/drizzle/meta/_journal.json +2 -2
  59. package/task-queue/postgres/module.d.ts +1 -0
  60. package/task-queue/postgres/module.js +5 -1
  61. package/task-queue/postgres/schemas.d.ts +9 -6
  62. package/task-queue/postgres/schemas.js +4 -3
  63. package/task-queue/postgres/task-queue.d.ts +2 -12
  64. package/task-queue/postgres/task-queue.js +431 -354
  65. package/task-queue/postgres/task.model.d.ts +12 -5
  66. package/task-queue/postgres/task.model.js +51 -25
  67. package/task-queue/task-context.d.ts +2 -2
  68. package/task-queue/task-context.js +7 -7
  69. package/task-queue/task-queue.d.ts +36 -19
  70. package/task-queue/task-queue.js +18 -10
  71. package/task-queue/tests/cascading-cancellations.test.d.ts +1 -0
  72. package/task-queue/tests/cascading-cancellations.test.js +38 -0
  73. package/task-queue/tests/complex.test.js +44 -228
  74. package/task-queue/tests/coverage-branch.test.d.ts +1 -0
  75. package/task-queue/tests/coverage-branch.test.js +407 -0
  76. package/task-queue/tests/coverage-enhancement.test.d.ts +1 -0
  77. package/task-queue/tests/coverage-enhancement.test.js +144 -0
  78. package/task-queue/tests/dag-dependencies.test.d.ts +1 -0
  79. package/task-queue/tests/dag-dependencies.test.js +41 -0
  80. package/task-queue/tests/dependencies.test.js +26 -26
  81. package/task-queue/tests/extensive-dependencies.test.js +64 -139
  82. package/task-queue/tests/fan-out-spawning.test.d.ts +1 -0
  83. package/task-queue/tests/fan-out-spawning.test.js +53 -0
  84. package/task-queue/tests/idempotent-replacement.test.d.ts +1 -0
  85. package/task-queue/tests/idempotent-replacement.test.js +61 -0
  86. package/task-queue/tests/missing-idempotent-tasks.test.d.ts +1 -0
  87. package/task-queue/tests/missing-idempotent-tasks.test.js +38 -0
  88. package/task-queue/tests/queue.test.js +33 -24
  89. package/task-queue/tests/worker.test.js +20 -5
  90. package/task-queue/tests/zombie-parent.test.d.ts +1 -0
  91. package/task-queue/tests/zombie-parent.test.js +45 -0
  92. package/task-queue/tests/zombie-recovery.test.d.ts +1 -0
  93. package/task-queue/tests/zombie-recovery.test.js +51 -0
  94. package/test5.js +5 -5
  95. package/testing/integration-setup.d.ts +4 -4
  96. package/testing/integration-setup.js +54 -29
  97. package/text/localization.service.js +2 -2
  98. package/utils/file-reader.js +1 -2
@@ -1,6 +1,7 @@
1
+ /** biome-ignore-all lint/nursery/noExcessiveClassesPerFile: <explanation> */
1
2
  import { BaseEntity, type Json, type Timestamp } from '../../orm/index.js';
2
3
  import type { ObjectLiteral, TypedOmit } from '../../types/types.js';
3
- import { DependencyJoinMode, type Task, TaskStatus } from '../task-queue.js';
4
+ import { type Task, TaskDependencyType, TaskStatus } from '../task-queue.js';
4
5
  export declare abstract class PostgresTaskBase<Data extends ObjectLiteral = ObjectLiteral, State extends ObjectLiteral = ObjectLiteral, Result extends ObjectLiteral = ObjectLiteral> extends BaseEntity implements TypedOmit<Task, 'parentId'> {
5
6
  namespace: string;
6
7
  type: string;
@@ -8,12 +9,10 @@ export declare abstract class PostgresTaskBase<Data extends ObjectLiteral = Obje
8
9
  idempotencyKey: string | null;
9
10
  traceId: string | null;
10
11
  tags: string[];
11
- completeAfterTags: string[];
12
- scheduleAfterTags: string[];
13
12
  failFast: boolean;
14
- dependencyJoinMode: DependencyJoinMode;
15
- dependencyTriggerStatuses: TaskStatus[];
16
13
  priority: number;
14
+ unresolvedScheduleDependencies: number;
15
+ unresolvedCompleteDependencies: number;
17
16
  token: string | null;
18
17
  creationTimestamp: Timestamp;
19
18
  priorityAgeTimestamp: Timestamp;
@@ -37,3 +36,11 @@ export declare class PostgresTaskArchive<Data extends ObjectLiteral = ObjectLite
37
36
  static readonly entityName = "TaskArchive";
38
37
  parentId: string | null;
39
38
  }
39
+ export declare class PostgresTaskDependency extends BaseEntity {
40
+ static readonly entityName = "TaskDependency";
41
+ namespace: string;
42
+ taskId: string;
43
+ dependencyTaskId: string;
44
+ type: TaskDependencyType;
45
+ requiredStatuses: TaskStatus[];
46
+ }
@@ -1,3 +1,4 @@
1
+ /** biome-ignore-all lint/nursery/noExcessiveClassesPerFile: <explanation> */
1
2
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
3
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
4
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -7,9 +8,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
8
  var __metadata = (this && this.__metadata) || function (k, v) {
8
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
10
  };
10
- import { BaseEntity, Index, JsonProperty, Reference, Table, TimestampProperty, Unique, UuidProperty } from '../../orm/index.js';
11
+ import { BaseEntity, ForeignKey, Index, JsonProperty, Table, TimestampProperty, Unique, UuidProperty } from '../../orm/index.js';
11
12
  import { Array as ArrayProperty, BooleanProperty, Enumeration, Integer, NumberProperty, StringProperty } from '../../schema/index.js';
12
- import { DependencyJoinMode, TaskStatus } from '../task-queue.js';
13
+ import { TaskDependencyType, TaskStatus } from '../task-queue.js';
13
14
  export class PostgresTaskBase extends BaseEntity {
14
15
  namespace;
15
16
  type;
@@ -17,12 +18,10 @@ export class PostgresTaskBase extends BaseEntity {
17
18
  idempotencyKey;
18
19
  traceId;
19
20
  tags;
20
- completeAfterTags;
21
- scheduleAfterTags;
22
21
  failFast;
23
- dependencyJoinMode;
24
- dependencyTriggerStatuses;
25
22
  priority;
23
+ unresolvedScheduleDependencies;
24
+ unresolvedCompleteDependencies;
26
25
  token;
27
26
  creationTimestamp;
28
27
  priorityAgeTimestamp;
@@ -62,30 +61,22 @@ __decorate([
62
61
  ArrayProperty(String),
63
62
  __metadata("design:type", Array)
64
63
  ], PostgresTaskBase.prototype, "tags", void 0);
65
- __decorate([
66
- ArrayProperty(String),
67
- __metadata("design:type", Array)
68
- ], PostgresTaskBase.prototype, "completeAfterTags", void 0);
69
- __decorate([
70
- ArrayProperty(String),
71
- __metadata("design:type", Array)
72
- ], PostgresTaskBase.prototype, "scheduleAfterTags", void 0);
73
64
  __decorate([
74
65
  BooleanProperty(),
75
66
  __metadata("design:type", Boolean)
76
67
  ], PostgresTaskBase.prototype, "failFast", void 0);
77
68
  __decorate([
78
- Enumeration(DependencyJoinMode),
79
- __metadata("design:type", String)
80
- ], PostgresTaskBase.prototype, "dependencyJoinMode", void 0);
69
+ Integer(),
70
+ __metadata("design:type", Number)
71
+ ], PostgresTaskBase.prototype, "priority", void 0);
81
72
  __decorate([
82
- Enumeration(TaskStatus, { array: true }),
83
- __metadata("design:type", Array)
84
- ], PostgresTaskBase.prototype, "dependencyTriggerStatuses", void 0);
73
+ Integer(),
74
+ __metadata("design:type", Number)
75
+ ], PostgresTaskBase.prototype, "unresolvedScheduleDependencies", void 0);
85
76
  __decorate([
86
77
  Integer(),
87
78
  __metadata("design:type", Number)
88
- ], PostgresTaskBase.prototype, "priority", void 0);
79
+ ], PostgresTaskBase.prototype, "unresolvedCompleteDependencies", void 0);
89
80
  __decorate([
90
81
  UuidProperty({ nullable: true }),
91
82
  __metadata("design:type", Object)
@@ -147,20 +138,19 @@ let PostgresTask = class PostgresTask extends PostgresTaskBase {
147
138
  parentId;
148
139
  };
149
140
  __decorate([
150
- Reference(() => PostgresTask),
151
141
  UuidProperty({ nullable: true }),
152
142
  __metadata("design:type", Object)
153
143
  ], PostgresTask.prototype, "parentId", void 0);
154
144
  PostgresTask = __decorate([
155
145
  Table('task', { schema: 'task_queue' }),
156
146
  Unique(['namespace', 'idempotencyKey']),
147
+ Unique(['namespace', 'id']),
157
148
  Index(['namespace', 'status', 'scheduleTimestamp', 'priority']),
158
149
  Index(['tags'], { using: 'gin' }),
159
- Index(['completeAfterTags'], { using: 'gin' }),
160
- Index(['scheduleAfterTags'], { using: 'gin' }),
161
150
  Index(['status', 'completeTimestamp']),
162
151
  Index(['status', 'visibilityDeadline']),
163
- Index(['parentId'])
152
+ Index(['parentId']),
153
+ ForeignKey(() => PostgresTask, ['namespace', 'parentId'], ['namespace', 'id'])
164
154
  ], PostgresTask);
165
155
  export { PostgresTask };
166
156
  let PostgresTaskArchive = class PostgresTaskArchive extends PostgresTaskBase {
@@ -176,3 +166,39 @@ PostgresTaskArchive = __decorate([
176
166
  Index(['namespace', 'completeTimestamp'])
177
167
  ], PostgresTaskArchive);
178
168
  export { PostgresTaskArchive };
169
+ let PostgresTaskDependency = class PostgresTaskDependency extends BaseEntity {
170
+ static entityName = 'TaskDependency';
171
+ namespace;
172
+ taskId;
173
+ dependencyTaskId;
174
+ type;
175
+ requiredStatuses;
176
+ };
177
+ __decorate([
178
+ StringProperty(),
179
+ __metadata("design:type", String)
180
+ ], PostgresTaskDependency.prototype, "namespace", void 0);
181
+ __decorate([
182
+ UuidProperty(),
183
+ __metadata("design:type", String)
184
+ ], PostgresTaskDependency.prototype, "taskId", void 0);
185
+ __decorate([
186
+ UuidProperty(),
187
+ __metadata("design:type", String)
188
+ ], PostgresTaskDependency.prototype, "dependencyTaskId", void 0);
189
+ __decorate([
190
+ Enumeration(TaskDependencyType),
191
+ __metadata("design:type", String)
192
+ ], PostgresTaskDependency.prototype, "type", void 0);
193
+ __decorate([
194
+ Enumeration(TaskStatus, { array: true }),
195
+ __metadata("design:type", Array)
196
+ ], PostgresTaskDependency.prototype, "requiredStatuses", void 0);
197
+ PostgresTaskDependency = __decorate([
198
+ Table('task_dependency', { schema: 'task_queue' }),
199
+ Unique(['namespace', 'taskId', 'dependencyTaskId', 'type']),
200
+ Index(['namespace', 'dependencyTaskId', 'type']),
201
+ ForeignKey(() => PostgresTask, ['namespace', 'taskId'], ['namespace', 'id'], { onDelete: 'cascade' }),
202
+ ForeignKey(() => PostgresTask, ['namespace', 'dependencyTaskId'], ['namespace', 'id'], { onDelete: 'cascade' })
203
+ ], PostgresTaskDependency);
204
+ export { PostgresTaskDependency };
@@ -10,8 +10,8 @@ export declare class TaskContext<Definitions extends TaskDefinitionMap, Type ext
10
10
  get type(): Type;
11
11
  get parentId(): string | null;
12
12
  get tags(): string[];
13
- get completeAfterTags(): string[];
14
- get scheduleAfterTags(): string[];
13
+ get unresolvedScheduleDependencies(): number;
14
+ get unresolvedCompleteDependencies(): number;
15
15
  get data(): TaskData<Definitions, Type>;
16
16
  get state(): TaskState<Definitions, Type> | null;
17
17
  get attempt(): number;
@@ -24,11 +24,11 @@ export class TaskContext {
24
24
  get tags() {
25
25
  return this.#task.tags;
26
26
  }
27
- get completeAfterTags() {
28
- return this.#task.completeAfterTags;
27
+ get unresolvedScheduleDependencies() {
28
+ return this.#task.unresolvedScheduleDependencies;
29
29
  }
30
- get scheduleAfterTags() {
31
- return this.#task.scheduleAfterTags;
30
+ get unresolvedCompleteDependencies() {
31
+ return this.#task.unresolvedCompleteDependencies;
32
32
  }
33
33
  get data() {
34
34
  return this.#task.data;
@@ -70,16 +70,16 @@ export class TaskContext {
70
70
  const data = isForOtherQueue ? dataOrOptionsOrNothing : typeOrData;
71
71
  const options = (isForOtherQueue ? optionsOrNothing : dataOrOptionsOrNothing);
72
72
  if (isForOtherQueue) {
73
- return await queueOrType.enqueue(type, data, { ...options, parentId: this.#task.id });
73
+ return await queueOrType.enqueue(type, data, options);
74
74
  }
75
75
  return await this.#queue.enqueue(type, data, { ...options, parentId: this.#task.id });
76
76
  }
77
77
  async spawnMany(queueOrItems, itemsOrNothing) {
78
78
  const isForOtherQueue = isInstanceOf(queueOrItems, TaskQueue);
79
- const items = (isForOtherQueue ? itemsOrNothing : queueOrItems).map((item) => ({ ...item, parentId: this.#task.id }));
80
79
  if (isForOtherQueue) {
81
- return await queueOrItems.enqueueMany(items, { returnTasks: true });
80
+ return await queueOrItems.enqueueMany(itemsOrNothing, { returnTasks: true });
82
81
  }
82
+ const items = queueOrItems.map((item) => ({ ...item, parentId: this.#task.id }));
83
83
  return await this.#queue.enqueueMany(items, { returnTasks: true });
84
84
  }
85
85
  async reschedule(timestampOrDelay) {
@@ -18,36 +18,44 @@ export declare class TaskProcessResult<Result = unknown> {
18
18
  }
19
19
  export declare const TaskStatus: {
20
20
  /**
21
- * The task is waiting to be processed.
21
+ * The task is ready to be processed and is waiting for a worker.
22
22
  */
23
23
  readonly Pending: "pending";
24
24
  /**
25
- * The task is currently being processed.
25
+ * The task is currently being processed by a worker.
26
26
  */
27
27
  readonly Running: "running";
28
28
  /**
29
- * The task has been completed successfully.
29
+ * The task has been completed successfully and all its lifecycle requirements met.
30
30
  */
31
31
  readonly Completed: "completed";
32
32
  /**
33
- * The task has been cancelled and will not be processed.
33
+ * The task has been cancelled and will not be processed further.
34
34
  */
35
35
  readonly Cancelled: "cancelled";
36
36
  /**
37
- * The task is scheduled to be processed in the future when all children have completed.
37
+ * The task has failed and will not be retried.
38
+ */
39
+ readonly Dead: "dead";
40
+ /**
41
+ * The task is waiting for its pre-execution (schedule) dependencies to be met.
38
42
  */
39
43
  readonly Waiting: "waiting";
40
44
  /**
41
- * The task has failed and will not be retried.
45
+ * The task has finished execution but is waiting for its completion dependencies (children) to finish.
42
46
  */
43
- readonly Dead: "dead";
47
+ readonly WaitingChildren: "waiting-children";
48
+ /**
49
+ * The task has been manually paused and will not be dequeued until resumed.
50
+ */
51
+ readonly Paused: "paused";
44
52
  };
45
53
  export type TaskStatus = EnumType<typeof TaskStatus>;
46
- export declare const DependencyJoinMode: {
47
- readonly And: "and";
48
- readonly Or: "or";
54
+ export declare const TaskDependencyType: {
55
+ readonly Schedule: "schedule";
56
+ readonly Complete: "complete";
49
57
  };
50
- export type DependencyJoinMode = EnumType<typeof DependencyJoinMode>;
58
+ export type TaskDependencyType = EnumType<typeof TaskDependencyType>;
51
59
  export type Task<Definitions extends TaskDefinitionMap = Record<string, {
52
60
  data: unknown;
53
61
  state: unknown;
@@ -67,11 +75,9 @@ export type Task<Definitions extends TaskDefinitionMap = Record<string, {
67
75
  idempotencyKey: string | null;
68
76
  traceId: string | null;
69
77
  tags: string[];
70
- completeAfterTags: string[];
71
- scheduleAfterTags: string[];
78
+ unresolvedScheduleDependencies: number;
79
+ unresolvedCompleteDependencies: number;
72
80
  failFast: boolean;
73
- dependencyJoinMode: DependencyJoinMode;
74
- dependencyTriggerStatuses: TaskStatus[];
75
81
  data: TaskData<Definitions, Type>;
76
82
  parentId: string | null;
77
83
  tries: number;
@@ -108,11 +114,16 @@ export type EnqueueOptions = {
108
114
  idempotencyKey?: string;
109
115
  replace?: boolean;
110
116
  tags?: string[];
111
- completeAfterTags?: string[];
112
- scheduleAfterTags?: string[];
117
+ scheduleAfter?: (string | {
118
+ id: string;
119
+ requiredStatuses?: TaskStatus[];
120
+ })[];
121
+ completeAfter?: (string | {
122
+ id: string;
123
+ requiredStatuses?: TaskStatus[];
124
+ })[];
113
125
  failFast?: boolean;
114
- dependencyJoinMode?: DependencyJoinMode;
115
- dependencyTriggerStatuses?: TaskStatus[];
126
+ waitForCompletion?: boolean;
116
127
  scheduleTimestamp?: number;
117
128
  timeToLive?: number;
118
129
  transaction?: Transaction;
@@ -197,6 +208,12 @@ export declare abstract class TaskQueue<Definitions extends TaskDefinitionMap =
197
208
  abstract readonly maxTries: number;
198
209
  batch(): TaskQueueEnqueueBatch<Definitions>;
199
210
  abstract enqueue<Type extends TaskTypes<Definitions>>(type: Type, data: TaskData<Definitions, Type>, options?: EnqueueOneOptions): Promise<TaskOfType<Definitions, Type>>;
211
+ /**
212
+ * Enqueues multiple tasks.
213
+ * @param items The items to enqueue.
214
+ * @param options Enqueue options. If `returnTasks` is true, returns the enqueued tasks.
215
+ * **NOTE:** The order of returned tasks is NOT guaranteed to match the order of input items.
216
+ */
200
217
  abstract enqueueMany<Type extends TaskTypes<Definitions>>(items: EnqueueManyItem<Definitions, Type>[], options?: EnqueueManyOptions & {
201
218
  returnTasks?: false;
202
219
  }): Promise<void>;
@@ -81,33 +81,41 @@ export class TaskProcessResult {
81
81
  }
82
82
  export const TaskStatus = defineEnum('TaskStatus', {
83
83
  /**
84
- * The task is waiting to be processed.
84
+ * The task is ready to be processed and is waiting for a worker.
85
85
  */
86
86
  Pending: 'pending',
87
87
  /**
88
- * The task is currently being processed.
88
+ * The task is currently being processed by a worker.
89
89
  */
90
90
  Running: 'running',
91
91
  /**
92
- * The task has been completed successfully.
92
+ * The task has been completed successfully and all its lifecycle requirements met.
93
93
  */
94
94
  Completed: 'completed',
95
95
  /**
96
- * The task has been cancelled and will not be processed.
96
+ * The task has been cancelled and will not be processed further.
97
97
  */
98
98
  Cancelled: 'cancelled',
99
99
  /**
100
- * The task is scheduled to be processed in the future when all children have completed.
100
+ * The task has failed and will not be retried.
101
+ */
102
+ Dead: 'dead',
103
+ /**
104
+ * The task is waiting for its pre-execution (schedule) dependencies to be met.
101
105
  */
102
106
  Waiting: 'waiting',
103
107
  /**
104
- * The task has failed and will not be retried.
108
+ * The task has finished execution but is waiting for its completion dependencies (children) to finish.
105
109
  */
106
- Dead: 'dead',
110
+ WaitingChildren: 'waiting-children',
111
+ /**
112
+ * The task has been manually paused and will not be dequeued until resumed.
113
+ */
114
+ Paused: 'paused',
107
115
  });
108
- export const DependencyJoinMode = defineEnum('DependencyJoinMode', {
109
- And: 'and',
110
- Or: 'or',
116
+ export const TaskDependencyType = defineEnum('TaskDependencyType', {
117
+ Schedule: 'schedule',
118
+ Complete: 'complete',
111
119
  });
112
120
  export const defaultTaskPriority = 1000;
113
121
  export const defaultQueueConfig = {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
2
+ import { TaskQueueProvider, TaskStatus } from '../../task-queue/index.js';
3
+ import { setupIntegrationTest } from '../../testing/index.js';
4
+ describe('Cascading Cancellations', () => {
5
+ let injector;
6
+ let queue;
7
+ beforeAll(async () => {
8
+ ({ injector } = await setupIntegrationTest({ modules: { taskQueue: true } }));
9
+ });
10
+ beforeEach(() => {
11
+ const queueProvider = injector.resolve(TaskQueueProvider);
12
+ const queueName = `cancellation-queue-${Date.now()}-${Math.random()}`;
13
+ queue = queueProvider.get(queueName, {
14
+ visibilityTimeout: 1000,
15
+ });
16
+ });
17
+ afterEach(async () => {
18
+ await queue.clear();
19
+ });
20
+ afterAll(async () => {
21
+ await injector?.dispose();
22
+ });
23
+ it('should recursively cancel children in ownership tree', async () => {
24
+ const root = await queue.enqueue('root', {});
25
+ const child1 = await queue.enqueue('child1', {}, { parentId: root.id });
26
+ const child2 = await queue.enqueue('child2', {}, { parentId: root.id });
27
+ const grandchild = await queue.enqueue('grandchild', {}, { parentId: child1.id });
28
+ await queue.cancel(root.id);
29
+ const uRoot = await queue.getTask(root.id);
30
+ const uChild1 = await queue.getTask(child1.id);
31
+ const uChild2 = await queue.getTask(child2.id);
32
+ const uGrandchild = await queue.getTask(grandchild.id);
33
+ expect(uRoot?.status).toBe(TaskStatus.Cancelled);
34
+ expect(uChild1?.status).toBe(TaskStatus.Cancelled);
35
+ expect(uChild2?.status).toBe(TaskStatus.Cancelled);
36
+ expect(uGrandchild?.status).toBe(TaskStatus.Cancelled);
37
+ });
38
+ });