@critical-path/core 0.36.0 → 0.37.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 (214) hide show
  1. package/README.md +1 -1
  2. package/dist/domain/authorization.d.ts.map +1 -1
  3. package/dist/domain/authorization.js +10 -7
  4. package/dist/domain/authorization.js.map +1 -1
  5. package/dist/engine/index.d.ts +6 -0
  6. package/dist/engine/index.d.ts.map +1 -1
  7. package/dist/engine/index.js +28 -2
  8. package/dist/engine/index.js.map +1 -1
  9. package/dist/schemas/index.d.ts +42 -12
  10. package/dist/schemas/index.d.ts.map +1 -1
  11. package/dist/schemas/index.js +4 -1
  12. package/dist/schemas/index.js.map +1 -1
  13. package/dist/store/firebase.d.ts +2 -2
  14. package/dist/store/firebase.d.ts.map +1 -1
  15. package/dist/store/firebase.js +4 -2
  16. package/dist/store/firebase.js.map +1 -1
  17. package/dist/store/index.d.ts +7 -2
  18. package/dist/store/index.d.ts.map +1 -1
  19. package/dist/store/index.js +3 -2
  20. package/dist/store/index.js.map +1 -1
  21. package/dist/store/sqlite.d.ts +2 -2
  22. package/dist/store/sqlite.d.ts.map +1 -1
  23. package/dist/store/sqlite.js +5 -3
  24. package/dist/store/sqlite.js.map +1 -1
  25. package/dist/testing/conformance.d.ts.map +1 -1
  26. package/dist/testing/conformance.js +9 -0
  27. package/dist/testing/conformance.js.map +1 -1
  28. package/dist/types/index.d.ts +13 -2
  29. package/dist/types/index.d.ts.map +1 -1
  30. package/package.json +5 -1
  31. package/CHANGELOG.md +0 -593
  32. package/dist/deliverables.test.d.ts +0 -2
  33. package/dist/deliverables.test.d.ts.map +0 -1
  34. package/dist/deliverables.test.js +0 -232
  35. package/dist/deliverables.test.js.map +0 -1
  36. package/dist/domain/calendar.test.d.ts +0 -2
  37. package/dist/domain/calendar.test.d.ts.map +0 -1
  38. package/dist/domain/calendar.test.js +0 -181
  39. package/dist/domain/calendar.test.js.map +0 -1
  40. package/dist/domain/cpm.test.d.ts +0 -2
  41. package/dist/domain/cpm.test.d.ts.map +0 -1
  42. package/dist/domain/cpm.test.js +0 -166
  43. package/dist/domain/cpm.test.js.map +0 -1
  44. package/dist/domain/ddd.test.d.ts +0 -2
  45. package/dist/domain/ddd.test.d.ts.map +0 -1
  46. package/dist/domain/ddd.test.js +0 -349
  47. package/dist/domain/ddd.test.js.map +0 -1
  48. package/dist/domain/ladder.test.d.ts +0 -2
  49. package/dist/domain/ladder.test.d.ts.map +0 -1
  50. package/dist/domain/ladder.test.js +0 -213
  51. package/dist/domain/ladder.test.js.map +0 -1
  52. package/dist/domain/metrics.test.d.ts +0 -2
  53. package/dist/domain/metrics.test.d.ts.map +0 -1
  54. package/dist/domain/metrics.test.js +0 -252
  55. package/dist/domain/metrics.test.js.map +0 -1
  56. package/dist/domain/task-duration.test.d.ts +0 -2
  57. package/dist/domain/task-duration.test.d.ts.map +0 -1
  58. package/dist/domain/task-duration.test.js +0 -307
  59. package/dist/domain/task-duration.test.js.map +0 -1
  60. package/dist/domain/workload.test.d.ts +0 -2
  61. package/dist/domain/workload.test.d.ts.map +0 -1
  62. package/dist/domain/workload.test.js +0 -261
  63. package/dist/domain/workload.test.js.map +0 -1
  64. package/dist/engine/actor.test.d.ts +0 -2
  65. package/dist/engine/actor.test.d.ts.map +0 -1
  66. package/dist/engine/actor.test.js +0 -54
  67. package/dist/engine/actor.test.js.map +0 -1
  68. package/dist/engine/authorization.test.d.ts +0 -2
  69. package/dist/engine/authorization.test.d.ts.map +0 -1
  70. package/dist/engine/authorization.test.js +0 -154
  71. package/dist/engine/authorization.test.js.map +0 -1
  72. package/dist/engine/cascade.test.d.ts +0 -2
  73. package/dist/engine/cascade.test.d.ts.map +0 -1
  74. package/dist/engine/cascade.test.js +0 -99
  75. package/dist/engine/cascade.test.js.map +0 -1
  76. package/dist/engine/config.test.d.ts +0 -2
  77. package/dist/engine/config.test.d.ts.map +0 -1
  78. package/dist/engine/config.test.js +0 -46
  79. package/dist/engine/config.test.js.map +0 -1
  80. package/dist/engine/entity-events.test.d.ts +0 -2
  81. package/dist/engine/entity-events.test.d.ts.map +0 -1
  82. package/dist/engine/entity-events.test.js +0 -61
  83. package/dist/engine/entity-events.test.js.map +0 -1
  84. package/dist/index.test.d.ts +0 -2
  85. package/dist/index.test.d.ts.map +0 -1
  86. package/dist/index.test.js +0 -429
  87. package/dist/index.test.js.map +0 -1
  88. package/dist/plugins/plugins.test.d.ts +0 -2
  89. package/dist/plugins/plugins.test.d.ts.map +0 -1
  90. package/dist/plugins/plugins.test.js +0 -137
  91. package/dist/plugins/plugins.test.js.map +0 -1
  92. package/dist/schemas/schemas.test.d.ts +0 -2
  93. package/dist/schemas/schemas.test.d.ts.map +0 -1
  94. package/dist/schemas/schemas.test.js +0 -58
  95. package/dist/schemas/schemas.test.js.map +0 -1
  96. package/dist/status.test.d.ts +0 -2
  97. package/dist/status.test.d.ts.map +0 -1
  98. package/dist/status.test.js +0 -295
  99. package/dist/status.test.js.map +0 -1
  100. package/dist/storage/storage.test.d.ts +0 -2
  101. package/dist/storage/storage.test.d.ts.map +0 -1
  102. package/dist/storage/storage.test.js +0 -236
  103. package/dist/storage/storage.test.js.map +0 -1
  104. package/dist/storage/upload-limits.test.d.ts +0 -2
  105. package/dist/storage/upload-limits.test.d.ts.map +0 -1
  106. package/dist/storage/upload-limits.test.js +0 -31
  107. package/dist/storage/upload-limits.test.js.map +0 -1
  108. package/dist/store/conformance.test.d.ts +0 -2
  109. package/dist/store/conformance.test.d.ts.map +0 -1
  110. package/dist/store/conformance.test.js +0 -15
  111. package/dist/store/conformance.test.js.map +0 -1
  112. package/dist/store/firebase.test.d.ts +0 -2
  113. package/dist/store/firebase.test.d.ts.map +0 -1
  114. package/dist/store/firebase.test.js +0 -103
  115. package/dist/store/firebase.test.js.map +0 -1
  116. package/dist/store/query.test.d.ts +0 -2
  117. package/dist/store/query.test.d.ts.map +0 -1
  118. package/dist/store/query.test.js +0 -89
  119. package/dist/store/query.test.js.map +0 -1
  120. package/dist/store/sqlite.test.d.ts +0 -2
  121. package/dist/store/sqlite.test.d.ts.map +0 -1
  122. package/dist/store/sqlite.test.js +0 -177
  123. package/dist/store/sqlite.test.js.map +0 -1
  124. package/dist/task-state.test.d.ts +0 -2
  125. package/dist/task-state.test.d.ts.map +0 -1
  126. package/dist/task-state.test.js +0 -423
  127. package/dist/task-state.test.js.map +0 -1
  128. package/dist/use-case-validation.test.d.ts +0 -2
  129. package/dist/use-case-validation.test.d.ts.map +0 -1
  130. package/dist/use-case-validation.test.js +0 -281
  131. package/dist/use-case-validation.test.js.map +0 -1
  132. package/dist/utils/fractional-index.test.d.ts +0 -2
  133. package/dist/utils/fractional-index.test.d.ts.map +0 -1
  134. package/dist/utils/fractional-index.test.js +0 -182
  135. package/dist/utils/fractional-index.test.js.map +0 -1
  136. package/dist/utils/key.test.d.ts +0 -2
  137. package/dist/utils/key.test.d.ts.map +0 -1
  138. package/dist/utils/key.test.js +0 -65
  139. package/dist/utils/key.test.js.map +0 -1
  140. package/dist/utils/mentions.test.d.ts +0 -2
  141. package/dist/utils/mentions.test.d.ts.map +0 -1
  142. package/dist/utils/mentions.test.js +0 -114
  143. package/dist/utils/mentions.test.js.map +0 -1
  144. package/dist/webhooks/webhooks.test.d.ts +0 -2
  145. package/dist/webhooks/webhooks.test.d.ts.map +0 -1
  146. package/dist/webhooks/webhooks.test.js +0 -154
  147. package/dist/webhooks/webhooks.test.js.map +0 -1
  148. package/src/deliverables.test.ts +0 -284
  149. package/src/domain/authorization.ts +0 -82
  150. package/src/domain/calendar.test.ts +0 -216
  151. package/src/domain/calendar.ts +0 -502
  152. package/src/domain/cpm.test.ts +0 -189
  153. package/src/domain/cpm.ts +0 -258
  154. package/src/domain/custom-fields.ts +0 -172
  155. package/src/domain/ddd.test.ts +0 -442
  156. package/src/domain/entities.ts +0 -798
  157. package/src/domain/errors.ts +0 -38
  158. package/src/domain/events.ts +0 -369
  159. package/src/domain/graph.ts +0 -70
  160. package/src/domain/index.ts +0 -12
  161. package/src/domain/ladder.test.ts +0 -251
  162. package/src/domain/ladder.ts +0 -474
  163. package/src/domain/metrics.test.ts +0 -288
  164. package/src/domain/metrics.ts +0 -497
  165. package/src/domain/task-duration.test.ts +0 -354
  166. package/src/domain/workload.test.ts +0 -311
  167. package/src/domain/workload.ts +0 -457
  168. package/src/engine/actor.test.ts +0 -63
  169. package/src/engine/authorization.test.ts +0 -199
  170. package/src/engine/cascade.test.ts +0 -121
  171. package/src/engine/config.test.ts +0 -51
  172. package/src/engine/entity-events.test.ts +0 -67
  173. package/src/engine/index.ts +0 -2495
  174. package/src/index.test.ts +0 -514
  175. package/src/index.ts +0 -9
  176. package/src/plugins/index.ts +0 -103
  177. package/src/plugins/plugins.test.ts +0 -161
  178. package/src/schemas/index.ts +0 -402
  179. package/src/schemas/schemas.test.ts +0 -116
  180. package/src/status.test.ts +0 -354
  181. package/src/storage/file-storage.ts +0 -200
  182. package/src/storage/firebase-storage.ts +0 -209
  183. package/src/storage/index.ts +0 -3
  184. package/src/storage/s3.ts +0 -151
  185. package/src/storage/storage.test.ts +0 -274
  186. package/src/storage/upload-limits.test.ts +0 -41
  187. package/src/store/conformance.test.ts +0 -15
  188. package/src/store/firebase.test.ts +0 -131
  189. package/src/store/firebase.ts +0 -658
  190. package/src/store/index.ts +0 -623
  191. package/src/store/query.test.ts +0 -110
  192. package/src/store/query.ts +0 -113
  193. package/src/store/sqlite.test.ts +0 -218
  194. package/src/store/sqlite.ts +0 -1480
  195. package/src/task-state.test.ts +0 -506
  196. package/src/testing/conformance.ts +0 -319
  197. package/src/testing/index.ts +0 -1
  198. package/src/types/index.ts +0 -871
  199. package/src/use-case-validation.test.ts +0 -324
  200. package/src/utils/fractional-index.test.ts +0 -228
  201. package/src/utils/fractional-index.ts +0 -254
  202. package/src/utils/index.ts +0 -7
  203. package/src/utils/key.test.ts +0 -76
  204. package/src/utils/key.ts +0 -62
  205. package/src/utils/mentions.test.ts +0 -132
  206. package/src/utils/mentions.ts +0 -131
  207. package/src/utils/status.ts +0 -419
  208. package/src/utils/workflow.ts +0 -306
  209. package/src/webhooks/dispatcher.ts +0 -190
  210. package/src/webhooks/index.ts +0 -2
  211. package/src/webhooks/signature.ts +0 -57
  212. package/src/webhooks/webhooks.test.ts +0 -201
  213. package/tsconfig.json +0 -8
  214. package/tsconfig.tsbuildinfo +0 -1
