@critical-path/core 0.21.0 → 0.23.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 (55) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +14 -0
  3. package/dist/domain/ddd.test.js +12 -0
  4. package/dist/domain/ddd.test.js.map +1 -1
  5. package/dist/domain/entities.d.ts.map +1 -1
  6. package/dist/domain/entities.js +3 -2
  7. package/dist/domain/entities.js.map +1 -1
  8. package/dist/domain/errors.d.ts +13 -0
  9. package/dist/domain/errors.d.ts.map +1 -0
  10. package/dist/domain/errors.js +19 -0
  11. package/dist/domain/errors.js.map +1 -0
  12. package/dist/domain/events.d.ts +9 -1
  13. package/dist/domain/events.d.ts.map +1 -1
  14. package/dist/domain/events.js.map +1 -1
  15. package/dist/domain/index.d.ts +1 -0
  16. package/dist/domain/index.d.ts.map +1 -1
  17. package/dist/domain/index.js +1 -0
  18. package/dist/domain/index.js.map +1 -1
  19. package/dist/engine/actor.test.d.ts +2 -0
  20. package/dist/engine/actor.test.d.ts.map +1 -0
  21. package/dist/engine/actor.test.js +53 -0
  22. package/dist/engine/actor.test.js.map +1 -0
  23. package/dist/engine/index.d.ts +23 -1
  24. package/dist/engine/index.d.ts.map +1 -1
  25. package/dist/engine/index.js +125 -29
  26. package/dist/engine/index.js.map +1 -1
  27. package/dist/index.test.js +20 -0
  28. package/dist/index.test.js.map +1 -1
  29. package/dist/store/sqlite.d.ts.map +1 -1
  30. package/dist/store/sqlite.js +5 -1
  31. package/dist/store/sqlite.js.map +1 -1
  32. package/dist/store/sqlite.test.js +20 -0
  33. package/dist/store/sqlite.test.js.map +1 -1
  34. package/dist/types/index.d.ts +7 -1
  35. package/dist/types/index.d.ts.map +1 -1
  36. package/dist/utils/fractional-index.d.ts.map +1 -1
  37. package/dist/utils/fractional-index.js +22 -26
  38. package/dist/utils/fractional-index.js.map +1 -1
  39. package/dist/utils/fractional-index.test.js +31 -0
  40. package/dist/utils/fractional-index.test.js.map +1 -1
  41. package/package.json +1 -5
  42. package/src/domain/ddd.test.ts +22 -0
  43. package/src/domain/entities.ts +3 -2
  44. package/src/domain/errors.ts +19 -0
  45. package/src/domain/events.ts +6 -0
  46. package/src/domain/index.ts +1 -0
  47. package/src/engine/actor.test.ts +62 -0
  48. package/src/engine/index.ts +134 -30
  49. package/src/index.test.ts +24 -0
  50. package/src/store/sqlite.test.ts +22 -0
  51. package/src/store/sqlite.ts +7 -1
  52. package/src/types/index.ts +8 -0
  53. package/src/utils/fractional-index.test.ts +37 -0
  54. package/src/utils/fractional-index.ts +20 -26
  55. package/tsconfig.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { DomainEventBus } from '../domain/events.js';
7
7
  import { validateAttachmentUrl } from '../domain/entities.js';
8
8
  import { validateCustomFieldValues } from '../domain/custom-fields.js';
9
9
  import { detectDependencyCycle, CircularDependencyError } from '../domain/graph.js';
10
+ import { ValidationError, NotFoundError } from '../domain/errors.js';
10
11
  import { calculateCPM } from '../domain/cpm.js';
11
12
  import { buildTimelineLadder, aggregateConcreteEvidenceForTask } from '../domain/ladder.js';
12
13
  import { calculateTaskMetrics, reconstructTaskProgressHistory } from '../domain/metrics.js';
