@critical-path/core 0.5.2 → 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 (51) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +51 -21
  3. package/dist/domain/custom-fields.d.ts +9 -0
  4. package/dist/domain/custom-fields.d.ts.map +1 -0
  5. package/dist/domain/custom-fields.js +72 -0
  6. package/dist/domain/custom-fields.js.map +1 -0
  7. package/dist/domain/ddd.test.d.ts +2 -0
  8. package/dist/domain/ddd.test.d.ts.map +1 -0
  9. package/dist/domain/ddd.test.js +246 -0
  10. package/dist/domain/ddd.test.js.map +1 -0
  11. package/dist/domain/entities.d.ts +82 -0
  12. package/dist/domain/entities.d.ts.map +1 -0
  13. package/dist/domain/entities.js +321 -0
  14. package/dist/domain/entities.js.map +1 -0
  15. package/dist/domain/events.d.ts +125 -0
  16. package/dist/domain/events.d.ts.map +1 -0
  17. package/dist/domain/events.js +35 -0
  18. package/dist/domain/events.js.map +1 -0
  19. package/dist/domain/graph.d.ts +19 -0
  20. package/dist/domain/graph.d.ts.map +1 -0
  21. package/dist/domain/graph.js +58 -0
  22. package/dist/domain/graph.js.map +1 -0
  23. package/dist/domain/index.d.ts +5 -0
  24. package/dist/domain/index.d.ts.map +1 -0
  25. package/dist/domain/index.js +5 -0
  26. package/dist/domain/index.js.map +1 -0
  27. package/dist/engine/index.d.ts +10 -2
  28. package/dist/engine/index.d.ts.map +1 -1
  29. package/dist/engine/index.js +288 -6
  30. package/dist/engine/index.js.map +1 -1
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/store/index.d.ts +23 -1
  36. package/dist/store/index.d.ts.map +1 -1
  37. package/dist/store/index.js.map +1 -1
  38. package/dist/types/index.d.ts +5 -0
  39. package/dist/types/index.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/src/domain/custom-fields.ts +131 -0
  42. package/src/domain/ddd.test.ts +307 -0
  43. package/src/domain/entities.ts +390 -0
  44. package/src/domain/events.ts +171 -0
  45. package/src/domain/graph.ts +70 -0
  46. package/src/domain/index.ts +4 -0
  47. package/src/engine/index.ts +355 -8
  48. package/src/index.ts +1 -1
  49. package/src/store/index.ts +35 -11
  50. package/src/types/index.ts +7 -0
  51. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,321 @@