@@ -1,38 +0,0 @@
1
- /**
2
- * Thrown when input fails a domain rule. Route handlers map it to HTTP 400.
3
- */
4
- export interface ValidationIssue {
5
- /** Dot-separated path to the invalid field, e.g. `todos.0.title`. Empty for the whole payload. */
6
- path: string;
7
- message: string;
8
- }
9
-
10
- export class ValidationError extends Error {
11
- public readonly issues?: ValidationIssue[];
12
-
13
- constructor(message: string, issues?: ValidationIssue[]) {
14
- super(message);
15
- this.name = 'ValidationError';
16
- this.issues = issues;
17
- }
18
- }
19
-
20
- /**
21
- * Thrown when a referenced entity does not exist. Route handlers map it to HTTP 404.
22
- */
23
- export class NotFoundError extends Error {
24
- constructor(message: string) {
25
- super(message);
26
- this.name = 'NotFoundError';
27
- }
28
- }
29
-
30
- /**
31
- * Thrown when the actor is not allowed to perform an action. Route handlers map it to HTTP 403.
32
- */
33
- export class ForbiddenError extends Error {
34
- constructor(message: string) {
35
- super(message);
36
- this.name = 'ForbiddenError';
37
- }
38
- }
@@ -1,369 +0,0 @@
1
- import type {
2
- Task,
3
- Project,
4
- Workflow,
5
- Iteration,
6
- Team,
7
- TaskContainer,
8
- TaskDependency,
9
- TimeEntry,
10
- Comment,
11
- CommentReaction,
12
- Attachment,
13
- Deliverable
14
- } from '../types/index.js';
15
-
16
- export interface DomainEvent<TPayload = Record<string, unknown>> {
17
- readonly id: string;
18
- readonly name: string;
19
- readonly aggregateId: string;
20
- readonly aggregateType: 'Task' | 'Project' | 'Workflow' | 'Iteration' | 'Team' | 'Container' | 'Dependency' | 'Comment' | 'Attachment' | 'Deliverable';
21
- readonly occurredAt: string;
22
- readonly payload: TPayload;
23
- }
24
-
25
- // Concrete Domain Events
26
- export interface TaskCreatedEvent extends DomainEvent<{ task: Task }> {
27
- readonly name: 'task.created';
28
- readonly aggregateType: 'Task';
29
- }
30
-
31
- export interface TaskUpdatedEvent extends DomainEvent<{
32
- task: Task;
33
- previous: Task;
34
- actorId?: string;
35
- actorName?: string;
36
- actor?: { userId: string; username?: string; actorType?: string };
37
- }> {
38
- readonly name: 'task.updated';
39
- readonly aggregateType: 'Task';
40
- }
41
-
42
- export interface TaskStatusChangedEvent extends DomainEvent<{
43
- task: Task;
44
- previousStatus: string;
45
- newStatus: string;
46
- actorId?: string;
47
- actorName?: string;
48
- actor?: { userId: string; username?: string; actorType?: string };
49
- }> {
50
- readonly name: 'task.status_changed';
51
- readonly aggregateType: 'Task';
52
- }
53
-
54
- export interface TaskBlockedEvent extends DomainEvent<{
55
- task: Task;
56
- reason?: string | null;
57
- blockedByTaskId?: string;
58
- actorId?: string;
59
- actorName?: string;
60
- actor?: { userId: string; username?: string; actorType?: string };
61
- }> {
62
- readonly name: 'task.blocked';
63
- readonly aggregateType: 'Task';
64
- }
65
-
66
- export interface TaskUnblockedEvent extends DomainEvent<{
67
- task: Task;
68
- upstreamTaskId?: string;
69
- actorId?: string;
70
- actorName?: string;
71
- actor?: { userId: string; username?: string; actorType?: string };
72
- }> {
73
- readonly name: 'task.unblocked';
74
- readonly aggregateType: 'Task';
75
- }
76
-
77
- export interface TaskDeletedEvent extends DomainEvent<{ taskId: string; projectId: string; title: string }> {
78
- readonly name: 'task.deleted';
79
- readonly aggregateType: 'Task';
80
- }
81
-
82
- export interface TimeLoggedEvent extends DomainEvent<{ timeEntry: TimeEntry; taskId: string }> {
83
- readonly name: 'time.logged';
84
- readonly aggregateType: 'Task';
85
- }
86
-
87
- export interface CommentAddedEvent extends DomainEvent<{ comment: Comment; taskId: string }> {
88
- readonly name: 'comment.created';
89
- readonly aggregateType: 'Comment';
90
- }
91
-
92
- export interface CommentUpdatedEvent extends DomainEvent<{ comment: Comment; previous: Comment }> {
93
- readonly name: 'comment.updated';
94
- readonly aggregateType: 'Comment';
95
- }
96
-
97
- export interface CommentDeletedEvent extends DomainEvent<{ commentId: string; taskId: string }> {
98
- readonly name: 'comment.deleted';
99
- readonly aggregateType: 'Comment';
100
- }
101
-
102
- export interface CommentReactionAddedEvent extends DomainEvent<{ commentId: string; reaction: CommentReaction; comment: Comment }> {
103
- readonly name: 'comment.reaction.added';
104
- readonly aggregateType: 'Comment';
105
- }
106
-
107
- export interface CommentReactionRemovedEvent extends DomainEvent<{ commentId: string; reaction: { emoji: string; userId: string }; comment: Comment }> {
108
- readonly name: 'comment.reaction.removed';
109
- readonly aggregateType: 'Comment';
110
- }
111
-
112
- export interface AttachmentCreatedEvent extends DomainEvent<{ attachment: Attachment }> {
113
- readonly name: 'attachment.created';
114
- readonly aggregateType: 'Attachment';
115
- }
116
-
117
- export interface AttachmentDeletedEvent extends DomainEvent<{ attachmentId: string; storageKey?: string; url: string; projectId?: string }> {
118
- readonly name: 'attachment.deleted';
119
- readonly aggregateType: 'Attachment';
120
- }
121
-
122
- export interface TaskDependencyAddedEvent extends DomainEvent<{ dependency: TaskDependency }> {
123
- readonly name: 'dependency.added';
124
- readonly aggregateType: 'Dependency';
125
- }
126
-
127
- export interface TaskDependencyRemovedEvent extends DomainEvent<{ dependency: TaskDependency }> {
128
- readonly name: 'dependency.removed';
129
- readonly aggregateType: 'Dependency';
130
- }
131
-
132
- export interface ProjectCreatedEvent extends DomainEvent<{ project: Project }> {
133
- readonly name: 'project.created';
134
- readonly aggregateType: 'Project';
135
- }
136
-
137
- export interface ProjectUpdatedEvent extends DomainEvent<{ project: Project; previous: Project }> {
138
- readonly name: 'project.updated';
139
- readonly aggregateType: 'Project';
140
- }
141
-
142
- export interface ProjectDeletedEvent extends DomainEvent<{ projectId: string; name: string; deletedTaskIds: string[]; tenantId?: string }> {
143
- readonly name: 'project.deleted';
144
- readonly aggregateType: 'Project';
145
- }
146
-
147
- export interface WorkflowCreatedEvent extends DomainEvent<{ workflow: Workflow }> {
148
- readonly name: 'workflow.created';
149
- readonly aggregateType: 'Workflow';
150
- }
151
-
152
- export interface WorkflowUpdatedEvent extends DomainEvent<{ workflow: Workflow; previous: Workflow }> {
153
- readonly name: 'workflow.updated';
154
- readonly aggregateType: 'Workflow';
155
- }
156
-
157
- export interface WorkflowDeletedEvent extends DomainEvent<{ workflowId: string; name: string; tenantId?: string }> {
158
- readonly name: 'workflow.deleted';
159
- readonly aggregateType: 'Workflow';
160
- }
161
-
162
- export interface IterationStartedEvent extends DomainEvent<{ iteration: Iteration }> {
163
- readonly name: 'iteration.started';
164
- readonly aggregateType: 'Iteration';
165
- }
166
-
167
- export interface IterationCompletedEvent extends DomainEvent<{ iteration: Iteration }> {
168
- readonly name: 'iteration.completed';
169
- readonly aggregateType: 'Iteration';
170
- }
171
-
172
- export interface TeamCreatedEvent extends DomainEvent<{ team: Team }> {
173
- readonly name: 'team.created';
174
- readonly aggregateType: 'Team';
175
- }
176
-
177
- export interface TeamUpdatedEvent extends DomainEvent<{ team: Team; previous: Team }> {
178
- readonly name: 'team.updated';
179
- readonly aggregateType: 'Team';
180
- }
181
-
182
- export interface TeamDeletedEvent extends DomainEvent<{ teamId: string; name: string; tenantId?: string }> {
183
- readonly name: 'team.deleted';
184
- readonly aggregateType: 'Team';
185
- }
186
-
187
- export interface ContainerUpdatedEvent extends DomainEvent<{ container: TaskContainer; previous: TaskContainer }> {
188
- readonly name: 'container.updated';
189
- readonly aggregateType: 'Container';
190
- }
191
-
192
- export interface ContainerDeletedEvent extends DomainEvent<{ containerId: string; projectId: string; name: string }> {
193
- readonly name: 'container.deleted';
194
- readonly aggregateType: 'Container';
195
- }
196
-
197
- export interface IterationCreatedEvent extends DomainEvent<{ iteration: Iteration }> {
198
- readonly name: 'iteration.created';
199
- readonly aggregateType: 'Iteration';
200
- }
201
-
202
- export interface IterationUpdatedEvent extends DomainEvent<{ iteration: Iteration; previous: Iteration }> {
203
- readonly name: 'iteration.updated';
204
- readonly aggregateType: 'Iteration';
205
- }
206
-
207
- export interface IterationDeletedEvent extends DomainEvent<{ iterationId: string; projectId: string; name: string }> {
208
- readonly name: 'iteration.deleted';
209
- readonly aggregateType: 'Iteration';
210
- }
211
-
212
- export interface ContainerCreatedEvent extends DomainEvent<{ container: TaskContainer }> {
213
- readonly name: 'container.created';
214
- readonly aggregateType: 'Container';
215
- }
216
-
217
- export interface DeliverableCreatedEvent extends DomainEvent<{ deliverable: Deliverable }> {
218
- readonly name: 'deliverable.created';
219
- readonly aggregateType: 'Deliverable';
220
- }
221
-
222
- export interface DeliverableUpdatedEvent extends DomainEvent<{ deliverable: Deliverable; previous: Deliverable }> {
223
- readonly name: 'deliverable.updated';
224
- readonly aggregateType: 'Deliverable';
225
- }
226
-
227
- export interface DeliverableStatusChangedEvent extends DomainEvent<{ deliverable: Deliverable; previousStatus: string; newStatus: string }> {
228
- readonly name: 'deliverable.status_changed';
229
- readonly aggregateType: 'Deliverable';
230
- }
231
-
232
- export interface DeliverableDeletedEvent extends DomainEvent<{ deliverableId: string; projectId: string }> {
233
- readonly name: 'deliverable.deleted';
234
- readonly aggregateType: 'Deliverable';
235
- }
236
-
237
- export type CriticalPathDomainEvent =
238
- | TaskCreatedEvent
239
- | TaskUpdatedEvent
240
- | TaskStatusChangedEvent
241
- | TaskBlockedEvent
242
- | TaskUnblockedEvent
243
- | TaskDeletedEvent
244
- | TimeLoggedEvent
245
- | CommentAddedEvent
246
- | CommentUpdatedEvent
247
- | CommentDeletedEvent
248
- | CommentReactionAddedEvent
249
- | CommentReactionRemovedEvent
250
- | AttachmentCreatedEvent
251
- | AttachmentDeletedEvent
252
- | TaskDependencyAddedEvent
253
- | TaskDependencyRemovedEvent
254
- | ProjectCreatedEvent
255
- | ProjectUpdatedEvent
256
- | ProjectDeletedEvent
257
- | WorkflowCreatedEvent
258
- | WorkflowUpdatedEvent
259
- | WorkflowDeletedEvent
260
- | IterationStartedEvent
261
- | IterationCompletedEvent
262
- | TeamCreatedEvent
263
- | TeamUpdatedEvent
264
- | TeamDeletedEvent
265
- | ContainerCreatedEvent
266
- | ContainerUpdatedEvent
267
- | ContainerDeletedEvent
268
- | IterationCreatedEvent
269
- | IterationUpdatedEvent
270
- | IterationDeletedEvent
271
- | DeliverableCreatedEvent
272
- | DeliverableUpdatedEvent
273
- | DeliverableStatusChangedEvent
274
- | DeliverableDeletedEvent;
275
-
276
- export type DomainEventHandler<T extends DomainEvent = DomainEvent> = (event: T) => Promise<void> | void;
277
-
278
- export class DomainEventBus {
279
- private handlers = new Map<string, Array<DomainEventHandler<any>>>();
280
-
281
- subscribe<T extends DomainEvent = DomainEvent>(
282
- eventName: T['name'] | '*',
283
- handler: DomainEventHandler<T>
284
- ): () => void {
285
- const list = this.handlers.get(eventName) || [];
286
- list.push(handler);
287
- this.handlers.set(eventName, list);
288
-
289
- return () => {
290
- const currentList = this.handlers.get(eventName) || [];
291
- this.handlers.set(
292
- eventName,
293
- currentList.filter((h) => h !== handler)
294
- );
295
- };
296
- }
297
-
298
- async publish(event: DomainEvent): Promise<void> {
299
- const directHandlers = this.handlers.get(event.name) || [];
300
- const wildcardHandlers = this.handlers.get('*') || [];
301
- const allHandlers = [...directHandlers, ...wildcardHandlers];
302
-
303
- for (const handler of allHandlers) {
304
- try {
305
- await handler(event);
306
- } catch (err) {
307
- // Prevent subscriber failures from breaking event pipeline
308
- console.error(`[DomainEventBus] Handler error on event "${event.name}":`, err);
309
- }
310
- }
311
- }
312
-
313
- async publishAll(events: DomainEvent[]): Promise<void> {
314
- for (const event of events) {
315
- await this.publish(event);
316
- }
317
- }
318
-
319
- clear(): void {
320
- this.handlers.clear();
321
- }
322
- }
323
-
324
- /** Every domain event name, e.g. for validating webhook subscriptions at runtime. */
325
- export const DOMAIN_EVENT_NAMES = [
326
- 'attachment.created',
327
- 'attachment.deleted',
328
- 'comment.created',
329
- 'comment.deleted',
330
- 'comment.reaction.added',
331
- 'comment.reaction.removed',
332
- 'comment.updated',
333
- 'container.created',
334
- 'container.deleted',
335
- 'container.updated',
336
- 'deliverable.created',
337
- 'deliverable.deleted',
338
- 'deliverable.status_changed',
339
- 'deliverable.updated',
340
- 'dependency.added',
341
- 'dependency.removed',
342
- 'iteration.completed',
343
- 'iteration.created',
344
- 'iteration.deleted',
345
- 'iteration.started',
346
- 'iteration.updated',
347
- 'project.created',
348
- 'project.deleted',
349
- 'project.updated',
350
- 'task.blocked',
351
- 'task.created',
352
- 'task.deleted',
353
- 'task.status_changed',
354
- 'task.unblocked',
355
- 'task.updated',
356
- 'team.created',
357
- 'team.deleted',
358
- 'team.updated',
359
- 'time.logged',
360
- 'workflow.created',
361
- 'workflow.deleted',
362
- 'workflow.updated'
363
- ] as const satisfies readonly CriticalPathDomainEvent['name'][];
364
-
365
- // Compile-time guard: adding an event to CriticalPathDomainEvent without listing it here fails the build.
366
- type UnlistedDomainEvent = Exclude<CriticalPathDomainEvent['name'], (typeof DOMAIN_EVENT_NAMES)[number]>;
367
- const _allDomainEventsListed: [UnlistedDomainEvent] extends [never] ? true : UnlistedDomainEvent = true;
368
- void _allDomainEventsListed;
369
-
@@ -1,70 +0,0 @@
1
- import type { TaskDependency } from '../types/index.js';
2
-
3
- export class CircularDependencyError extends Error {
4
- public readonly taskId: string;
5
- public readonly dependsOnTaskId: string;
6
- public readonly cyclePath?: string[];
7
-
8
- constructor(taskId: string, dependsOnTaskId: string, cyclePath?: string[]) {
9
- const pathStr = cyclePath ? ` (Cycle detected: ${cyclePath.join(' -> ')})` : '';
10
- super(`Cannot add dependency from "${taskId}" to "${dependsOnTaskId}" because it would create a circular dependency cycle${pathStr}.`);
11
- this.name = 'CircularDependencyError';
12
- this.taskId = taskId;
13
- this.dependsOnTaskId = dependsOnTaskId;
14
- this.cyclePath = cyclePath;
15
- }
16
- }
17
-
18
- /**
19
- * Validates that adding a dependency from taskId to dependsOnTaskId will not create a cycle in the task graph.
20
- * A cycle occurs if dependsOnTaskId already transitively depends on taskId.
21
- */
22
- export function detectDependencyCycle(
23
- existingDependencies: TaskDependency[],
24
- newDependency: { taskId: string; dependsOnTaskId: string }
25
- ): { hasCycle: boolean; cyclePath?: string[] } {
26
- const { taskId, dependsOnTaskId } = newDependency;
27
-
28
- // Self-dependency check
29
- if (taskId === dependsOnTaskId) {
30
- return { hasCycle: true, cyclePath: [taskId, taskId] };
31
- }
32
-
33
- // Build adjacency list: node -> array of nodes it depends on
34
- const adj = new Map<string, string[]>();
35
- for (const dep of existingDependencies) {
36
- const targets = adj.get(dep.taskId) || [];
37
- targets.push(dep.dependsOnTaskId);
38
- adj.set(dep.taskId, targets);
39
- }
40
-
41
- // Check if dependsOnTaskId can reach taskId via existing dependency paths
42
- const visited = new Set<string>();
43
- const path: string[] = [taskId, dependsOnTaskId];
44
-
45
- function dfs(current: string): boolean {
46
- if (current === taskId) {
47
- return true;
48
- }
49
- if (visited.has(current)) {
50
- return false;
51
- }
52
- visited.add(current);
53
-
54
- const neighbors = adj.get(current) || [];
55
- for (const next of neighbors) {
56
- path.push(next);
57
- if (dfs(next)) {
58
- return true;
59
- }
60
- path.pop();
61
- }
62
- return false;
63
- }
64
-
65
- const hasCycle = dfs(dependsOnTaskId);
66
- return {
67
- hasCycle,
68
- cyclePath: hasCycle ? path : undefined
69
- };
70
- }
@@ -1,12 +0,0 @@
1
- export * from './events.js';
2
- export * from './custom-fields.js';
3
- export * from './graph.js';
4
- export * from './errors.js';
5
- export * from './authorization.js';
6
- export * from './entities.js';
7
- export * from './cpm.js';
8
- export * from './ladder.js';
9
- export * from './metrics.js';
10
- export * from './workload.js';
11
- export * from './calendar.js';
12
-