@@ -18,6 +19,8 @@ export class CriticalPathEngine {
18
19
  plugins;
19
20
  events;
20
21
  ready = Promise.resolve();
22
+ /** The identity mutations are attributed to. Set only on views returned by `withActor`. */
23
+ actor;
21
24
  constructor(config = {}) {
22
25
  this.config = config;
23
26
  this.store = typeof config.store === 'object' && config.store !== null
@@ -35,6 +38,21 @@ export class CriticalPathEngine {
35
38
  this.ready = this.seedInitialData(config.initialData);
36
39
  }
37
40
  }
41
+ /**
42
+ * Returns a view of this engine that attributes every mutation to `actor`: activity log
43
+ * entries, comment authors, reactions, time entries, attachment uploaders and task reporters.
44
+ * Identity fields supplied in payloads are ignored on the view, so callers cannot claim to be
45
+ * someone else. The view shares the store, plugins and event bus, and does not modify this engine,
46
+ * so it is safe to create one per request.
47
+ */
48
+ withActor(actor) {
49
+ const scoped = Object.create(this);
50
+ Object.defineProperty(scoped, 'actor', { value: Object.freeze({ ...actor }), enumerable: true });
51
+ return scoped;
52
+ }
53
+ actorIdOr(fallback) {
54
+ return this.actor?.userId ?? fallback;
55
+ }
38
56
  async seedInitialData(data) {
39
57
  if (data.workflows) {
40
58
  for (const wf of data.workflows) {
@@ -92,7 +110,7 @@ export class CriticalPathEngine {
92
110
  };
93
111
  await this.events.publish(event);
94
112
  await this.store.logActivity({
95
- actorId: 'system',
113
+ actorId: this.actorIdOr('system'),
96
114
  action: 'workflow.created',
97
115
  details: { name: created.name }
98
116
  });
@@ -116,7 +134,7 @@ export class CriticalPathEngine {
116
134
  };
117
135
  await this.events.publish(event);
118
136
  await this.store.logActivity({
119
- actorId: 'system',
137
+ actorId: this.actorIdOr('system'),
120
138
  action: 'workflow.updated',
121
139
  details: { name: updated.name }
122
140
  });
@@ -141,7 +159,7 @@ export class CriticalPathEngine {
141
159
  };
142
160
  await this.events.publish(event);
143
161
  await this.store.logActivity({
144
- actorId: 'system',
162
+ actorId: this.actorIdOr('system'),
145
163
  action: 'workflow.deleted',
146
164
  details: { name: existing.name }
147
165
  });
@@ -208,7 +226,7 @@ export class CriticalPathEngine {
208
226
  await this.events.publish(event);
209
227
  await this.store.logActivity({
210
228
  projectId: created.id,
211
- actorId: project.ownerId || 'system',
229
+ actorId: this.actorIdOr(project.ownerId || 'system'),
212
230
  action: 'project.created',
213
231
  details: { name: created.name, key: created.key }
214
232
  });
@@ -233,7 +251,7 @@ export class CriticalPathEngine {
233
251
  await this.events.publish(event);
234
252
  await this.store.logActivity({
235
253
  projectId: updated.id,
236
- actorId: 'system',
254
+ actorId: this.actorIdOr('system'),
237
255
  action: 'project.updated',
238
256
  details: { name: updated.name }
239
257
  });
@@ -241,6 +259,43 @@ export class CriticalPathEngine {
241
259
  }
242
260
  return updated;
243
261
  }
262
+ /**
263
+ * Deletes a project and its tasks. Each task goes through `deleteTask`, so plugin
264
+ * hooks run and `task.deleted` events fire before `project.deleted` is published.
265
+ */
266
+ async deleteProject(id) {
267
+ const existing = await this.store.getProject(id);
268
+ if (!existing)
269
+ return false;
270
+ const tasks = await this.store.getTasks(id);
271
+ const deletedTaskIds = [];
272
+ for (const task of tasks) {
273
+ if (await this.deleteTask(task.id)) {
274
+ deletedTaskIds.push(task.id);
275
+ }
276
+ }
277
+ const deleted = await this.store.deleteProject(id);
278
+ if (deleted) {
279
+ const now = new Date().toISOString();
280
+ const event = {
281
+ id: `evt_${Math.random().toString(36).substring(2, 9)}`,
282
+ name: 'project.deleted',
283
+ aggregateId: id,
284
+ aggregateType: 'Project',
285
+ occurredAt: now,
286
+ payload: { projectId: id, name: existing.name, deletedTaskIds }
287
+ };
288
+ await this.events.publish(event);
289
+ await this.store.logActivity({
290
+ projectId: id,
291
+ actorId: this.actorIdOr('system'),
292
+ action: 'project.deleted',
293
+ details: { name: existing.name, deletedTaskCount: deletedTaskIds.length }
294
+ });
295
+ this.dispatchWebhook('project.deleted', { projectId: id, name: existing.name, deletedTaskIds });
296
+ }
297
+ return deleted;
298
+ }
244
299
  // --- Tasks ---
245
300
  async getTasks(projectId) {
246
301
  return this.store.getTasks(projectId);
@@ -249,6 +304,9 @@ export class CriticalPathEngine {
249
304
  return this.store.getTask(id);
250
305
  }
251
306
  async createTask(taskInput) {
307
+ if (this.actor && !taskInput.reporterId) {
308
+ taskInput = { ...taskInput, reporterId: this.actor.userId };
309
+ }
252
310
  const processedInput = await this.plugins.runBeforeTaskCreate(taskInput);
253
311
  const projectId = processedInput.projectId || taskInput.projectId;
254
312
  const project = await this.store.getProject(projectId);
@@ -323,7 +381,7 @@ export class CriticalPathEngine {
323
381
  await this.store.logActivity({
324
382
  projectId: created.projectId,
325
383
  taskId: created.id,
326
- actorId: created.reporterId || 'system',
384
+ actorId: this.actorIdOr(created.reporterId || 'system'),
327
385
  action: 'task.created',
328
386
  details: { title: created.title, status: created.status }
329
387
  });
@@ -334,22 +392,26 @@ export class CriticalPathEngine {
334
392
  const existing = await this.store.getTask(id);
335
393
  if (!existing)
336
394
  return null;
395
+ // On a withActor view, the scoped actor replaces any identity claimed in the payload.
396
+ // Explicit options from trusted server-side code still take precedence.
397
+ options = options ?? (this.actor ? { actor: this.actor } : undefined);
398
+ const claimed = this.actor ? undefined : updates;
337
399
  const actorId = options?.actorId ||
338
- updates.actorId ||
400
+ claimed?.actorId ||
339
401
  options?.actor?.userId ||
340
- updates.actor?.userId ||
402
+ claimed?.actor?.userId ||
341
403
  'system';
342
404
  const actorName = options?.actorName ||
343
- updates.actorName ||
405
+ claimed?.actorName ||
344
406
  options?.actor?.username ||
345
- updates.actor?.username ||
407
+ claimed?.actor?.username ||
346
408
  (actorId === 'system' ? 'System' : undefined);
347
409
  const actorType = options?.actorType ||
348
- updates.actorType ||
410
+ claimed?.actorType ||
349
411
  options?.actor?.actorType ||
350
- updates.actor?.actorType ||
412
+ claimed?.actor?.actorType ||
351
413
  (actorId === 'system' ? 'system' : 'user');
352
- const actorObj = options?.actor || updates.actor || {
414
+ const actorObj = options?.actor || claimed?.actor || {
353
415
  userId: actorId,
354
416
  username: actorName,
355
417
  actorType
@@ -688,7 +750,7 @@ export class CriticalPathEngine {
688
750
  await this.store.logActivity({
689
751
  projectId: downstream.projectId,
690
752
  taskId: downstream.id,
691
- actorId: 'system',
753
+ actorId: this.actorIdOr('system'),
692
754
  action: 'task.unblocked',
693
755
  details: { unblockedByTaskId: completedTask.id }
694
756
  });
@@ -728,7 +790,7 @@ export class CriticalPathEngine {
728
790
  await this.store.logActivity({
729
791
  projectId: existing.projectId,
730
792
  taskId: id,
731
- actorId: 'system',
793
+ actorId: this.actorIdOr('system'),
732
794
  action: 'task.deleted',
733
795
  details: { title: existing.title }
734
796
  });
@@ -738,13 +800,9 @@ export class CriticalPathEngine {
738
800
  }
739
801
  // --- Task Dependencies & Graph ---
740
802
  async addDependency(dep) {
741
- const existingDependencies = await this.store.getDependencies(dep.taskId);
742
- const allProjectDeps = [
743
- ...existingDependencies,
744
- ...(await this.store.getDependencies(dep.dependsOnTaskId))
745
- ];
746
803
  // Enforce Directed Acyclic Graph (DAG) Invariant
747
- const cycleCheck = detectDependencyCycle(allProjectDeps, dep);
804
+ const reachableDeps = await this.collectUpstreamDependencies(dep.dependsOnTaskId);
805
+ const cycleCheck = detectDependencyCycle(reachableDeps, dep);
748
806
  if (cycleCheck.hasCycle) {
749
807
  throw new CircularDependencyError(dep.taskId, dep.dependsOnTaskId, cycleCheck.cyclePath);
750
808
  }
@@ -761,6 +819,34 @@ export class CriticalPathEngine {
761
819
  await this.events.publish(event);
762
820
  return created;
763
821
  }
822
+ /**
823
+ * Collects every dependency edge reachable upstream from `startTaskId`. A new edge
824
+ * `taskId -> dependsOnTaskId` creates a cycle exactly when `taskId` is reachable from
825
+ * `dependsOnTaskId`, so this is the full set of edges the cycle check needs.
826
+ */
827
+ async collectUpstreamDependencies(startTaskId) {
828
+ const edges = new Map();
829
+ const visited = new Set();
830
+ let frontier = [startTaskId];
831
+ while (frontier.length > 0) {
832
+ const next = [];
833
+ const results = await Promise.all(frontier.map((id) => this.store.getDependencies(id)));
834
+ frontier.forEach((id) => visited.add(id));
835
+ for (const deps of results) {
836
+ for (const d of deps) {
837
+ // getDependencies returns edges in both directions; follow only outgoing ones.
838
+ if (!visited.has(d.taskId))
839
+ continue;
840
+ edges.set(d.id, d);
841
+ if (!visited.has(d.dependsOnTaskId) && !next.includes(d.dependsOnTaskId)) {
842
+ next.push(d.dependsOnTaskId);
843
+ }
844
+ }
845
+ }
846
+ frontier = next;
847
+ }
848
+ return Array.from(edges.values());
849
+ }
764
850
  async getTaskDependencyGraph(taskId) {
765
851
  const dependencies = await this.store.getDependencies(taskId);
766
852
  const upstreamTaskIds = new Set();
@@ -800,8 +886,8 @@ export class CriticalPathEngine {
800
886
  }
801
887
  // --- Time Tracking ---
802
888
  async logTime(entry) {
803
- if (entry.hours <= 0) {
804
- throw new Error('Logged hours must be a positive number.');
889
+ if (!Number.isFinite(entry.hours) || entry.hours <= 0) {
890
+ throw new ValidationError('Logged hours must be a positive number.');
805
891
  }
806
892
  const task = await this.store.getTask(entry.taskId);
807
893
  if (task) {
@@ -816,7 +902,7 @@ export class CriticalPathEngine {
816
902
  }
817
903
  const fullEntry = {
818
904
  ...entry,
819
- userId: entry.userId || task?.assigneeId || 'system',
905
+ userId: this.actor?.userId || entry.userId || task?.assigneeId || 'system',
820
906
  loggedAt: entry.loggedAt
821
907
  };
822
908
  const created = await this.store.logTime(fullEntry);
@@ -840,6 +926,9 @@ export class CriticalPathEngine {
840
926
  return this.store.getComment(id);
841
927
  }
842
928
  async addComment(comment) {
929
+ if (this.actor) {
930
+ comment = { ...comment, authorId: this.actor.userId, authorType: this.actor.actorType ?? 'user' };
931
+ }
843
932
  const mentions = comment.mentions ?? extractMentions(comment.content);
844
933
  const created = await this.store.addComment({ ...comment, mentions });
845
934
  const now = new Date().toISOString();
@@ -898,6 +987,8 @@ export class CriticalPathEngine {
898
987
  return deleted;
899
988
  }
900
989
  async addCommentReaction(commentId, reaction) {
990
+ if (this.actor)
991
+ reaction = { ...reaction, userId: this.actor.userId };
901
992
  const existing = await this.store.getComment(commentId);
902
993
  if (!existing)
903
994
  return null;
@@ -941,6 +1032,8 @@ export class CriticalPathEngine {
941
1032
  return updated;
942
1033
  }
943
1034
  async removeCommentReaction(commentId, reaction) {
1035
+ if (this.actor)
1036
+ reaction = { ...reaction, userId: this.actor.userId };
944
1037
  const existing = await this.store.getComment(commentId);
945
1038
  if (!existing)
946
1039
  return null;
@@ -979,6 +1072,9 @@ export class CriticalPathEngine {
979
1072
  return this.store.getAttachment(id);
980
1073
  }
981
1074
  async createAttachment(attachment) {
1075
+ if (this.actor) {
1076
+ attachment = { ...attachment, uploaderId: this.actor.userId, uploaderType: this.actor.actorType ?? 'user' };
1077
+ }
982
1078
  validateAttachmentUrl(attachment.url);
983
1079
  const created = await this.store.createAttachment(attachment);
984
1080
  const now = new Date().toISOString();
@@ -1050,7 +1146,7 @@ export class CriticalPathEngine {
1050
1146
  async readAttachmentText(id) {
1051
1147
  const attachment = await this.getAttachment(id);
1052
1148
  if (!attachment) {
1053
- throw new Error(`Attachment with id "${id}" not found.`);
1149
+ throw new NotFoundError(`Attachment with id "${id}" not found.`);
1054
1150
  }
1055
1151
  if (attachment.storageKey && this.fileStorage && typeof this.fileStorage.download === 'function') {
1056
1152
  const bytes = await this.fileStorage.download(attachment.storageKey);
@@ -1167,7 +1263,7 @@ export class CriticalPathEngine {
1167
1263
  await this.events.publish(event);
1168
1264
  await this.store.logActivity({
1169
1265
  projectId: created.projectId,
1170
- actorId: 'system',
1266
+ actorId: this.actorIdOr('system'),
1171
1267
  action: 'deliverable.created',
1172
1268
  details: { title: created.title, format: created.format }
1173
1269
  });
@@ -1215,7 +1311,7 @@ export class CriticalPathEngine {
1215
1311
  await this.events.publish(updateEvent);
1216
1312
  await this.store.logActivity({
1217
1313
  projectId: updated.projectId,
1218
- actorId: 'system',
1314
+ actorId: this.actorIdOr('system'),
1219
1315
  action: 'deliverable.updated',
1220
1316
  details: { title: updated.title, status: updated.status }
1221
1317
  });
@@ -1241,7 +1337,7 @@ export class CriticalPathEngine {
1241
1337
  await this.events.publish(event);
1242
1338
  await this.store.logActivity({
1243
1339
  projectId: existing.projectId,
1244
- actorId: 'system',
1340
+ actorId: this.actorIdOr('system'),
1245
1341
  action: 'deliverable.deleted',
1246
1342
  details: { title: existing.title }
1247
1343
  });
@@ -1376,7 +1472,7 @@ export class CriticalPathEngine {
1376
1472
  async getTimelineLadder(projectId, options = {}) {
1377
1473
  const project = await this.store.getProject(projectId);
1378
1474
  if (!project) {
1379
- throw new Error(`Project with ID "${projectId}" not found.`);
1475
+ throw new NotFoundError(`Project with ID "${projectId}" not found.`);
1380
1476
  }
1381
1477
  let tasks = await this.store.getTasks(projectId);
1382
1478
  if (options.containerId) {