1
+ import { validateTransition, WorkflowValidationError } from '../utils/workflow.js';
2
+ import { resolveStatusDefinition } from '../utils/status.js';
3
+ import { validateCustomFieldValues } from './custom-fields.js';
4
+ import { generateProjectKey } from '../utils/key.js';
5
+ export class BaseEntity {
6
+ id;
7
+ createdAt;
8
+ updatedAt;
9
+ uncommittedEvents = [];
10
+ constructor(id, createdAt, updatedAt) {
11
+ const now = new Date().toISOString();
12
+ this.id = id;
13
+ this.createdAt = createdAt || now;
14
+ this.updatedAt = updatedAt || now;
15
+ }
16
+ raiseEvent(event) {
17
+ this.uncommittedEvents.push(event);
18
+ }
19
+ getUncommittedEvents() {
20
+ return [...this.uncommittedEvents];
21
+ }
22
+ clearEvents() {
23
+ this.uncommittedEvents = [];
24
+ }
25
+ markUpdated() {
26
+ this.updatedAt = new Date().toISOString();
27
+ }
28
+ }
29
+ export class TaskEntity extends BaseEntity {
30
+ projectId;
31
+ key;
32
+ title;
33
+ description;
34
+ status;
35
+ priority;
36
+ taskType;
37
+ assigneeId;
38
+ reporterId;
39
+ reviewerId;
40
+ iterationId;
41
+ teamId;
42
+ containerId;
43
+ plannedStartDate;
44
+ actualStartDate;
45
+ actualEndDate;
46
+ dueDate;
47
+ estimatedHours;
48
+ loggedHours;
49
+ actualHours;
50
+ billableHours;
51
+ estimatedDurationMinutes;
52
+ actualDurationMinutes;
53
+ billableDurationMinutes;
54
+ progress;
55
+ tags;
56
+ customFields;
57
+ parentId;
58
+ constructor(data) {
59
+ super(data.id, data.createdAt, data.updatedAt);
60
+ this.projectId = data.projectId;
61
+ this.key = data.key;
62
+ this.title = data.title;
63
+ this.description = data.description;
64
+ this.status = data.status;
65
+ this.priority = data.priority;
66
+ this.taskType = data.taskType;
67
+ this.assigneeId = data.assigneeId;
68
+ this.reporterId = data.reporterId;
69
+ this.reviewerId = data.reviewerId;
70
+ this.iterationId = data.iterationId;
71
+ this.teamId = data.teamId;
72
+ this.containerId = data.containerId;
73
+ this.plannedStartDate = data.plannedStartDate;
74
+ this.actualStartDate = data.actualStartDate;
75
+ this.actualEndDate = data.actualEndDate;
76
+ this.dueDate = data.dueDate;
77
+ this.estimatedHours = data.estimatedHours;
78
+ this.loggedHours = data.loggedHours ?? 0;
79
+ this.actualHours = data.actualHours;
80
+ this.billableHours = data.billableHours;
81
+ this.estimatedDurationMinutes = data.estimatedDurationMinutes;
82
+ this.actualDurationMinutes = data.actualDurationMinutes;
83
+ this.billableDurationMinutes = data.billableDurationMinutes;
84
+ this.progress = data.progress ?? 0;
85
+ this.tags = data.tags ? [...data.tags] : [];
86
+ this.customFields = data.customFields ? { ...data.customFields } : {};
87
+ this.parentId = data.parentId;
88
+ }
89
+ static create(input, options) {
90
+ const id = options?.id || `task_${Math.random().toString(36).substring(2, 9)}`;
91
+ const now = new Date().toISOString();
92
+ if (options?.customFieldDefs) {
93
+ validateCustomFieldValues(options.customFieldDefs, input.customFields);
94
+ }
95
+ const task = new TaskEntity({
96
+ ...input,
97
+ id,
98
+ createdAt: now,
99
+ updatedAt: now,
100
+ status: input.status || options?.workflow?.defaultStatusKey || 'todo',
101
+ priority: input.priority || 'medium',
102
+ loggedHours: input.loggedHours ?? 0,
103
+ progress: input.progress ?? 0,
104
+ tags: input.tags ?? [],
105
+ customFields: input.customFields ?? {}
106
+ });
107
+ const createdEvent = {
108
+ id: `evt_${Math.random().toString(36).substring(2, 9)}`,
109
+ name: 'task.created',
110
+ aggregateId: task.id,
111
+ aggregateType: 'Task',
112
+ occurredAt: now,
113
+ payload: { task: task.toPlain() }
114
+ };
115
+ task.raiseEvent(createdEvent);
116
+ return task;
117
+ }
118
+ transitionTo(newStatus, workflow, options) {
119
+ if (this.status === newStatus)
120
+ return this;
121
+ const isValid = validateTransition(workflow, this.status, newStatus);
122
+ if (!isValid) {
123
+ throw new WorkflowValidationError(this.status, newStatus, workflow?.id);
124
+ }
125
+ const previousStatus = this.status;
126
+ this.status = newStatus;
127
+ const now = new Date().toISOString();
128
+ const statusDef = resolveStatusDefinition(newStatus, options?.statusDefs || workflow?.statuses);
129
+ if (statusDef.executionState === 'active' && !this.actualStartDate) {
130
+ this.actualStartDate = now;
131
+ }
132
+ if (statusDef.completionState === 'done') {
133
+ this.actualEndDate = now;
134
+ if (this.progress !== undefined && this.progress < 100) {
135
+ this.progress = 100;
136
+ }
137
+ }
138
+ this.markUpdated();
139
+ const event = {
140
+ id: `evt_${Math.random().toString(36).substring(2, 9)}`,
141
+ name: 'task.status_changed',
142
+ aggregateId: this.id,
143
+ aggregateType: 'Task',
144
+ occurredAt: now,
145
+ payload: {
146
+ task: this.toPlain(),
147
+ previousStatus,
148
+ newStatus
149
+ }
150
+ };
151
+ this.raiseEvent(event);
152
+ return this;
153
+ }
154
+ logTime(entry) {
155
+ if (entry.hours <= 0) {
156
+ throw new Error('Logged hours must be a positive number.');
157
+ }
158
+ this.loggedHours = (this.loggedHours || 0) + entry.hours;
159
+ this.actualHours = (this.actualHours || 0) + entry.hours;
160
+ if (entry.isBillable !== false) {
161
+ this.billableHours = (this.billableHours || 0) + entry.hours;
162
+ }
163
+ const now = new Date().toISOString();
164
+ this.markUpdated();
165
+ const timeEntry = {
166
+ id: `time_${Math.random().toString(36).substring(2, 9)}`,
167
+ taskId: this.id,
168
+ userId: entry.userId || this.assigneeId || 'system',
169
+ hours: entry.hours,
170
+ isBillable: entry.isBillable ?? true,
171
+ description: entry.description,
172
+ loggedAt: now
173
+ };
174
+ const event = {
175
+ id: `evt_${Math.random().toString(36).substring(2, 9)}`,
176
+ name: 'time.logged',
177
+ aggregateId: this.id,
178
+ aggregateType: 'Task',
179
+ occurredAt: now,
180
+ payload: {
181
+ taskId: this.id,
182
+ timeEntry
183
+ }
184
+ };
185
+ this.raiseEvent(event);
186
+ return timeEntry;
187
+ }
188
+ update(updates, customFieldDefs) {
189
+ const previous = this.toPlain();
190
+ if (updates.customFields && customFieldDefs) {
191
+ validateCustomFieldValues(customFieldDefs, {
192
+ ...this.customFields,
193
+ ...updates.customFields
194
+ });
195
+ }
196
+ Object.assign(this, updates);
197
+ this.markUpdated();
198
+ const event = {
199
+ id: `evt_${Math.random().toString(36).substring(2, 9)}`,
200
+ name: 'task.updated',
201
+ aggregateId: this.id,
202
+ aggregateType: 'Task',
203
+ occurredAt: new Date().toISOString(),
204
+ payload: {
205
+ task: this.toPlain(),
206
+ previous
207
+ }
208
+ };
209
+ this.raiseEvent(event);
210
+ return this;
211
+ }
212
+ toPlain() {
213
+ return {
214
+ id: this.id,
215
+ projectId: this.projectId,
216
+ key: this.key,
217
+ title: this.title,
218
+ description: this.description,
219
+ status: this.status,
220
+ priority: this.priority,
221
+ taskType: this.taskType,
222
+ assigneeId: this.assigneeId,
223
+ reporterId: this.reporterId,
224
+ reviewerId: this.reviewerId,
225
+ iterationId: this.iterationId,
226
+ teamId: this.teamId,
227
+ containerId: this.containerId,
228
+ plannedStartDate: this.plannedStartDate,
229
+ actualStartDate: this.actualStartDate,
230
+ actualEndDate: this.actualEndDate,
231
+ dueDate: this.dueDate,
232
+ estimatedHours: this.estimatedHours,
233
+ loggedHours: this.loggedHours,
234
+ actualHours: this.actualHours,
235
+ billableHours: this.billableHours,
236
+ estimatedDurationMinutes: this.estimatedDurationMinutes,
237
+ actualDurationMinutes: this.actualDurationMinutes,
238
+ billableDurationMinutes: this.billableDurationMinutes,
239
+ progress: this.progress,
240
+ tags: this.tags ? [...this.tags] : [],
241
+ customFields: this.customFields ? { ...this.customFields } : {},
242
+ parentId: this.parentId,
243
+ createdAt: this.createdAt,
244
+ updatedAt: this.updatedAt
245
+ };
246
+ }
247
+ }
248
+ export class ProjectEntity extends BaseEntity {
249
+ key;
250
+ name;
251
+ description;
252
+ ownerId;
253
+ members;
254
+ teamIds;
255
+ workflowId;
256
+ workflow;
257
+ taskTypes;
258
+ statusDefinitions;
259
+ priorityDefinitions;
260
+ customFieldDefinitions;
261
+ constructor(data) {
262
+ super(data.id, data.createdAt, data.updatedAt);
263
+ this.key = data.key || generateProjectKey(data.name);
264
+ this.name = data.name;
265
+ this.description = data.description;
266
+ this.ownerId = data.ownerId;
267
+ this.members = data.members ? [...data.members] : [];
268
+ this.teamIds = data.teamIds ? [...data.teamIds] : [];
269
+ this.workflowId = data.workflowId;
270
+ this.workflow = data.workflow;
271
+ this.taskTypes = data.taskTypes;
272
+ this.statusDefinitions = data.statusDefinitions;
273
+ this.priorityDefinitions = data.priorityDefinitions;
274
+ this.customFieldDefinitions = data.customFieldDefinitions ? [...data.customFieldDefinitions] : [];
275
+ }
276
+ static create(input, options) {
277
+ const id = options?.id || `proj_${Math.random().toString(36).substring(2, 9)}`;
278
+ const now = new Date().toISOString();
279
+ const key = input.key || generateProjectKey(input.name);
280
+ const project = new ProjectEntity({
281
+ ...input,
282
+ id,
283
+ key,
284
+ createdAt: now,
285
+ updatedAt: now
286
+ });
287
+ const event = {
288
+ id: `evt_${Math.random().toString(36).substring(2, 9)}`,
289
+ name: 'project.created',
290
+ aggregateId: project.id,
291
+ aggregateType: 'Project',
292
+ occurredAt: now,
293
+ payload: { project: project.toPlain() }
294
+ };
295
+ project.raiseEvent(event);
296
+ return project;
297
+ }
298
+ validateCustomFields(values) {
299
+ validateCustomFieldValues(this.customFieldDefinitions, values);
300
+ }
301
+ toPlain() {
302
+ return {
303
+ id: this.id,
304
+ key: this.key,
305
+ name: this.name,
306
+ description: this.description,
307
+ ownerId: this.ownerId,
308
+ members: this.members ? [...this.members] : [],
309
+ teamIds: this.teamIds ? [...this.teamIds] : [],
310
+ workflowId: this.workflowId,
311
+ workflow: this.workflow,
312
+ taskTypes: this.taskTypes,
313
+ statusDefinitions: this.statusDefinitions,
314
+ priorityDefinitions: this.priorityDefinitions,
315
+ customFieldDefinitions: this.customFieldDefinitions ? [...this.customFieldDefinitions] : [],
316
+ createdAt: this.createdAt,
317
+ updatedAt: this.updatedAt
318
+ };
319
+ }
320
+ }
321
+ //# sourceMappingURL=entities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entities.js","sourceRoot":"","sources":["../../src/domain/entities.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,OAAgB,UAAU;IACd,EAAE,CAAS;IACpB,SAAS,CAAS;IAClB,SAAS,CAAS;IACjB,iBAAiB,GAAkB,EAAE,CAAC;IAE9C,YAAY,EAAU,EAAE,SAAkB,EAAE,SAAkB;QAC5D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,GAAG,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,GAAG,CAAC;IACpC,CAAC;IAES,UAAU,CAAC,KAAkB;QACrC,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IAEM,oBAAoB;QACzB,OAAO,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAEM,WAAW;QAChB,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC;IAC9B,CAAC;IAES,WAAW;QACnB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,CAAC;CACF;AAED,MAAM,OAAO,UAAW,SAAQ,UAAU;IACjC,SAAS,CAAS;IAClB,GAAG,CAAU;IACb,KAAK,CAAS;IACd,WAAW,CAAU;IACrB,MAAM,CAAa;IACnB,QAAQ,CAAW;IACnB,QAAQ,CAAU;IAClB,UAAU,CAAU;IACpB,UAAU,CAAU;IACpB,UAAU,CAAU;IACpB,WAAW,CAAU;IACrB,MAAM,CAAU;IAChB,WAAW,CAAU;IACrB,gBAAgB,CAAU;IAC1B,eAAe,CAAU;IACzB,aAAa,CAAU;IACvB,OAAO,CAAU;IACjB,cAAc,CAAU;IACxB,WAAW,CAAU;IACrB,WAAW,CAAU;IACrB,aAAa,CAAU;IACvB,wBAAwB,CAAU;IAClC,qBAAqB,CAAU;IAC/B,uBAAuB,CAAU;IACjC,QAAQ,CAAU;IAClB,IAAI,CAAY;IAChB,YAAY,CAA2B;IACvC,QAAQ,CAAU;IAEzB,YAAY,IAAU;QACpB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,CAAC;QAC9C,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC;QAC5C,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC;QACzC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC;QACxC,IAAI,CAAC,wBAAwB,GAAG,IAAI,CAAC,wBAAwB,CAAC;QAC9D,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,CAAC;QACxD,IAAI,CAAC,uBAAuB,GAAG,IAAI,CAAC,uBAAuB,CAAC;QAC5D,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChC,CAAC;IAEM,MAAM,CAAC,MAAM,CAClB,KAAsB,EACtB,OAAyF;QAEzF,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC/E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;YAC7B,yBAAyB,CAAC,OAAO,CAAC,eAAe,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC;YAC1B,GAAG,KAAK;YACR,EAAE;YACF,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,OAAO,EAAE,QAAQ,EAAE,gBAAgB,IAAI,MAAM;YACrE,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,QAAQ;YACpC,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,CAAC;YACnC,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,CAAC;YAC7B,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;YACtB,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,EAAE;SACvC,CAAC,CAAC;QAEH,MAAM,YAAY,GAAqB;YACrC,EAAE,EAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACvD,IAAI,EAAE,cAAc;YACpB,WAAW,EAAE,IAAI,CAAC,EAAE;YACpB,aAAa,EAAE,MAAM;YACrB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE;SAClC,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAE9B,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,YAAY,CACjB,SAAiB,EACjB,QAAmB,EACnB,OAAiE;QAEjE,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QAE3C,MAAM,OAAO,GAAG,kBAAkB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACrE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,uBAAuB,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErC,MAAM,SAAS,GAAG,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,UAAU,IAAI,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAChG,IAAI,SAAS,CAAC,cAAc,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YACnE,IAAI,CAAC,eAAe,GAAG,GAAG,CAAC;QAC7B,CAAC;QACD,IAAI,SAAS,CAAC,eAAe,KAAK,MAAM,EAAE,CAAC;YACzC,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC;YACzB,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC;gBACvD,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;YACtB,CAAC;QACH,CAAC;QAED,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,KAAK,GAA2B;YACpC,EAAE,EAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACvD,IAAI,EAAE,qBAAqB;YAC3B,WAAW,EAAE,IAAI,CAAC,EAAE;YACpB,aAAa,EAAE,MAAM;YACrB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE;gBACP,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE;gBACpB,cAAc;gBACd,SAAS;aACV;SACF,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEvB,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,OAAO,CACZ,KAAqF;QAErF,IAAI,KAAK,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QACzD,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QACzD,IAAI,KAAK,CAAC,UAAU,KAAK,KAAK,EAAE,CAAC;YAC/B,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC;QAC/D,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,SAAS,GAAc;YAC3B,EAAE,EAAE,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACxD,MAAM,EAAE,IAAI,CAAC,EAAE;YACf,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,IAAI,QAAQ;YACnD,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI;YACpC,WAAW,EAAE,KAAK,CAAC,WAAW;YAC9B,QAAQ,EAAE,GAAG;SACd,CAAC;QAEF,MAAM,KAAK,GAAoB;YAC7B,EAAE,EAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACvD,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,IAAI,CAAC,EAAE;YACpB,aAAa,EAAE,MAAM;YACrB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE;gBACP,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,SAAS;aACV;SACF,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEvB,OAAO,SAAS,CAAC;IACnB,CAAC;IAEM,MAAM,CAAC,OAAsB,EAAE,eAAyC;QAC7E,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAEhC,IAAI,OAAO,CAAC,YAAY,IAAI,eAAe,EAAE,CAAC;YAC5C,yBAAyB,CAAC,eAAe,EAAE;gBACzC,GAAG,IAAI,CAAC,YAAY;gBACpB,GAAG,OAAO,CAAC,YAAY;aACxB,CAAC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC7B,IAAI,CAAC,WAAW,EAAE,CAAC;QAEnB,MAAM,KAAK,GAAqB;YAC9B,EAAE,EAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACvD,IAAI,EAAE,cAAc;YACpB,WAAW,EAAE,IAAI,CAAC,EAAE;YACpB,aAAa,EAAE,MAAM;YACrB,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACpC,OAAO,EAAE;gBACP,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE;gBACpB,QAAQ;aACT;SACF,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEvB,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,OAAO;QACZ,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,wBAAwB,EAAE,IAAI,CAAC,wBAAwB;YACvD,qBAAqB,EAAE,IAAI,CAAC,qBAAqB;YACjD,uBAAuB,EAAE,IAAI,CAAC,uBAAuB;YACrD,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;YACrC,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE;YAC/D,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAO,aAAc,SAAQ,UAAU;IACpC,GAAG,CAAS;IACZ,IAAI,CAAS;IACb,WAAW,CAAU;IACrB,OAAO,CAAU;IACjB,OAAO,CAAY;IACnB,OAAO,CAAY;IACnB,UAAU,CAAU;IACpB,QAAQ,CAAY;IACpB,SAAS,CAAwB;IACjC,iBAAiB,CAAgC;IACjD,mBAAmB,CAAkC;IACrD,sBAAsB,CAA2B;IAExD,YAAY,IAAa;QACvB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACtB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QACpC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QAChC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAChD,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,mBAAmB,CAAC;QACpD,IAAI,CAAC,sBAAsB,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpG,CAAC;IAEM,MAAM,CAAC,MAAM,CAClB,KAAyB,EACzB,OAAyB;QAEzB,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC/E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAExD,MAAM,OAAO,GAAG,IAAI,aAAa,CAAC;YAChC,GAAG,KAAK;YACR,EAAE;YACF,GAAG;YACH,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC,CAAC;QAEH,MAAM,KAAK,GAAwB;YACjC,EAAE,EAAE,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;YACvD,IAAI,EAAE,iBAAiB;YACvB,WAAW,EAAE,OAAO,CAAC,EAAE;YACvB,aAAa,EAAE,SAAS;YACxB,UAAU,EAAE,GAAG;YACf,OAAO,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE;SACxC,CAAC;QACF,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAE1B,OAAO,OAAO,CAAC;IACjB,CAAC;IAEM,oBAAoB,CAAC,MAAgC;QAC1D,yBAAyB,CAAC,IAAI,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC;IACjE,CAAC;IAEM,OAAO;QACZ,OAAO;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;YAC9C,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE;YAC9C,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,mBAAmB,EAAE,IAAI,CAAC,mBAAmB;YAC7C,sBAAsB,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAAE;YAC3F,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,125 @@
1
+ import type { Task, Project, Workflow, Iteration, Team, TaskContainer, TaskDependency, TimeEntry, Comment } from '../types/index.js';
2
+ export interface DomainEvent<TPayload = Record<string, unknown>> {
3
+ readonly id: string;
4
+ readonly name: string;
5
+ readonly aggregateId: string;
6
+ readonly aggregateType: 'Task' | 'Project' | 'Workflow' | 'Iteration' | 'Team' | 'Container' | 'Dependency';
7
+ readonly occurredAt: string;
8
+ readonly payload: TPayload;
9
+ }
10
+ export interface TaskCreatedEvent extends DomainEvent<{
11
+ task: Task;
12
+ }> {
13
+ readonly name: 'task.created';
14
+ readonly aggregateType: 'Task';
15
+ }
16
+ export interface TaskUpdatedEvent extends DomainEvent<{
17
+ task: Task;
18
+ previous: Task;
19
+ }> {
20
+ readonly name: 'task.updated';
21
+ readonly aggregateType: 'Task';
22
+ }
23
+ export interface TaskStatusChangedEvent extends DomainEvent<{
24
+ task: Task;
25
+ previousStatus: string;
26
+ newStatus: string;
27
+ }> {
28
+ readonly name: 'task.status_changed';
29
+ readonly aggregateType: 'Task';
30
+ }
31
+ export interface TaskDeletedEvent extends DomainEvent<{
32
+ taskId: string;
33
+ projectId: string;
34
+ title: string;
35
+ }> {
36
+ readonly name: 'task.deleted';
37
+ readonly aggregateType: 'Task';
38
+ }
39
+ export interface TimeLoggedEvent extends DomainEvent<{
40
+ timeEntry: TimeEntry;
41
+ taskId: string;
42
+ }> {
43
+ readonly name: 'time.logged';
44
+ readonly aggregateType: 'Task';
45
+ }
46
+ export interface CommentAddedEvent extends DomainEvent<{
47
+ comment: Comment;
48
+ taskId: string;
49
+ }> {
50
+ readonly name: 'comment.created';
51
+ readonly aggregateType: 'Task';
52
+ }
53
+ export interface TaskDependencyAddedEvent extends DomainEvent<{
54
+ dependency: TaskDependency;
55
+ }> {
56
+ readonly name: 'dependency.added';
57
+ readonly aggregateType: 'Dependency';
58
+ }
59
+ export interface ProjectCreatedEvent extends DomainEvent<{
60
+ project: Project;
61
+ }> {
62
+ readonly name: 'project.created';
63
+ readonly aggregateType: 'Project';
64
+ }
65
+ export interface ProjectUpdatedEvent extends DomainEvent<{
66
+ project: Project;
67
+ previous: Project;
68
+ }> {
69
+ readonly name: 'project.updated';
70
+ readonly aggregateType: 'Project';
71
+ }
72
+ export interface WorkflowCreatedEvent extends DomainEvent<{
73
+ workflow: Workflow;
74
+ }> {
75
+ readonly name: 'workflow.created';
76
+ readonly aggregateType: 'Workflow';
77
+ }
78
+ export interface WorkflowUpdatedEvent extends DomainEvent<{
79
+ workflow: Workflow;
80
+ previous: Workflow;
81
+ }> {
82
+ readonly name: 'workflow.updated';
83
+ readonly aggregateType: 'Workflow';
84
+ }
85
+ export interface WorkflowDeletedEvent extends DomainEvent<{
86
+ workflowId: string;
87
+ name: string;
88
+ }> {
89
+ readonly name: 'workflow.deleted';
90
+ readonly aggregateType: 'Workflow';
91
+ }
92
+ export interface IterationStartedEvent extends DomainEvent<{
93
+ iteration: Iteration;
94
+ }> {
95
+ readonly name: 'iteration.started';
96
+ readonly aggregateType: 'Iteration';
97
+ }
98
+ export interface IterationCompletedEvent extends DomainEvent<{
99
+ iteration: Iteration;
100
+ }> {
101
+ readonly name: 'iteration.completed';
102
+ readonly aggregateType: 'Iteration';
103
+ }
104
+ export interface TeamCreatedEvent extends DomainEvent<{
105
+ team: Team;
106
+ }> {
107
+ readonly name: 'team.created';
108
+ readonly aggregateType: 'Team';
109
+ }
110
+ export interface ContainerCreatedEvent extends DomainEvent<{
111
+ container: TaskContainer;
112
+ }> {
113
+ readonly name: 'container.created';
114
+ readonly aggregateType: 'Container';
115
+ }
116
+ export type CriticalPathDomainEvent = TaskCreatedEvent | TaskUpdatedEvent | TaskStatusChangedEvent | TaskDeletedEvent | TimeLoggedEvent | CommentAddedEvent | TaskDependencyAddedEvent | ProjectCreatedEvent | ProjectUpdatedEvent | WorkflowCreatedEvent | WorkflowUpdatedEvent | WorkflowDeletedEvent | IterationStartedEvent | IterationCompletedEvent | TeamCreatedEvent | ContainerCreatedEvent;
117
+ export type DomainEventHandler<T extends DomainEvent = DomainEvent> = (event: T) => Promise<void> | void;
118
+ export declare class DomainEventBus {
119
+ private handlers;
120
+ subscribe<T extends DomainEvent = DomainEvent>(eventName: T['name'] | '*', handler: DomainEventHandler<T>): () => void;
121
+ publish(event: DomainEvent): Promise<void>;
122
+ publishAll(events: DomainEvent[]): Promise<void>;
123
+ clear(): void;
124
+ }
125
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/domain/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export class DomainEventBus {
2
+ handlers = new Map();
3
+ subscribe(eventName, handler) {
4
+ const list = this.handlers.get(eventName) || [];
5
+ list.push(handler);
6
+ this.handlers.set(eventName, list);
7
+ return () => {
8
+ const currentList = this.handlers.get(eventName) || [];
9
+ this.handlers.set(eventName, currentList.filter((h) => h !== handler));
10
+ };
11
+ }
12
+ async publish(event) {
13
+ const directHandlers = this.handlers.get(event.name) || [];
14
+ const wildcardHandlers = this.handlers.get('*') || [];
15
+ const allHandlers = [...directHandlers, ...wildcardHandlers];
16
+ for (const handler of allHandlers) {
17
+ try {
18
+ await handler(event);
19
+ }
20
+ catch (err) {
21
+ // Prevent subscriber failures from breaking event pipeline
22
+ console.error(`[DomainEventBus] Handler error on event "${event.name}":`, err);
23
+ }
24
+ }
25
+ }
26
+ async publishAll(events) {
27
+ for (const event of events) {
28
+ await this.publish(event);
29
+ }
30
+ }
31
+ clear() {
32
+ this.handlers.clear();
33
+ }
34
+ }
35
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/domain/events.ts"],"names":[],"mappings":"AA8HA,MAAM,OAAO,cAAc;IACjB,QAAQ,GAAG,IAAI,GAAG,EAA0C,CAAC;IAErE,SAAS,CACP,SAA0B,EAC1B,OAA8B;QAE9B,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAEnC,OAAO,GAAG,EAAE;YACV,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;YACvD,IAAI,CAAC,QAAQ,CAAC,GAAG,CACf,SAAS,EACT,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,OAAO,CAAC,CACzC,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAkB;QAC9B,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3D,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACtD,MAAM,WAAW,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,gBAAgB,CAAC,CAAC;QAE7D,KAAK,MAAM,OAAO,IAAI,WAAW,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;YACvB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,2DAA2D;gBAC3D,OAAO,CAAC,KAAK,CAAC,4CAA4C,KAAK,CAAC,IAAI,IAAI,EAAE,GAAG,CAAC,CAAC;YACjF,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAqB;QACpC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,KAAK;QACH,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ import type { TaskDependency } from '../types/index.js';
2
+ export declare class CircularDependencyError extends Error {
3
+ readonly taskId: string;
4
+ readonly dependsOnTaskId: string;
5
+ readonly cyclePath?: string[];
6
+ constructor(taskId: string, dependsOnTaskId: string, cyclePath?: string[]);
7
+ }
8
+ /**
9
+ * Validates that adding a dependency from taskId to dependsOnTaskId will not create a cycle in the task graph.
10
+ * A cycle occurs if dependsOnTaskId already transitively depends on taskId.
11
+ */
12
+ export declare function detectDependencyCycle(existingDependencies: TaskDependency[], newDependency: {
13
+ taskId: string;
14
+ dependsOnTaskId: string;
15
+ }): {
16
+ hasCycle: boolean;
17
+ cyclePath?: string[];
18
+ };
19
+ //# sourceMappingURL=graph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/domain/graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,SAAgB,eAAe,EAAE,MAAM,CAAC;IACxC,SAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;gBAEzB,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE;CAQ1E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,oBAAoB,EAAE,cAAc,EAAE,EACtC,aAAa,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GACzD;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CA6C7C"}
@@ -0,0 +1,58 @@
1
+ export class CircularDependencyError extends Error {
2
+ taskId;
3
+ dependsOnTaskId;
4
+ cyclePath;
5
+ constructor(taskId, dependsOnTaskId, cyclePath) {
6
+ const pathStr = cyclePath ? ` (Cycle detected: ${cyclePath.join(' -> ')})` : '';
7
+ super(`Cannot add dependency from "${taskId}" to "${dependsOnTaskId}" because it would create a circular dependency cycle${pathStr}.`);
8
+ this.name = 'CircularDependencyError';
9
+ this.taskId = taskId;
10
+ this.dependsOnTaskId = dependsOnTaskId;
11
+ this.cyclePath = cyclePath;
12
+ }
13
+ }
14
+ /**
15
+ * Validates that adding a dependency from taskId to dependsOnTaskId will not create a cycle in the task graph.
16
+ * A cycle occurs if dependsOnTaskId already transitively depends on taskId.
17
+ */
18
+ export function detectDependencyCycle(existingDependencies, newDependency) {
19
+ const { taskId, dependsOnTaskId } = newDependency;
20
+ // Self-dependency check
21
+ if (taskId === dependsOnTaskId) {
22
+ return { hasCycle: true, cyclePath: [taskId, taskId] };
23
+ }
24
+ // Build adjacency list: node -> array of nodes it depends on
25
+ const adj = new Map();
26
+ for (const dep of existingDependencies) {
27
+ const targets = adj.get(dep.taskId) || [];
28
+ targets.push(dep.dependsOnTaskId);
29
+ adj.set(dep.taskId, targets);
30
+ }
31
+ // Check if dependsOnTaskId can reach taskId via existing dependency paths
32
+ const visited = new Set();
33
+ const path = [taskId, dependsOnTaskId];
34
+ function dfs(current) {
35
+ if (current === taskId) {
36
+ return true;
37
+ }
38
+ if (visited.has(current)) {
39
+ return false;
40
+ }
41
+ visited.add(current);
42
+ const neighbors = adj.get(current) || [];
43
+ for (const next of neighbors) {
44
+ path.push(next);
45
+ if (dfs(next)) {
46
+ return true;
47
+ }
48
+ path.pop();
49
+ }
50
+ return false;
51
+ }
52
+ const hasCycle = dfs(dependsOnTaskId);
53
+ return {
54
+ hasCycle,
55
+ cyclePath: hasCycle ? path : undefined
56
+ };
57
+ }
58
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/domain/graph.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChC,MAAM,CAAS;IACf,eAAe,CAAS;IACxB,SAAS,CAAY;IAErC,YAAY,MAAc,EAAE,eAAuB,EAAE,SAAoB;QACvE,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,qBAAqB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,KAAK,CAAC,+BAA+B,MAAM,SAAS,eAAe,wDAAwD,OAAO,GAAG,CAAC,CAAC;QACvI,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,oBAAsC,EACtC,aAA0D;IAE1D,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,GAAG,aAAa,CAAC;IAElD,wBAAwB;IACxB,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;QAC/B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACzD,CAAC;IAED,6DAA6D;IAC7D,MAAM,GAAG,GAAG,IAAI,GAAG,EAAoB,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAClC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC;IAED,0EAA0E;IAC1E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,IAAI,GAAa,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAEjD,SAAS,GAAG,CAAC,OAAe;QAC1B,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAErB,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACzC,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACd,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,CAAC,GAAG,EAAE,CAAC;QACb,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC;IACtC,OAAO;QACL,QAAQ;QACR,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;KACvC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './events.js';
2
+ export * from './custom-fields.js';
3
+ export * from './graph.js';
4
+ export * from './entities.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './events.js';
2
+ export * from './custom-fields.js';
3
+ export * from './graph.js';
4
+ export * from './entities.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC"}
@@ -1,10 +1,12 @@
1
- import type { CriticalPathConfig, Project, Task, TaskDependencyGraph, Team, TaskContainer, Iteration, Workflow } from '../types/index.js';
1
+ import type { CriticalPathConfig, Project, Task, TaskDependency, TaskDependencyGraph, Team, TaskContainer, Iteration, Comment, TimeEntry, Workflow, CreateTaskInput } from '../types/index.js';
2
2
  import { StorageAdapter } from '../store/index.js';
3
3
  import { PluginRegistry } from '../plugins/index.js';
4
4
  import { type TaskLifecycleState } from '../utils/status.js';
5
+ import { DomainEventBus } from '../domain/events.js';
5
6
  export declare class CriticalPathEngine {
6
7
  readonly store: StorageAdapter;
7
8
  readonly plugins: PluginRegistry;
9
+ readonly events: DomainEventBus;
8
10
  constructor(config?: CriticalPathConfig);
9
11
  private seedInitialData;
10
12
  getWorkflows(): Promise<Workflow[]>;
@@ -17,13 +19,19 @@ export declare class CriticalPathEngine {
17
19
  getProjects(): Promise<Project[]>;
18
20
  getProject(id: string): Promise<Project | null>;
19
21
  createProject(project: Omit<Project, 'id' | 'createdAt' | 'updatedAt'>): Promise<Project>;
22
+ updateProject(id: string, updates: Partial<Project>): Promise<Project | null>;
20
23
  getTasks(projectId?: string): Promise<Task[]>;
21
24
  getTask(id: string): Promise<Task | null>;
22
- createTask(taskInput: Omit<Task, 'id' | 'createdAt' | 'updatedAt'>): Promise<Task>;
25
+ createTask(taskInput: CreateTaskInput): Promise<Task>;
23
26
  updateTask(id: string, updates: Partial<Task>): Promise<Task | null>;
24
27
  deleteTask(id: string): Promise<boolean>;
28
+ addDependency(dep: Omit<TaskDependency, 'id'>): Promise<TaskDependency>;
25
29
  getTaskDependencyGraph(taskId: string): Promise<TaskDependencyGraph>;
26
30
  getTaskLifecycleState(taskId: string): Promise<TaskLifecycleState | null>;
31
+ logTime(entry: Omit<TimeEntry, 'id' | 'loggedAt' | 'userId'> & {
32
+ userId?: string;
33
+ }): Promise<TimeEntry>;
34
+ addComment(comment: Omit<Comment, 'id' | 'createdAt' | 'updatedAt'>): Promise<Comment>;
27
35
  getTeams(): Promise<Team[]>;
28
36
  getTeam(id: string): Promise<Team | null>;
29
37
  createTeam(team: Omit<Team, 'id' | 'createdAt' | 'updatedAt'>): Promise<Team>;