@outbuild-company/schedule-core 1.10.4 → 1.12.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.
package/dist/index.js CHANGED
@@ -1,3 +1,679 @@
1
+ // src/types.ts
2
+ var WORK_TIME_DIRECTION = {
3
+ FUTURE: "future",
4
+ PAST: "past"
5
+ };
6
+ var CALENDAR_UNIT = {
7
+ HOUR: "hour",
8
+ DAY: "day"
9
+ };
10
+ var ACTIVITY_PONDERATOR_CRITERION = {
11
+ DURATION: "DURATION",
12
+ COST: "COST",
13
+ WORK_HOURS: "HH"
14
+ };
15
+ var STATUS_CRITERIA = {
16
+ BASELINE: "Baseline",
17
+ ACTUAL: "Actual"
18
+ };
19
+ var STATUS = {
20
+ DONE: "Done",
21
+ OVERDUE: "Overdue",
22
+ ADVANCEMENT: "Advancement",
23
+ WAITING: "Waiting",
24
+ DOING: "Doing"
25
+ };
26
+
27
+ // src/constraints/index.ts
28
+ var CONSTRAINT_TYPE = {
29
+ ASAP: "asap",
30
+ ALAP: "alap",
31
+ SNET: "snet",
32
+ SNLT: "snlt",
33
+ FNET: "fnet",
34
+ FNLT: "fnlt",
35
+ MSO: "mso",
36
+ MFO: "mfo"
37
+ };
38
+ var VIOLATION_RULES = {
39
+ mso: () => true,
40
+ mfo: () => true,
41
+ snlt: (constraint, projected) => constraint < projected,
42
+ snet: (constraint, projected) => constraint > projected,
43
+ fnlt: (constraint, projected) => constraint < projected,
44
+ fnet: (constraint, projected) => constraint > projected
45
+ };
46
+ function checkConstraintViolation(constraintType, constraintDate, projectedDate) {
47
+ if (!constraintDate) return { violated: false };
48
+ const rule = VIOLATION_RULES[constraintType];
49
+ if (!rule) return { violated: false };
50
+ if (rule(constraintDate, projectedDate)) {
51
+ return { violated: true, constraintType, constraintDate };
52
+ }
53
+ return { violated: false };
54
+ }
55
+ var START_BASED_CONSTRAINTS = /* @__PURE__ */ new Set([
56
+ "mso",
57
+ "snet",
58
+ "snlt"
59
+ ]);
60
+ function pickProjectedDateForConstraint(constraintType, projectedStart, projectedEnd) {
61
+ return START_BASED_CONSTRAINTS.has(constraintType) ? projectedStart : projectedEnd;
62
+ }
63
+ function buildConstraintNotification(constraintType, constraintDate, projectedDate) {
64
+ return {
65
+ type: "constraint",
66
+ messageKey: "constraint_violation",
67
+ data: {
68
+ constraintType,
69
+ constraintDate,
70
+ ...projectedDate ? { projectedDate } : {}
71
+ }
72
+ };
73
+ }
74
+ var CONSTRAINT_CASES = {
75
+ snet: { startOfDay: true, direction: WORK_TIME_DIRECTION.FUTURE },
76
+ snlt: { startOfDay: true, direction: WORK_TIME_DIRECTION.PAST },
77
+ fnet: { startOfDay: false, direction: WORK_TIME_DIRECTION.FUTURE },
78
+ fnlt: { startOfDay: false, direction: WORK_TIME_DIRECTION.PAST },
79
+ mso: { startOfDay: true, direction: WORK_TIME_DIRECTION.FUTURE },
80
+ mfo: { startOfDay: false, direction: WORK_TIME_DIRECTION.PAST }
81
+ };
82
+ var startOfUtcDay = (d) => new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
83
+ var addUtcDays = (d, n) => new Date(d.getTime() + n * 864e5);
84
+ var sameUtcDay = (a, b) => a.getUTCFullYear() === b.getUTCFullYear() && a.getUTCMonth() === b.getUTCMonth() && a.getUTCDate() === b.getUTCDate();
85
+ function getEffectiveConstraintDate(activity, adapter) {
86
+ if (!activity.constraintDate || !activity.constraintType) return null;
87
+ const config = CONSTRAINT_CASES[activity.constraintType];
88
+ if (!config) return activity.constraintDate;
89
+ const cd = activity.constraintDate;
90
+ const firstWorkOfDay = adapter.getClosestWorkTime({
91
+ date: startOfUtcDay(cd),
92
+ dir: WORK_TIME_DIRECTION.FUTURE,
93
+ task: activity
94
+ });
95
+ if (sameUtcDay(firstWorkOfDay, cd)) {
96
+ if (cd.getTime() !== startOfUtcDay(cd).getTime()) return cd;
97
+ if (config.startOfDay) return firstWorkOfDay;
98
+ return adapter.getClosestWorkTime({
99
+ date: addUtcDays(startOfUtcDay(cd), 1),
100
+ dir: WORK_TIME_DIRECTION.PAST,
101
+ task: activity
102
+ });
103
+ }
104
+ const effectiveMidnight = startOfUtcDay(
105
+ adapter.getClosestWorkTime({
106
+ date: cd,
107
+ dir: config.direction,
108
+ task: activity
109
+ })
110
+ );
111
+ if (config.startOfDay) {
112
+ return adapter.getClosestWorkTime({
113
+ date: effectiveMidnight,
114
+ dir: WORK_TIME_DIRECTION.FUTURE,
115
+ task: activity
116
+ });
117
+ }
118
+ return adapter.getClosestWorkTime({
119
+ date: addUtcDays(effectiveMidnight, 1),
120
+ dir: WORK_TIME_DIRECTION.PAST,
121
+ task: activity
122
+ });
123
+ }
124
+ function computeConstraintBounds(activity, adapter) {
125
+ const empty = {
126
+ earliestStart: null,
127
+ latestStart: null,
128
+ earliestEnd: null,
129
+ latestEnd: null
130
+ };
131
+ const type = activity.constraintType;
132
+ if (!type || type === "asap" || type === "alap") return empty;
133
+ const constraintDate = getEffectiveConstraintDate(activity, adapter);
134
+ if (!constraintDate) return empty;
135
+ const endFromStart = (start) => adapter.calculateEndDate({
136
+ startDate: start,
137
+ durationHours: activity.durationHours,
138
+ task: activity
139
+ });
140
+ const startFromEnd = (end) => adapter.calculateEndDate({
141
+ startDate: end,
142
+ durationHours: -activity.durationHours,
143
+ task: activity
144
+ });
145
+ switch (type) {
146
+ case "snet":
147
+ return {
148
+ earliestStart: constraintDate,
149
+ latestStart: null,
150
+ earliestEnd: endFromStart(constraintDate),
151
+ latestEnd: null
152
+ };
153
+ case "snlt":
154
+ return {
155
+ earliestStart: null,
156
+ latestStart: constraintDate,
157
+ earliestEnd: null,
158
+ latestEnd: endFromStart(constraintDate)
159
+ };
160
+ case "fnet":
161
+ return {
162
+ earliestStart: startFromEnd(constraintDate),
163
+ latestStart: null,
164
+ earliestEnd: constraintDate,
165
+ latestEnd: null
166
+ };
167
+ case "fnlt":
168
+ return {
169
+ earliestStart: null,
170
+ latestStart: startFromEnd(constraintDate),
171
+ earliestEnd: null,
172
+ latestEnd: constraintDate
173
+ };
174
+ case "mso": {
175
+ const end = endFromStart(constraintDate);
176
+ return {
177
+ earliestStart: constraintDate,
178
+ latestStart: constraintDate,
179
+ earliestEnd: end,
180
+ latestEnd: end
181
+ };
182
+ }
183
+ case "mfo": {
184
+ const start = startFromEnd(constraintDate);
185
+ return {
186
+ earliestStart: start,
187
+ latestStart: start,
188
+ earliestEnd: constraintDate,
189
+ latestEnd: constraintDate
190
+ };
191
+ }
192
+ default:
193
+ return empty;
194
+ }
195
+ }
196
+ function isStartWithinBounds(start, bounds) {
197
+ if (bounds.earliestStart && start < bounds.earliestStart) return false;
198
+ if (bounds.latestStart && start > bounds.latestStart) return false;
199
+ return true;
200
+ }
201
+ function clampStartToBounds(candidate, bounds) {
202
+ if (bounds.latestStart && candidate > bounds.latestStart) {
203
+ return bounds.latestStart;
204
+ }
205
+ if (bounds.earliestStart && candidate < bounds.earliestStart) {
206
+ return bounds.earliestStart;
207
+ }
208
+ return candidate;
209
+ }
210
+
211
+ // src/autoscheduler/types.ts
212
+ var LINK_TYPE = {
213
+ FINISH_TO_START: "0",
214
+ START_TO_START: "1",
215
+ FINISH_TO_FINISH: "2",
216
+ START_TO_FINISH: "3"
217
+ };
218
+
219
+ // src/constants/columns.ts
220
+ var EDITABLE = {
221
+ TEXT: "text",
222
+ DESCRIPTION: "description",
223
+ DURATION: "duration",
224
+ PROGRESS: "progress",
225
+ COST: "cost",
226
+ USED_COST: "used_cost",
227
+ HH_WORK_TIME: "hhWorkTime",
228
+ START_DATE: "start_date",
229
+ END_DATE: "end_date",
230
+ CONSTRAINT_TYPE: "constraint_type",
231
+ CONSTRAINT_DATE: "constraint_date",
232
+ CALENDAR_ID: "calendar_id",
233
+ CUSTOM_ID: "custom_id",
234
+ SUBCONTRACT_ID: "subcontractId",
235
+ RESPONSABLES: "responsables",
236
+ TAGS: "tags",
237
+ CUSTOM_PREDECESSORS: "custom_predecessors",
238
+ CUSTOM_SUCESSORS: "custom_sucessors"
239
+ };
240
+ var READ_ONLY = {
241
+ REAL_WORK: "real_work",
242
+ REAL_COST: "real_cost",
243
+ EXPECTED_PROGRESS: "expected_progress",
244
+ EXPECTED_PROGRESS_BASE: "expected_progress_base",
245
+ START_BASE: "start_base",
246
+ END_BASE: "end_base",
247
+ DURATION_BASE: "duration_base",
248
+ COST_BASE: "cost_base",
249
+ WORK_BASE: "work_base",
250
+ CALENDAR_DURATION: "calendarDuration",
251
+ IS_CRITICAL: "is_critical",
252
+ EARLY_START: "earlyStart",
253
+ EARLY_FINISH: "earlyFinish",
254
+ LATE_START: "lateStart",
255
+ LATE_FINISH: "lateFinish",
256
+ FREE_SLACK: "freeSlack",
257
+ TOTAL_SLACK: "totalSlack",
258
+ CORRELATIVE_ID: "correlative_id",
259
+ UNIQUE_CORRELATIVE_ID: "unique_correlative_id",
260
+ PONDERATOR: "ponderator",
261
+ STATUS: "status"
262
+ };
263
+ var COLUMN = { ...EDITABLE, ...READ_ONLY };
264
+
265
+ // src/autoscheduler/links/types.ts
266
+ var LINK_OPERATION_KIND = {
267
+ CREATE: "create",
268
+ UPDATE: "update",
269
+ DELETE: "delete"
270
+ };
271
+ var LINK_REJECTION_REASON = {
272
+ SELF_LINK: "self-link",
273
+ CYCLE: "cycle",
274
+ DUPLICATE: "duplicate",
275
+ ACTIVITY_MISSING: "activity-missing",
276
+ LINK_MISSING: "link-missing",
277
+ HIERARCHY_LINK: "hierarchy-link"
278
+ };
279
+
280
+ // src/dispatch/action-kinds.ts
281
+ var DISPATCH_ACTION_KIND = {
282
+ ACTIVITY_CLIPBOARD_CLEAR: "activity-clipboard-clear",
283
+ ACTIVITY_COPY: "activity-copy",
284
+ CALENDAR_RECONCILE: "calendar-reconcile",
285
+ ACTIVITY_PASTE_COPIED: "activity-paste-copied",
286
+ PERSISTENCE_ACKNOWLEDGE: "persistence-acknowledge",
287
+ BASELINE_APPLY: "baseline-apply",
288
+ PONDERATOR_CRITERION_SET: "ponderator-criterion-set",
289
+ STATUS_CRITERIA_SET: "status-criteria-set",
290
+ INLINE_EDIT: "inline-edit",
291
+ DATES_BATCH: "dates-batch",
292
+ BULK_EDIT: "bulk-edit",
293
+ LINK_CREATE: "link-create",
294
+ LINK_UPDATE: "link-update",
295
+ LINK_DELETE: "link-delete",
296
+ LINKS_BATCH: "links-batch",
297
+ ACTIVITY_CREATE: "activity-create",
298
+ ACTIVITY_DELETE: "activity-delete",
299
+ ACTIVITY_MOVE: "activity-move",
300
+ ACTIVITY_INDENT: "activity-indent",
301
+ ACTIVITY_OUTDENT: "activity-outdent",
302
+ ACTIVITY_SET_PROGRESS: "activity-set-progress",
303
+ SELECTION_TOGGLE: "selection-toggle",
304
+ SELECTION_REPLACE: "selection-replace",
305
+ VISIBILITY_SET: "visibility-set",
306
+ FILTER_SET: "filter-set",
307
+ SORT_SET: "sort-set",
308
+ SIR_SYNC: "sir-sync",
309
+ ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync"
310
+ };
311
+ var ACTIVITY_BATCH_ACTION_KIND = "activity-batch";
312
+ var DISPATCH_LINK_OPERATION_KIND = LINK_OPERATION_KIND;
313
+ var DISPATCH_ACTION_KINDS = Object.values(DISPATCH_ACTION_KIND);
314
+
315
+ // src/propagations/shared/get-active-baseline.ts
316
+ function getActiveBaseline(activity) {
317
+ const points = activity?.baselinePoints;
318
+ if (!Array.isArray(points) || points.length === 0) return null;
319
+ return points.find((point) => point.isActiveVersion) ?? null;
320
+ }
321
+
322
+ // src/api/types.ts
323
+ var ACTIVITY_FIELD = {
324
+ NAME: "name",
325
+ DESCRIPTION: "description",
326
+ DURATION_DAYS: "durationDays",
327
+ PROGRESS: "progress",
328
+ COST: "cost",
329
+ USED_COST: "usedCost",
330
+ WORK_HOURS: "workHours",
331
+ START_DATE: "startDate",
332
+ END_DATE: "endDate",
333
+ CONSTRAINT_TYPE: "constraintType",
334
+ CONSTRAINT_DATE: "constraintDate",
335
+ CALENDAR_ID: "calendarId",
336
+ CUSTOM_ID: "customId",
337
+ SUBCONTRACT_ID: "subcontractId",
338
+ RESPONSABLE_IDS: "responsableIds",
339
+ TAG_IDS: "tagIds"
340
+ };
341
+ var ACTIVITY_DATE_EDGE = {
342
+ START: "start",
343
+ END: "end"
344
+ };
345
+ var LINK_RELATIONSHIP = {
346
+ FINISH_TO_START: "finish-to-start",
347
+ START_TO_START: "start-to-start",
348
+ FINISH_TO_FINISH: "finish-to-finish",
349
+ START_TO_FINISH: "start-to-finish"
350
+ };
351
+ var LINK_BATCH_OPERATION_KIND = {
352
+ CREATE: "create",
353
+ UPDATE: "update",
354
+ REMOVE: "remove"
355
+ };
356
+
357
+ // src/api/activity-fields.ts
358
+ var ACTIVITY_EDIT_COLUMNS = {
359
+ [ACTIVITY_FIELD.NAME]: COLUMN.TEXT,
360
+ [ACTIVITY_FIELD.DESCRIPTION]: COLUMN.DESCRIPTION,
361
+ [ACTIVITY_FIELD.DURATION_DAYS]: COLUMN.DURATION,
362
+ [ACTIVITY_FIELD.PROGRESS]: COLUMN.PROGRESS,
363
+ [ACTIVITY_FIELD.COST]: COLUMN.COST,
364
+ [ACTIVITY_FIELD.USED_COST]: COLUMN.USED_COST,
365
+ [ACTIVITY_FIELD.WORK_HOURS]: COLUMN.HH_WORK_TIME,
366
+ [ACTIVITY_FIELD.START_DATE]: COLUMN.START_DATE,
367
+ [ACTIVITY_FIELD.END_DATE]: COLUMN.END_DATE,
368
+ [ACTIVITY_FIELD.CONSTRAINT_TYPE]: COLUMN.CONSTRAINT_TYPE,
369
+ [ACTIVITY_FIELD.CONSTRAINT_DATE]: COLUMN.CONSTRAINT_DATE,
370
+ [ACTIVITY_FIELD.CALENDAR_ID]: COLUMN.CALENDAR_ID,
371
+ [ACTIVITY_FIELD.CUSTOM_ID]: COLUMN.CUSTOM_ID,
372
+ [ACTIVITY_FIELD.SUBCONTRACT_ID]: COLUMN.SUBCONTRACT_ID,
373
+ [ACTIVITY_FIELD.RESPONSABLE_IDS]: COLUMN.RESPONSABLES,
374
+ [ACTIVITY_FIELD.TAG_IDS]: COLUMN.TAGS
375
+ };
376
+ function activityEditToColumnEdit(activityId, edit) {
377
+ return {
378
+ activityId,
379
+ column: ACTIVITY_EDIT_COLUMNS[edit.field],
380
+ newValue: edit.value
381
+ };
382
+ }
383
+
384
+ // src/api/schedule-api.ts
385
+ var LINK_TYPES = {
386
+ [LINK_RELATIONSHIP.FINISH_TO_START]: LINK_TYPE.FINISH_TO_START,
387
+ [LINK_RELATIONSHIP.START_TO_START]: LINK_TYPE.START_TO_START,
388
+ [LINK_RELATIONSHIP.FINISH_TO_FINISH]: LINK_TYPE.FINISH_TO_FINISH,
389
+ [LINK_RELATIONSHIP.START_TO_FINISH]: LINK_TYPE.START_TO_FINISH
390
+ };
391
+ function linkType(relationship) {
392
+ return LINK_TYPES[relationship];
393
+ }
394
+ function batchLink(operation) {
395
+ if (operation.kind === LINK_BATCH_OPERATION_KIND.CREATE) {
396
+ return {
397
+ kind: DISPATCH_LINK_OPERATION_KIND.CREATE,
398
+ source: operation.sourceId,
399
+ target: operation.targetId,
400
+ type: linkType(operation.relationship),
401
+ ...operation.lagDays === void 0 ? {} : { lag: operation.lagDays },
402
+ ...operation.linkId === void 0 ? {} : { linkId: operation.linkId }
403
+ };
404
+ }
405
+ if (operation.kind === LINK_BATCH_OPERATION_KIND.UPDATE) {
406
+ return {
407
+ kind: DISPATCH_LINK_OPERATION_KIND.UPDATE,
408
+ linkId: operation.linkId,
409
+ ...operation.relationship === void 0 ? {} : { type: linkType(operation.relationship) },
410
+ ...operation.lagDays === void 0 ? {} : { lag: operation.lagDays }
411
+ };
412
+ }
413
+ if (operation.kind === LINK_BATCH_OPERATION_KIND.REMOVE) {
414
+ return {
415
+ kind: DISPATCH_LINK_OPERATION_KIND.DELETE,
416
+ linkId: operation.linkId
417
+ };
418
+ }
419
+ return operation;
420
+ }
421
+ function activityDateColumn(edge) {
422
+ if (edge === ACTIVITY_DATE_EDGE.START) return COLUMN.START_DATE;
423
+ if (edge === ACTIVITY_DATE_EDGE.END) return COLUMN.END_DATE;
424
+ return edge;
425
+ }
426
+ function activityBatch(input) {
427
+ return {
428
+ kind: ACTIVITY_BATCH_ACTION_KIND,
429
+ mode: input.mode,
430
+ items: input.items,
431
+ links: input.links.map((link) => ({
432
+ source: link.source,
433
+ target: link.target,
434
+ type: linkType(link.relationship),
435
+ ...link.lagDays === void 0 ? {} : { lag: link.lagDays },
436
+ ...link.linkId === void 0 ? {} : { linkId: link.linkId }
437
+ })),
438
+ ...input.eventSource === void 0 ? {} : { eventSource: input.eventSource }
439
+ };
440
+ }
441
+ function createActivitiesApi(engine) {
442
+ return {
443
+ get: (id) => engine.getActivityView(id),
444
+ list: () => engine.getAllActivitiesView(),
445
+ ids: () => engine.getAllIds(),
446
+ forEachId: (visit) => engine.forEachActivityId(visit),
447
+ property: (id, property) => engine.getProperty(id, property),
448
+ children: (parentId) => engine.getChildrenView(parentId),
449
+ childIds: (parentId) => engine.getChildrenIds(parentId),
450
+ hasChildren: (parentId) => engine.hasChild(parentId),
451
+ indentTargetParentIds: (ids) => engine.getIndentTargetParentIds(ids),
452
+ isCustomIdInUse: (customId, currentCustomId) => engine.isCustomIdInUse(customId, currentCustomId ?? null),
453
+ create: (input, options) => engine.dispatch(
454
+ { ...input, kind: DISPATCH_ACTION_KIND.ACTIVITY_CREATE },
455
+ options
456
+ ),
457
+ applyBatch: (input, options) => engine.applyActivityBatch(activityBatch(input), options),
458
+ editInline: (activityId, edit, options) => engine.dispatch(
459
+ {
460
+ ...activityEditToColumnEdit(activityId, edit),
461
+ kind: DISPATCH_ACTION_KIND.INLINE_EDIT
462
+ },
463
+ options
464
+ ),
465
+ applyDragBatch: (edits, options) => engine.dispatch(
466
+ {
467
+ kind: DISPATCH_ACTION_KIND.DATES_BATCH,
468
+ edits: edits.map((edit) => ({
469
+ activityId: edit.activityId,
470
+ column: activityDateColumn(edit.edge),
471
+ newValue: edit.value
472
+ }))
473
+ },
474
+ options
475
+ ),
476
+ editFields: (edits, options) => engine.dispatch(
477
+ {
478
+ kind: DISPATCH_ACTION_KIND.BULK_EDIT,
479
+ edits: edits.map(
480
+ (edit) => activityEditToColumnEdit(edit.activityId, edit)
481
+ )
482
+ },
483
+ options
484
+ ),
485
+ remove: (activityIds, context = {}) => engine.dispatch({
486
+ ...context,
487
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_DELETE,
488
+ activityIds
489
+ }),
490
+ move: (input, options) => engine.dispatch(
491
+ { ...input, kind: DISPATCH_ACTION_KIND.ACTIVITY_MOVE },
492
+ options
493
+ ),
494
+ indent: (activityIds, context = {}) => engine.dispatch({
495
+ ...context,
496
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_INDENT,
497
+ activityIds
498
+ }),
499
+ outdent: (activityIds, context = {}) => engine.dispatch({
500
+ ...context,
501
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_OUTDENT,
502
+ activityIds
503
+ }),
504
+ setProgress: (activityId, progress, context = {}) => engine.dispatch({
505
+ ...context,
506
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_SET_PROGRESS,
507
+ activityId,
508
+ newValue: progress
509
+ }),
510
+ copy: (context = {}) => engine.dispatch({ ...context, kind: DISPATCH_ACTION_KIND.ACTIVITY_COPY }),
511
+ paste: (afterSiblingId, context = {}) => engine.dispatch({
512
+ ...context,
513
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_PASTE_COPIED,
514
+ destination: { afterSiblingId }
515
+ }),
516
+ clearClipboard: (context = {}) => engine.dispatch({
517
+ ...context,
518
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR
519
+ }),
520
+ lookaheadSync: (input) => engine.dispatch({
521
+ ...input,
522
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC
523
+ }),
524
+ createDateGesturePreview: (gesture) => engine.createDateGesturePreview(gesture)
525
+ };
526
+ }
527
+ function createLinksApi(engine) {
528
+ return {
529
+ get: (id) => engine.getLinkView(id),
530
+ list: () => engine.getAllLinksView(),
531
+ forActivity: (activityId) => engine.getLinksForActivityView(activityId),
532
+ create: (input, options) => engine.dispatch(
533
+ {
534
+ kind: DISPATCH_ACTION_KIND.LINK_CREATE,
535
+ source: input.sourceId,
536
+ target: input.targetId,
537
+ type: linkType(input.relationship),
538
+ ...input.lagDays === void 0 ? {} : { lag: input.lagDays },
539
+ ...input.linkId === void 0 ? {} : { linkId: input.linkId }
540
+ },
541
+ options
542
+ ),
543
+ update: (linkId, patch, options) => engine.dispatch(
544
+ {
545
+ kind: DISPATCH_ACTION_KIND.LINK_UPDATE,
546
+ linkId,
547
+ ...patch.relationship === void 0 ? {} : { type: linkType(patch.relationship) },
548
+ ...patch.lagDays === void 0 ? {} : { lag: patch.lagDays }
549
+ },
550
+ options
551
+ ),
552
+ remove: (linkId, options) => engine.dispatch(
553
+ { kind: DISPATCH_ACTION_KIND.LINK_DELETE, linkId },
554
+ options
555
+ ),
556
+ batch: (operations, options) => engine.dispatch(
557
+ {
558
+ kind: DISPATCH_ACTION_KIND.LINKS_BATCH,
559
+ operations: operations.map(batchLink)
560
+ },
561
+ options
562
+ )
563
+ };
564
+ }
565
+ function createScheduleNamespaces(engine) {
566
+ const applyBaselinePoints2 = (points, options) => engine.dispatch(
567
+ { kind: DISPATCH_ACTION_KIND.BASELINE_APPLY, points },
568
+ options
569
+ );
570
+ return {
571
+ activities: createActivitiesApi(engine),
572
+ links: createLinksApi(engine),
573
+ calendars: {
574
+ get: (id) => engine.getCalendar(id),
575
+ list: () => engine.getAllCalendars(),
576
+ listBase: () => engine.getBaseCalendars(),
577
+ projectWorkHours: () => engine.getProjectWorkHours(),
578
+ reconcile: (options) => engine.dispatch(
579
+ { kind: DISPATCH_ACTION_KIND.CALENDAR_RECONCILE },
580
+ options
581
+ )
582
+ },
583
+ selection: {
584
+ ids: () => engine.getSelectedActivityIds(),
585
+ toggle: ({ checked, ...input }) => engine.dispatch({
586
+ ...input,
587
+ kind: DISPATCH_ACTION_KIND.SELECTION_TOGGLE,
588
+ isChecked: checked
589
+ }),
590
+ replace: (activityIds, context = {}) => engine.dispatch({
591
+ ...context,
592
+ kind: DISPATCH_ACTION_KIND.SELECTION_REPLACE,
593
+ activityIds
594
+ })
595
+ },
596
+ view: {
597
+ hiddenActivityIds: () => engine.getHiddenActivityIds(),
598
+ visibleActivityIds: () => engine.getVisibleActivityIds(),
599
+ visualOrderIds: () => engine.getVisualOrderIds(),
600
+ filter: () => engine.getActiveFilter(),
601
+ setFilter: (input) => engine.dispatch({ ...input, kind: DISPATCH_ACTION_KIND.FILTER_SET }),
602
+ order: () => engine.getActiveOrder(),
603
+ setOrder: (rules, context = {}) => engine.dispatch({
604
+ ...context,
605
+ kind: DISPATCH_ACTION_KIND.SORT_SET,
606
+ rules
607
+ }),
608
+ setVisibility: (activityIds, context = {}) => engine.dispatch({
609
+ ...context,
610
+ kind: DISPATCH_ACTION_KIND.VISIBILITY_SET,
611
+ visibleIds: activityIds
612
+ }),
613
+ setStatusCriteria: (criteria, options) => engine.dispatch(
614
+ { kind: DISPATCH_ACTION_KIND.STATUS_CRITERIA_SET, criteria },
615
+ options
616
+ )
617
+ },
618
+ baselines: {
619
+ refresh: applyBaselinePoints2,
620
+ setVisibility: applyBaselinePoints2,
621
+ setPonderatorCriterion: (criterion, options) => engine.dispatch(
622
+ { kind: DISPATCH_ACTION_KIND.PONDERATOR_CRITERION_SET, criterion },
623
+ options
624
+ ),
625
+ activeFor: (activity) => getActiveBaseline(activity)
626
+ },
627
+ impactRequests: {
628
+ sync: (input) => engine.dispatch({ ...input, kind: DISPATCH_ACTION_KIND.SIR_SYNC })
629
+ },
630
+ persistence: {
631
+ hasChanges: () => engine.hasUnsavedChanges(),
632
+ modifiedActivities: () => engine.getModifiedActivities(),
633
+ modifiedActivityFields: () => engine.getModifiedActivityFields(),
634
+ newActivities: () => engine.getNewActivities(),
635
+ deletedActivities: () => engine.getDeletedActivitiesSinceLastSave(),
636
+ modifiedLinks: () => engine.getModifiedLinks(),
637
+ newLinks: () => engine.getNewLinks(),
638
+ deletedLinks: () => engine.getDeletedLinksSinceLastSave(),
639
+ captureHistoryBoundary: () => engine.capturePersistenceHistoryBoundary(),
640
+ readSnapshot: () => ({
641
+ activities: engine.getAllActivitiesView(),
642
+ links: engine.getAllLinksView(),
643
+ historyBoundary: engine.capturePersistenceHistoryBoundary()
644
+ }),
645
+ acknowledge: (checkpoint) => engine.dispatch({
646
+ kind: DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE,
647
+ checkpoint
648
+ })
649
+ },
650
+ history: {
651
+ undo: (options) => engine.undo(options),
652
+ redo: (options) => engine.redo(options),
653
+ canUndo: () => engine.canUndo(),
654
+ canRedo: () => engine.canRedo(),
655
+ clear: () => engine.clearHistory(),
656
+ depth: () => engine.undoDepth()
657
+ },
658
+ projection: {
659
+ changeSetFrom: (source) => engine.createProjectionChangeSetFrom(source)
660
+ },
661
+ criticalPath: {
662
+ get ready() {
663
+ return engine.criticalPathReady;
664
+ },
665
+ recompute: () => engine.recomputeCriticalPath(),
666
+ isSettled: () => engine.isCriticalPathSettled(),
667
+ whenSettled: () => engine.whenCriticalPathSettled()
668
+ },
669
+ diagnostics: {
670
+ auditEffectiveGraph: () => engine.auditEffectiveGraph(),
671
+ revision: () => engine.getScheduleRevision(),
672
+ canonicalDigest: () => engine.getCanonicalDigest()
673
+ }
674
+ };
675
+ }
676
+
1
677
  // src/shared/queue.ts
2
678
  var Queue = class {
3
679
  items = [];
@@ -247,23 +923,105 @@ function dispatchVisibilitySet(action, deps) {
247
923
  return { ok: true, changes };
248
924
  }
249
925
 
926
+ // src/autoscheduler/constants.ts
927
+ var ACTIVITY_TYPE = {
928
+ TASK: "task",
929
+ PROJECT: "project",
930
+ MILESTONE: "milestone"
931
+ };
932
+ var TIMING = {
933
+ YIELD_SLICE_MS: 8
934
+ };
935
+
936
+ // src/internal/filter/types.ts
937
+ var FILTER_VALUE_KIND = {
938
+ STRING: "string",
939
+ NUMBER: "number",
940
+ DATE: "date",
941
+ ID_ARRAY: "id-array",
942
+ ENUM: "enum",
943
+ BOOLEAN: "boolean",
944
+ REFERENCE: "reference"
945
+ };
946
+ var FILTER_FIELD = {
947
+ NAME: "name",
948
+ DESCRIPTION: "description",
949
+ CUSTOM_ID: "customId",
950
+ CORRELATIVE_ID: "correlativeId",
951
+ UNIQUE_CORRELATIVE_ID: "uniqueCorrelativeId",
952
+ PROGRESS: "progress",
953
+ DURATION_DAYS: "durationDays",
954
+ CALENDAR_DURATION: "calendarDuration",
955
+ COST: "cost",
956
+ USED_COST: "usedCost",
957
+ REAL_COST: "realCost",
958
+ WORK_HOURS: "workHours",
959
+ REAL_WORK_HOURS: "realWorkHours",
960
+ PONDERATOR: "ponderator",
961
+ FREE_SLACK_DAYS: "freeSlackDays",
962
+ TOTAL_SLACK_DAYS: "totalSlackDays",
963
+ EXPECTED_PROGRESS_BASELINE: "expectedProgressBaseline",
964
+ BASELINE_DURATION_DAYS: "baselineDurationDays",
965
+ BASELINE_COST: "baselineCost",
966
+ BASELINE_WORK_HOURS: "baselineWorkHours",
967
+ EXPECTED_PROGRESS: "expectedProgress",
968
+ START_DATE: "startDate",
969
+ END_DATE: "endDate",
970
+ CONSTRAINT_DATE: "constraintDate",
971
+ BASELINE_START_DATE: "baselineStartDate",
972
+ BASELINE_END_DATE: "baselineEndDate",
973
+ EARLY_START: "earlyStart",
974
+ EARLY_FINISH: "earlyFinish",
975
+ LATE_START: "lateStart",
976
+ LATE_FINISH: "lateFinish",
977
+ RESPONSABLE_IDS: "responsableIds",
978
+ TAG_IDS: "tagIds",
979
+ STATUS: "status",
980
+ CONSTRAINT_TYPE: "constraintType",
981
+ CALENDAR_ID: "calendarId",
982
+ SUBCONTRACT_ID: "subcontractId",
983
+ IS_CRITICAL: "isCritical"
984
+ };
985
+ var FILTER_OPERATOR = {
986
+ INCLUDES: "includes",
987
+ NOT_INCLUDES: "notIncludes",
988
+ IS: "is",
989
+ IS_NOT: "isNot",
990
+ EQUALS: "equals",
991
+ NOT_EQUALS: "notEquals",
992
+ GREATER_THAN: "greaterThan",
993
+ LESS_THAN: "lessThan",
994
+ GREATER_OR_EQUAL: "greaterOrEqual",
995
+ LESS_OR_EQUAL: "lessOrEqual",
996
+ AFTER: "after",
997
+ BEFORE: "before",
998
+ BETWEEN: "between",
999
+ SOME_OF: "someOf",
1000
+ NOT_SOME_OF: "notSomeOf"
1001
+ };
1002
+ var FILTER_LOGIC = {
1003
+ AND: "and",
1004
+ OR: "or"
1005
+ };
1006
+
250
1007
  // src/internal/filter/field-registry.ts
1008
+ var BASELINE_EXPECTED_PROGRESS_PRECISION = 2;
251
1009
  var STATUS_ORDER = [
252
- "Waiting",
253
- "Done",
254
- "Doing",
255
- "Overdue",
256
- "Advancement"
1010
+ STATUS.WAITING,
1011
+ STATUS.DONE,
1012
+ STATUS.DOING,
1013
+ STATUS.OVERDUE,
1014
+ STATUS.ADVANCEMENT
257
1015
  ];
258
1016
  var CONSTRAINT_TYPE_ORDER = [
259
- "mfo",
260
- "mso",
261
- "snlt",
262
- "snet",
263
- "alap",
264
- "asap",
265
- "fnet",
266
- "fnlt"
1017
+ CONSTRAINT_TYPE.MFO,
1018
+ CONSTRAINT_TYPE.MSO,
1019
+ CONSTRAINT_TYPE.SNLT,
1020
+ CONSTRAINT_TYPE.SNET,
1021
+ CONSTRAINT_TYPE.ALAP,
1022
+ CONSTRAINT_TYPE.ASAP,
1023
+ CONSTRAINT_TYPE.FNET,
1024
+ CONSTRAINT_TYPE.FNLT
267
1025
  ];
268
1026
  var MILLISECONDS_PER_DAY = 1e3 * 60 * 60 * 24;
269
1027
  function toDays(hours, hoursPerDay) {
@@ -285,131 +1043,161 @@ function calendarDaySpan(startDate, endDate) {
285
1043
  return Math.floor((endDay - startDay) / MILLISECONDS_PER_DAY) + 1;
286
1044
  }
287
1045
  var FIELD_REGISTRY = {
288
- name: { valueKind: "string", extract: (activity) => activity.name },
289
- description: {
290
- valueKind: "string",
1046
+ [FILTER_FIELD.NAME]: {
1047
+ valueKind: FILTER_VALUE_KIND.STRING,
1048
+ extract: (activity) => activity.name
1049
+ },
1050
+ [FILTER_FIELD.DESCRIPTION]: {
1051
+ valueKind: FILTER_VALUE_KIND.STRING,
291
1052
  extract: (activity) => activity.description
292
1053
  },
293
- customId: { valueKind: "string", extract: (activity) => activity.customId },
294
- correlativeId: {
295
- valueKind: "number",
1054
+ [FILTER_FIELD.CUSTOM_ID]: {
1055
+ valueKind: FILTER_VALUE_KIND.STRING,
1056
+ extract: (activity) => activity.customId
1057
+ },
1058
+ [FILTER_FIELD.CORRELATIVE_ID]: {
1059
+ valueKind: FILTER_VALUE_KIND.NUMBER,
296
1060
  extract: (activity) => activity.correlativeId
297
1061
  },
298
- uniqueCorrelativeId: {
299
- valueKind: "number",
1062
+ [FILTER_FIELD.UNIQUE_CORRELATIVE_ID]: {
1063
+ valueKind: FILTER_VALUE_KIND.NUMBER,
300
1064
  extract: (activity) => {
301
1065
  const value = Number(activity.uniqueCorrelativeId);
302
1066
  return Number.isFinite(value) ? value : null;
303
1067
  }
304
1068
  },
305
- progress: { valueKind: "number", extract: (activity) => activity.progress },
306
- durationDays: {
307
- valueKind: "number",
1069
+ [FILTER_FIELD.PROGRESS]: {
1070
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1071
+ extract: (activity) => activity.progress
1072
+ },
1073
+ [FILTER_FIELD.DURATION_DAYS]: {
1074
+ valueKind: FILTER_VALUE_KIND.NUMBER,
308
1075
  extract: (activity, context) => toDays(activity.durationHours, context.hoursPerDay)
309
1076
  },
310
- calendarDuration: {
311
- valueKind: "number",
312
- extract: (activity) => activity.type === "milestone" ? 0 : calendarDaySpan(activity.startDate, activity.endDate)
1077
+ [FILTER_FIELD.CALENDAR_DURATION]: {
1078
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1079
+ extract: (activity) => activity.type === ACTIVITY_TYPE.MILESTONE ? 0 : calendarDaySpan(activity.startDate, activity.endDate)
1080
+ },
1081
+ [FILTER_FIELD.COST]: {
1082
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1083
+ extract: (activity) => activity.cost
1084
+ },
1085
+ [FILTER_FIELD.USED_COST]: {
1086
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1087
+ extract: (activity) => activity.usedCost
313
1088
  },
314
- cost: { valueKind: "number", extract: (activity) => activity.cost },
315
- usedCost: { valueKind: "number", extract: (activity) => activity.usedCost },
316
- realCost: { valueKind: "number", extract: (activity) => activity.realCost },
317
- workHours: { valueKind: "number", extract: (activity) => activity.workHours },
318
- realWorkHours: {
319
- valueKind: "number",
1089
+ [FILTER_FIELD.REAL_COST]: {
1090
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1091
+ extract: (activity) => activity.realCost
1092
+ },
1093
+ [FILTER_FIELD.WORK_HOURS]: {
1094
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1095
+ extract: (activity) => activity.workHours
1096
+ },
1097
+ [FILTER_FIELD.REAL_WORK_HOURS]: {
1098
+ valueKind: FILTER_VALUE_KIND.NUMBER,
320
1099
  extract: (activity) => activity.realWorkHours
321
1100
  },
322
- ponderator: {
323
- valueKind: "number",
1101
+ [FILTER_FIELD.PONDERATOR]: {
1102
+ valueKind: FILTER_VALUE_KIND.NUMBER,
324
1103
  extract: (activity) => activity.ponderator
325
1104
  },
326
- freeSlackDays: {
327
- valueKind: "number",
1105
+ [FILTER_FIELD.FREE_SLACK_DAYS]: {
1106
+ valueKind: FILTER_VALUE_KIND.NUMBER,
328
1107
  extract: (activity, context) => toDays(activity.freeSlackHours, context.hoursPerDay)
329
1108
  },
330
- totalSlackDays: {
331
- valueKind: "number",
1109
+ [FILTER_FIELD.TOTAL_SLACK_DAYS]: {
1110
+ valueKind: FILTER_VALUE_KIND.NUMBER,
332
1111
  extract: (activity, context) => toDays(
333
1112
  activity.criticalPath?.totalSlackHours ?? null,
334
1113
  context.hoursPerDay
335
1114
  )
336
1115
  },
337
- expectedProgressBaseline: {
338
- valueKind: "number",
339
- equalityPrecision: 2,
1116
+ [FILTER_FIELD.EXPECTED_PROGRESS_BASELINE]: {
1117
+ valueKind: FILTER_VALUE_KIND.NUMBER,
1118
+ equalityPrecision: BASELINE_EXPECTED_PROGRESS_PRECISION,
340
1119
  extract: (activity) => activity.expectedProgressBaseline
341
1120
  },
342
- expectedProgress: {
343
- valueKind: "number",
1121
+ [FILTER_FIELD.EXPECTED_PROGRESS]: {
1122
+ valueKind: FILTER_VALUE_KIND.NUMBER,
344
1123
  extract: (activity) => activity.expectedProgress
345
1124
  },
346
- baselineDurationDays: {
347
- valueKind: "number",
1125
+ [FILTER_FIELD.BASELINE_DURATION_DAYS]: {
1126
+ valueKind: FILTER_VALUE_KIND.NUMBER,
348
1127
  extract: (activity) => activity.baselineSnapshot?.durationDays ?? null
349
1128
  },
350
- baselineCost: {
351
- valueKind: "number",
1129
+ [FILTER_FIELD.BASELINE_COST]: {
1130
+ valueKind: FILTER_VALUE_KIND.NUMBER,
352
1131
  extract: (activity) => activity.baselineSnapshot?.cost ?? null
353
1132
  },
354
- baselineWorkHours: {
355
- valueKind: "number",
1133
+ [FILTER_FIELD.BASELINE_WORK_HOURS]: {
1134
+ valueKind: FILTER_VALUE_KIND.NUMBER,
356
1135
  extract: (activity) => activity.baselineSnapshot?.workHours ?? null
357
1136
  },
358
- startDate: { valueKind: "date", extract: (activity) => activity.startDate },
359
- endDate: { valueKind: "date", extract: (activity) => activity.endDate },
360
- constraintDate: {
361
- valueKind: "date",
1137
+ [FILTER_FIELD.START_DATE]: {
1138
+ valueKind: FILTER_VALUE_KIND.DATE,
1139
+ extract: (activity) => activity.startDate
1140
+ },
1141
+ [FILTER_FIELD.END_DATE]: {
1142
+ valueKind: FILTER_VALUE_KIND.DATE,
1143
+ extract: (activity) => activity.endDate
1144
+ },
1145
+ [FILTER_FIELD.CONSTRAINT_DATE]: {
1146
+ valueKind: FILTER_VALUE_KIND.DATE,
362
1147
  extract: (activity) => activity.constraintDate
363
1148
  },
364
- baselineStartDate: {
365
- valueKind: "date",
1149
+ [FILTER_FIELD.BASELINE_START_DATE]: {
1150
+ valueKind: FILTER_VALUE_KIND.DATE,
366
1151
  extract: (activity) => activity.baselineSnapshot?.startDate ?? null
367
1152
  },
368
- baselineEndDate: {
369
- valueKind: "date",
1153
+ [FILTER_FIELD.BASELINE_END_DATE]: {
1154
+ valueKind: FILTER_VALUE_KIND.DATE,
370
1155
  extract: (activity) => activity.baselineSnapshot?.endDate ?? null
371
1156
  },
372
- earlyStart: {
373
- valueKind: "date",
1157
+ [FILTER_FIELD.EARLY_START]: {
1158
+ valueKind: FILTER_VALUE_KIND.DATE,
374
1159
  extract: (activity) => activity.criticalPath?.earlyStart ?? null
375
1160
  },
376
- earlyFinish: {
377
- valueKind: "date",
1161
+ [FILTER_FIELD.EARLY_FINISH]: {
1162
+ valueKind: FILTER_VALUE_KIND.DATE,
378
1163
  extract: (activity) => activity.criticalPath?.earlyFinish ?? null
379
1164
  },
380
- lateStart: {
381
- valueKind: "date",
1165
+ [FILTER_FIELD.LATE_START]: {
1166
+ valueKind: FILTER_VALUE_KIND.DATE,
382
1167
  extract: (activity) => activity.criticalPath?.lateStart ?? null
383
1168
  },
384
- lateFinish: {
385
- valueKind: "date",
1169
+ [FILTER_FIELD.LATE_FINISH]: {
1170
+ valueKind: FILTER_VALUE_KIND.DATE,
386
1171
  extract: (activity) => activity.criticalPath?.lateFinish ?? null
387
1172
  },
388
- responsableIds: {
389
- valueKind: "id-array",
1173
+ [FILTER_FIELD.RESPONSABLE_IDS]: {
1174
+ valueKind: FILTER_VALUE_KIND.ID_ARRAY,
390
1175
  extract: (activity) => activity.responsableIds
391
1176
  },
392
- tagIds: { valueKind: "id-array", extract: (activity) => activity.tagIds },
393
- status: {
394
- valueKind: "enum",
1177
+ [FILTER_FIELD.TAG_IDS]: {
1178
+ valueKind: FILTER_VALUE_KIND.ID_ARRAY,
1179
+ extract: (activity) => activity.tagIds
1180
+ },
1181
+ [FILTER_FIELD.STATUS]: {
1182
+ valueKind: FILTER_VALUE_KIND.ENUM,
395
1183
  order: STATUS_ORDER,
396
1184
  extract: (activity) => activity.status
397
1185
  },
398
- constraintType: {
399
- valueKind: "enum",
1186
+ [FILTER_FIELD.CONSTRAINT_TYPE]: {
1187
+ valueKind: FILTER_VALUE_KIND.ENUM,
400
1188
  order: CONSTRAINT_TYPE_ORDER,
401
1189
  extract: (activity) => activity.constraintType
402
1190
  },
403
- calendarId: {
404
- valueKind: "reference",
1191
+ [FILTER_FIELD.CALENDAR_ID]: {
1192
+ valueKind: FILTER_VALUE_KIND.REFERENCE,
405
1193
  extract: (activity) => activity.calendarId === null ? null : String(activity.calendarId)
406
1194
  },
407
- subcontractId: {
408
- valueKind: "reference",
1195
+ [FILTER_FIELD.SUBCONTRACT_ID]: {
1196
+ valueKind: FILTER_VALUE_KIND.REFERENCE,
409
1197
  extract: (activity) => activity.subcontractId === null ? null : String(activity.subcontractId)
410
1198
  },
411
- isCritical: {
412
- valueKind: "boolean",
1199
+ [FILTER_FIELD.IS_CRITICAL]: {
1200
+ valueKind: FILTER_VALUE_KIND.BOOLEAN,
413
1201
  extract: (activity) => activity.isCritical
414
1202
  }
415
1203
  };
@@ -430,27 +1218,31 @@ function utcDayMs(date2) {
430
1218
  }
431
1219
  function matchString(value, target, operator) {
432
1220
  const isAbsent = value === null;
433
- if (operator === "includes") {
1221
+ if (operator === FILTER_OPERATOR.INCLUDES) {
434
1222
  return !isAbsent && String(value).toLowerCase().includes(target.toLowerCase());
435
1223
  }
436
- if (operator === "notIncludes") {
1224
+ if (operator === FILTER_OPERATOR.NOT_INCLUDES) {
437
1225
  return isAbsent || !String(value).toLowerCase().includes(target.toLowerCase());
438
1226
  }
439
- if (operator === "is") return !isAbsent && String(value) === target;
440
- if (operator === "isNot") return isAbsent || String(value) !== target;
1227
+ if (operator === FILTER_OPERATOR.IS) {
1228
+ return !isAbsent && String(value) === target;
1229
+ }
1230
+ if (operator === FILTER_OPERATOR.IS_NOT) {
1231
+ return isAbsent || String(value) !== target;
1232
+ }
441
1233
  return false;
442
1234
  }
443
1235
  function matchNumber(value, target, operator, equalityPrecision) {
444
1236
  if (value === null || typeof value !== "number") {
445
- return operator === "notEquals";
1237
+ return operator === FILTER_OPERATOR.NOT_EQUALS;
446
1238
  }
447
1239
  const equalityValue = equalityPrecision === void 0 ? value : Number(value.toFixed(equalityPrecision));
448
- if (operator === "equals") return equalityValue === target;
449
- if (operator === "notEquals") return equalityValue !== target;
450
- if (operator === "greaterThan") return value > target;
451
- if (operator === "lessThan") return value < target;
452
- if (operator === "greaterOrEqual") return value >= target;
453
- if (operator === "lessOrEqual") return value <= target;
1240
+ if (operator === FILTER_OPERATOR.EQUALS) return equalityValue === target;
1241
+ if (operator === FILTER_OPERATOR.NOT_EQUALS) return equalityValue !== target;
1242
+ if (operator === FILTER_OPERATOR.GREATER_THAN) return value > target;
1243
+ if (operator === FILTER_OPERATOR.LESS_THAN) return value < target;
1244
+ if (operator === FILTER_OPERATOR.GREATER_OR_EQUAL) return value >= target;
1245
+ if (operator === FILTER_OPERATOR.LESS_OR_EQUAL) return value <= target;
454
1246
  return false;
455
1247
  }
456
1248
  function matchNumberBetween(value, minimum, maximum) {
@@ -460,8 +1252,8 @@ function matchDate(value, target, operator) {
460
1252
  if (!(value instanceof Date)) return false;
461
1253
  const valueDay = utcDayMs(value);
462
1254
  const targetDay = utcDayMs(target);
463
- if (operator === "after") return valueDay > targetDay;
464
- if (operator === "before") return valueDay < targetDay;
1255
+ if (operator === FILTER_OPERATOR.AFTER) return valueDay > targetDay;
1256
+ if (operator === FILTER_OPERATOR.BEFORE) return valueDay < targetDay;
465
1257
  return false;
466
1258
  }
467
1259
  function matchDateBetween(value, minimum, maximum) {
@@ -472,14 +1264,14 @@ function matchDateBetween(value, minimum, maximum) {
472
1264
  function matchIdArray(value, allowed, operator) {
473
1265
  const ids = Array.isArray(value) ? value : [];
474
1266
  const intersects = ids.some((id) => allowed.has(String(id)));
475
- if (operator === "someOf") return intersects;
476
- if (operator === "notSomeOf") return !intersects;
1267
+ if (operator === FILTER_OPERATOR.SOME_OF) return intersects;
1268
+ if (operator === FILTER_OPERATOR.NOT_SOME_OF) return !intersects;
477
1269
  return false;
478
1270
  }
479
1271
  function matchEnum(value, allowed, operator) {
480
1272
  const isMember = value !== null && allowed.has(String(value));
481
- if (operator === "someOf") return isMember;
482
- if (operator === "notSomeOf") return !isMember;
1273
+ if (operator === FILTER_OPERATOR.SOME_OF) return isMember;
1274
+ if (operator === FILTER_OPERATOR.NOT_SOME_OF) return !isMember;
483
1275
  return false;
484
1276
  }
485
1277
  function toAllowedSet(value) {
@@ -491,15 +1283,15 @@ function matchCriterion(activity, criterion, context) {
491
1283
  if (descriptor === null) return false;
492
1284
  const value = descriptor.extract(activity, context);
493
1285
  const { operator } = criterion;
494
- if (operator === "between") {
495
- if (descriptor.valueKind === "number") {
1286
+ if (operator === FILTER_OPERATOR.BETWEEN) {
1287
+ if (descriptor.valueKind === FILTER_VALUE_KIND.NUMBER) {
496
1288
  return matchNumberBetween(
497
1289
  value,
498
1290
  Number(criterion.value),
499
1291
  Number(criterion.valueTo)
500
1292
  );
501
1293
  }
502
- if (descriptor.valueKind === "date") {
1294
+ if (descriptor.valueKind === FILTER_VALUE_KIND.DATE) {
503
1295
  return matchDateBetween(
504
1296
  value,
505
1297
  toTargetDate(criterion.value),
@@ -508,10 +1300,10 @@ function matchCriterion(activity, criterion, context) {
508
1300
  }
509
1301
  return false;
510
1302
  }
511
- if (descriptor.valueKind === "string") {
1303
+ if (descriptor.valueKind === FILTER_VALUE_KIND.STRING) {
512
1304
  return matchString(value, String(criterion.value), operator);
513
1305
  }
514
- if (descriptor.valueKind === "number") {
1306
+ if (descriptor.valueKind === FILTER_VALUE_KIND.NUMBER) {
515
1307
  return matchNumber(
516
1308
  value,
517
1309
  Number(criterion.value),
@@ -519,17 +1311,17 @@ function matchCriterion(activity, criterion, context) {
519
1311
  descriptor.equalityPrecision
520
1312
  );
521
1313
  }
522
- if (descriptor.valueKind === "date") {
1314
+ if (descriptor.valueKind === FILTER_VALUE_KIND.DATE) {
523
1315
  return matchDate(value, toTargetDate(criterion.value), operator);
524
1316
  }
525
- if (descriptor.valueKind === "id-array") {
1317
+ if (descriptor.valueKind === FILTER_VALUE_KIND.ID_ARRAY) {
526
1318
  return matchIdArray(value, toAllowedSet(criterion.value), operator);
527
1319
  }
528
1320
  return matchEnum(value, toAllowedSet(criterion.value), operator);
529
1321
  }
530
1322
  function matchesCriteria(activity, filter, context) {
531
1323
  if (filter.criteria.length === 0) return true;
532
- if (filter.logic === "or") {
1324
+ if (filter.logic === FILTER_LOGIC.OR) {
533
1325
  return filter.criteria.some(
534
1326
  (criterion) => matchCriterion(activity, criterion, context)
535
1327
  );
@@ -684,36 +1476,62 @@ function buildFilterContext(hoursPerDay) {
684
1476
  }
685
1477
 
686
1478
  // src/internal/filter/validate.ts
1479
+ var FILTER_REJECTION_REASON = {
1480
+ UNKNOWN_FIELD: "unknown_field",
1481
+ UNKNOWN_OPERATOR: "unknown_operator",
1482
+ INVALID_VALUE: "invalid_value"
1483
+ };
687
1484
  var OPERATORS_BY_KIND = {
688
- string: /* @__PURE__ */ new Set(["includes", "notIncludes", "is", "isNot"]),
689
- number: /* @__PURE__ */ new Set([
690
- "equals",
691
- "notEquals",
692
- "greaterThan",
693
- "lessThan",
694
- "greaterOrEqual",
695
- "lessOrEqual",
696
- "between"
1485
+ [FILTER_VALUE_KIND.STRING]: /* @__PURE__ */ new Set([
1486
+ FILTER_OPERATOR.INCLUDES,
1487
+ FILTER_OPERATOR.NOT_INCLUDES,
1488
+ FILTER_OPERATOR.IS,
1489
+ FILTER_OPERATOR.IS_NOT
697
1490
  ]),
698
- date: /* @__PURE__ */ new Set(["after", "before", "between"]),
699
- "id-array": /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
700
- enum: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
701
- boolean: /* @__PURE__ */ new Set(["someOf", "notSomeOf"]),
702
- reference: /* @__PURE__ */ new Set(["someOf", "notSomeOf"])
1491
+ [FILTER_VALUE_KIND.NUMBER]: /* @__PURE__ */ new Set([
1492
+ FILTER_OPERATOR.EQUALS,
1493
+ FILTER_OPERATOR.NOT_EQUALS,
1494
+ FILTER_OPERATOR.GREATER_THAN,
1495
+ FILTER_OPERATOR.LESS_THAN,
1496
+ FILTER_OPERATOR.GREATER_OR_EQUAL,
1497
+ FILTER_OPERATOR.LESS_OR_EQUAL,
1498
+ FILTER_OPERATOR.BETWEEN
1499
+ ]),
1500
+ [FILTER_VALUE_KIND.DATE]: /* @__PURE__ */ new Set([
1501
+ FILTER_OPERATOR.AFTER,
1502
+ FILTER_OPERATOR.BEFORE,
1503
+ FILTER_OPERATOR.BETWEEN
1504
+ ]),
1505
+ [FILTER_VALUE_KIND.ID_ARRAY]: /* @__PURE__ */ new Set([
1506
+ FILTER_OPERATOR.SOME_OF,
1507
+ FILTER_OPERATOR.NOT_SOME_OF
1508
+ ]),
1509
+ [FILTER_VALUE_KIND.ENUM]: /* @__PURE__ */ new Set([
1510
+ FILTER_OPERATOR.SOME_OF,
1511
+ FILTER_OPERATOR.NOT_SOME_OF
1512
+ ]),
1513
+ [FILTER_VALUE_KIND.BOOLEAN]: /* @__PURE__ */ new Set([
1514
+ FILTER_OPERATOR.SOME_OF,
1515
+ FILTER_OPERATOR.NOT_SOME_OF
1516
+ ]),
1517
+ [FILTER_VALUE_KIND.REFERENCE]: /* @__PURE__ */ new Set([
1518
+ FILTER_OPERATOR.SOME_OF,
1519
+ FILTER_OPERATOR.NOT_SOME_OF
1520
+ ])
703
1521
  };
704
1522
  function normalizeDateRange(value) {
705
1523
  if (value === void 0) return { ok: true, dateRange: void 0 };
706
1524
  if (typeof value !== "object" || value === null) {
707
- return { ok: false, reason: "invalid_value" };
1525
+ return { ok: false, reason: FILTER_REJECTION_REASON.INVALID_VALUE };
708
1526
  }
709
1527
  const { start, end } = value;
710
1528
  if (!(start instanceof Date) || !(end instanceof Date)) {
711
- return { ok: false, reason: "invalid_value" };
1529
+ return { ok: false, reason: FILTER_REJECTION_REASON.INVALID_VALUE };
712
1530
  }
713
1531
  const startTime = start.getTime();
714
1532
  const endTime = end.getTime();
715
1533
  if (!Number.isFinite(startTime) || !Number.isFinite(endTime) || startTime > endTime) {
716
- return { ok: false, reason: "invalid_value" };
1534
+ return { ok: false, reason: FILTER_REJECTION_REASON.INVALID_VALUE };
717
1535
  }
718
1536
  return {
719
1537
  ok: true,
@@ -722,30 +1540,32 @@ function normalizeDateRange(value) {
722
1540
  }
723
1541
  function normalizeCriterion(criterion) {
724
1542
  const descriptor = getFieldDescriptor(criterion.field);
725
- if (descriptor === null) return { ok: false, reason: "unknown_field" };
1543
+ if (descriptor === null) {
1544
+ return { ok: false, reason: FILTER_REJECTION_REASON.UNKNOWN_FIELD };
1545
+ }
726
1546
  if (!OPERATORS_BY_KIND[descriptor.valueKind].has(criterion.operator)) {
727
- return { ok: false, reason: "unknown_operator" };
1547
+ return { ok: false, reason: FILTER_REJECTION_REASON.UNKNOWN_OPERATOR };
728
1548
  }
729
- if (criterion.operator === "between") {
1549
+ if (criterion.operator === FILTER_OPERATOR.BETWEEN) {
730
1550
  return normalizeBetweenCriterion(criterion, descriptor.valueKind);
731
1551
  }
732
- if (descriptor.valueKind === "number") {
1552
+ if (descriptor.valueKind === FILTER_VALUE_KIND.NUMBER) {
733
1553
  const value = normalizeNumberValue(criterion.value);
734
- return value === null ? { ok: false, reason: "invalid_value" } : {
1554
+ return value === null ? { ok: false, reason: FILTER_REJECTION_REASON.INVALID_VALUE } : {
735
1555
  ok: true,
736
1556
  criterion: { ...criterion, value }
737
1557
  };
738
1558
  }
739
- if (descriptor.valueKind === "date") {
1559
+ if (descriptor.valueKind === FILTER_VALUE_KIND.DATE) {
740
1560
  const value = normalizeDateValue(criterion.value);
741
- return value === null ? { ok: false, reason: "invalid_value" } : {
1561
+ return value === null ? { ok: false, reason: FILTER_REJECTION_REASON.INVALID_VALUE } : {
742
1562
  ok: true,
743
1563
  criterion: { ...criterion, value }
744
1564
  };
745
1565
  }
746
1566
  const rejection = validateValueForKind(criterion, descriptor.valueKind);
747
1567
  if (rejection !== null) return { ok: false, reason: rejection };
748
- if (descriptor.valueKind === "boolean") {
1568
+ if (descriptor.valueKind === FILTER_VALUE_KIND.BOOLEAN) {
749
1569
  return {
750
1570
  ok: true,
751
1571
  criterion: {
@@ -754,7 +1574,7 @@ function normalizeCriterion(criterion) {
754
1574
  }
755
1575
  };
756
1576
  }
757
- if (descriptor.valueKind === "id-array" || descriptor.valueKind === "enum" || descriptor.valueKind === "reference") {
1577
+ if (descriptor.valueKind === FILTER_VALUE_KIND.ID_ARRAY || descriptor.valueKind === FILTER_VALUE_KIND.ENUM || descriptor.valueKind === FILTER_VALUE_KIND.REFERENCE) {
758
1578
  return {
759
1579
  ok: true,
760
1580
  criterion: {
@@ -770,41 +1590,41 @@ function normalizeCriterion(criterion) {
770
1590
  return { ok: true, criterion };
771
1591
  }
772
1592
  function normalizeBetweenCriterion(criterion, valueKind) {
773
- if (valueKind === "number") {
1593
+ if (valueKind === FILTER_VALUE_KIND.NUMBER) {
774
1594
  const value = normalizeNumberValue(criterion.value);
775
1595
  const valueTo = normalizeNumberValue(criterion.valueTo);
776
1596
  if (value === null || valueTo === null || value > valueTo) {
777
- return { ok: false, reason: "invalid_value" };
1597
+ return { ok: false, reason: FILTER_REJECTION_REASON.INVALID_VALUE };
778
1598
  }
779
1599
  return {
780
1600
  ok: true,
781
1601
  criterion: { ...criterion, value, valueTo }
782
1602
  };
783
1603
  }
784
- if (valueKind === "date") {
1604
+ if (valueKind === FILTER_VALUE_KIND.DATE) {
785
1605
  const value = normalizeDateValue(criterion.value);
786
1606
  const valueTo = normalizeDateValue(criterion.valueTo);
787
1607
  if (value === null || valueTo === null || value.getTime() > valueTo.getTime()) {
788
- return { ok: false, reason: "invalid_value" };
1608
+ return { ok: false, reason: FILTER_REJECTION_REASON.INVALID_VALUE };
789
1609
  }
790
1610
  return {
791
1611
  ok: true,
792
1612
  criterion: { ...criterion, value, valueTo }
793
1613
  };
794
1614
  }
795
- return { ok: false, reason: "unknown_operator" };
1615
+ return { ok: false, reason: FILTER_REJECTION_REASON.UNKNOWN_OPERATOR };
796
1616
  }
797
1617
  function validateValueForKind(criterion, valueKind) {
798
1618
  const { value } = criterion;
799
- if (valueKind === "boolean") {
800
- return Array.isArray(value) && value.every((item) => typeof item === "boolean") ? null : "invalid_value";
1619
+ if (valueKind === FILTER_VALUE_KIND.BOOLEAN) {
1620
+ return Array.isArray(value) && value.every((item) => typeof item === "boolean") ? null : FILTER_REJECTION_REASON.INVALID_VALUE;
801
1621
  }
802
- if (valueKind === "id-array" || valueKind === "enum" || valueKind === "reference") {
1622
+ if (valueKind === FILTER_VALUE_KIND.ID_ARRAY || valueKind === FILTER_VALUE_KIND.ENUM || valueKind === FILTER_VALUE_KIND.REFERENCE) {
803
1623
  return Array.isArray(value) && value.every(
804
1624
  (item) => typeof item === "string" || typeof item === "number"
805
- ) ? null : "invalid_value";
1625
+ ) ? null : FILTER_REJECTION_REASON.INVALID_VALUE;
806
1626
  }
807
- if (Array.isArray(value)) return "invalid_value";
1627
+ if (Array.isArray(value)) return FILTER_REJECTION_REASON.INVALID_VALUE;
808
1628
  return null;
809
1629
  }
810
1630
  function normalizeNumberValue(value) {
@@ -852,455 +1672,198 @@ function resolveFilter(adapter, filter, hoursPerDay) {
852
1672
  });
853
1673
  return { visibleIds: projection.visibleIds, projection };
854
1674
  }
855
- function dispatchFilterSet(action, deps) {
856
- const { adapter, hoursPerDay } = deps;
857
- const criteria = [];
858
- for (const criterion of action.criteria) {
859
- const result = normalizeCriterion(criterion);
860
- if (!result.ok) return { ok: false, reason: result.reason };
861
- criteria.push(result.criterion);
862
- }
863
- const rangeResult = normalizeDateRange(action.dateRange);
864
- if (!rangeResult.ok) return { ok: false, reason: rangeResult.reason };
865
- const filter = cloneDomainValue(
866
- rangeResult.dateRange === void 0 ? { criteria, logic: action.logic } : {
867
- criteria,
868
- logic: action.logic,
869
- dateRange: rangeResult.dateRange
870
- }
871
- );
872
- adapter.setActiveFilter(isEmptyFilter(filter) ? null : filter);
873
- const { visibleIds, projection } = resolveFilter(
874
- adapter,
875
- filter,
876
- hoursPerDay
877
- );
878
- adapter.setFilterProjection(projection);
879
- const viewState = applyVisibleSet(adapter, visibleIds);
880
- const changes = {
881
- source: action,
882
- activities: [],
883
- links: [],
884
- calendars: [],
885
- trackingEvents: [],
886
- viewState
887
- };
888
- return { ok: true, changes };
889
- }
890
-
891
- // src/internal/hierarchy/root-parent.ts
892
- var ROOT_PARENT_ID = "0";
893
- var ROOT_PROJECT_CORRELATIVE_ID = 0;
894
- function isRootParent(parent) {
895
- return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
896
- }
897
- function normalizeParentKey(parent) {
898
- return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
899
- }
900
-
901
- // src/internal/hierarchy/visual-order.ts
902
- var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
903
- function getChildrenInVisualOrder(parentId, adapter) {
904
- const children = collectChildrenSnapshots(parentId, adapter);
905
- const userOrder = adapter.getOrderComparator?.() ?? null;
906
- children.sort(
907
- userOrder === null ? compareActivitiesInVisualOrder : (a, b) => userOrder(a, b) || compareActivitiesInVisualOrder(a, b)
908
- );
909
- return children.map((activity) => String(activity.id));
910
- }
911
- function iterateInVisualOrder(adapter) {
912
- const result = [];
913
- const visit = (activity) => {
914
- result.push(activity);
915
- const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
916
- for (const childId of childIds) {
917
- const child = adapter.getActivity(childId);
918
- if (child) visit(child);
919
- }
920
- };
921
- const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
922
- for (const rootId of rootIds) {
923
- const root = adapter.getActivity(rootId);
924
- if (root) visit(root);
925
- }
926
- return result;
927
- }
928
- function findPreviousNonSelectedSibling(taskId, selected, adapter) {
929
- const activity = adapter.getActivity(taskId);
930
- if (!activity) return null;
931
- const parentKey = parentKeyOf(activity);
932
- const siblings = getChildrenInVisualOrder(parentKey, adapter);
933
- const idx = siblings.findIndex((id) => String(id) === String(taskId));
934
- if (idx <= 0) return null;
935
- for (let i = idx - 1; i >= 0; i--) {
936
- const candidateId = siblings[i];
937
- if (candidateId === void 0) continue;
938
- if (!setHas(selected, candidateId)) return candidateId;
939
- }
940
- return null;
941
- }
942
- function visualIndexInParent(taskId, adapter) {
943
- const activity = adapter.getActivity(taskId);
944
- if (!activity) return -1;
945
- const parentKey = parentKeyOf(activity);
946
- const siblings = getChildrenInVisualOrder(parentKey, adapter);
947
- return siblings.findIndex((id) => String(id) === String(taskId));
948
- }
949
- function collectChildrenSnapshots(parentId, adapter) {
950
- const childIds = String(parentId) === ROOT_PARENT_ID ? adapter.getRootIds?.() ?? adapter.getChildren(ROOT_PARENT_ID) : adapter.getChildren(parentId);
951
- const out = [];
952
- for (const id of childIds) {
953
- const snap = adapter.getActivity(id);
954
- if (snap) out.push(snap);
955
- }
956
- return out;
957
- }
958
- function compareActivitiesInVisualOrder(a, b) {
959
- const ac = correlativeIdOf(a);
960
- const bc = correlativeIdOf(b);
961
- if (ac !== bc) return ac - bc;
962
- return String(a.id).localeCompare(String(b.id));
963
- }
964
- function correlativeIdOf(activity) {
965
- const raw = activity.correlativeId;
966
- const n = typeof raw === "number" ? raw : Number(raw);
967
- return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
968
- }
969
- function parentKeyOf(activity) {
970
- const parentId = activity.parentId;
971
- if (parentId === null) return "0";
972
- return parentId;
973
- }
974
- function setHas(set, id) {
975
- if (set.has(id)) return true;
976
- return set.has(String(id));
977
- }
978
-
979
- // src/dispatch/shared/collect-branch-order.ts
980
- function collectBranchOrder(adapter) {
981
- const branches = [];
982
- const visit = (parentId) => {
983
- const childIds = getChildrenInVisualOrder(parentId, adapter);
984
- if (childIds.length > 1) {
985
- branches.push({ parentId, childIds });
986
- }
987
- for (const childId of childIds) {
988
- visit(childId);
989
- }
990
- };
991
- visit(ROOT_PARENT_ID);
992
- return branches;
993
- }
994
- function collectBranchOrderForParents(adapter, parentIds) {
995
- const branches = [];
996
- for (const parentId of parentIds) {
997
- const childIds = getChildrenInVisualOrder(parentId, adapter);
998
- if (childIds.length > 1) branches.push({ parentId, childIds });
999
- }
1000
- return branches;
1001
- }
1002
-
1003
- // src/dispatch/order.ts
1004
- function validateRule(rule) {
1005
- if (getFieldDescriptor(rule.field) === null) return "unknown_field";
1006
- if (rule.direction !== "asc" && rule.direction !== "desc") {
1007
- return "unknown_operator";
1008
- }
1009
- return null;
1010
- }
1011
- function dispatchSortSet(action, deps) {
1012
- const { adapter } = deps;
1013
- for (const rule of action.rules) {
1014
- const rejection = validateRule(rule);
1015
- if (rejection !== null) return { ok: false, reason: rejection };
1016
- }
1017
- const order = action.rules.length === 0 ? null : cloneDomainValue({ rules: action.rules });
1018
- adapter.setActiveOrder(order);
1019
- const changes = {
1020
- source: action,
1021
- activities: [],
1022
- links: [],
1023
- calendars: [],
1024
- trackingEvents: [],
1025
- order: collectBranchOrder(adapter)
1026
- };
1027
- return { ok: true, changes };
1028
- }
1029
-
1030
- // src/constants/columns.ts
1031
- var EDITABLE = {
1032
- TEXT: "text",
1033
- DESCRIPTION: "description",
1034
- DURATION: "duration",
1035
- PROGRESS: "progress",
1036
- COST: "cost",
1037
- USED_COST: "used_cost",
1038
- HH_WORK_TIME: "hhWorkTime",
1039
- START_DATE: "start_date",
1040
- END_DATE: "end_date",
1041
- CONSTRAINT_TYPE: "constraint_type",
1042
- CONSTRAINT_DATE: "constraint_date",
1043
- CALENDAR_ID: "calendar_id",
1044
- CUSTOM_ID: "custom_id",
1045
- SUBCONTRACT_ID: "subcontractId",
1046
- RESPONSABLES: "responsables",
1047
- TAGS: "tags",
1048
- CUSTOM_PREDECESSORS: "custom_predecessors",
1049
- CUSTOM_SUCESSORS: "custom_sucessors"
1050
- };
1051
- var READ_ONLY = {
1052
- REAL_WORK: "real_work",
1053
- REAL_COST: "real_cost",
1054
- EXPECTED_PROGRESS: "expected_progress",
1055
- EXPECTED_PROGRESS_BASE: "expected_progress_base",
1056
- START_BASE: "start_base",
1057
- END_BASE: "end_base",
1058
- DURATION_BASE: "duration_base",
1059
- COST_BASE: "cost_base",
1060
- WORK_BASE: "work_base",
1061
- CALENDAR_DURATION: "calendarDuration",
1062
- IS_CRITICAL: "is_critical",
1063
- EARLY_START: "earlyStart",
1064
- EARLY_FINISH: "earlyFinish",
1065
- LATE_START: "lateStart",
1066
- LATE_FINISH: "lateFinish",
1067
- FREE_SLACK: "freeSlack",
1068
- TOTAL_SLACK: "totalSlack",
1069
- CORRELATIVE_ID: "correlative_id",
1070
- UNIQUE_CORRELATIVE_ID: "unique_correlative_id",
1071
- PONDERATOR: "ponderator",
1072
- STATUS: "status"
1073
- };
1074
- var COLUMN = { ...EDITABLE, ...READ_ONLY };
1075
-
1076
- // src/shared/assert-never.ts
1077
- function assertNever(value, message) {
1078
- throw new Error(message);
1079
- }
1080
-
1081
- // src/autoscheduler/utils/cancellation.ts
1082
- function createIsCurrent(id, getCurrentId) {
1083
- return () => getCurrentId() === id;
1675
+ function dispatchFilterSet(action, deps) {
1676
+ const { adapter, hoursPerDay } = deps;
1677
+ const criteria = [];
1678
+ for (const criterion of action.criteria) {
1679
+ const result = normalizeCriterion(criterion);
1680
+ if (!result.ok) return { ok: false, reason: result.reason };
1681
+ criteria.push(result.criterion);
1682
+ }
1683
+ const rangeResult = normalizeDateRange(action.dateRange);
1684
+ if (!rangeResult.ok) return { ok: false, reason: rangeResult.reason };
1685
+ const filter = cloneDomainValue(
1686
+ rangeResult.dateRange === void 0 ? { criteria, logic: action.logic } : {
1687
+ criteria,
1688
+ logic: action.logic,
1689
+ dateRange: rangeResult.dateRange
1690
+ }
1691
+ );
1692
+ adapter.setActiveFilter(isEmptyFilter(filter) ? null : filter);
1693
+ const { visibleIds, projection } = resolveFilter(
1694
+ adapter,
1695
+ filter,
1696
+ hoursPerDay
1697
+ );
1698
+ adapter.setFilterProjection(projection);
1699
+ const viewState = applyVisibleSet(adapter, visibleIds);
1700
+ const changes = {
1701
+ source: action,
1702
+ activities: [],
1703
+ links: [],
1704
+ calendars: [],
1705
+ trackingEvents: [],
1706
+ viewState
1707
+ };
1708
+ return { ok: true, changes };
1084
1709
  }
1085
1710
 
1086
- // src/types.ts
1087
- var WORK_TIME_DIRECTION = {
1088
- FUTURE: "future",
1089
- PAST: "past"
1090
- };
1091
- var CALENDAR_UNIT = {
1092
- HOUR: "hour",
1093
- DAY: "day"
1094
- };
1095
- var STATUS = {
1096
- DONE: "Done",
1097
- OVERDUE: "Overdue",
1098
- ADVANCEMENT: "Advancement",
1099
- WAITING: "Waiting",
1100
- DOING: "Doing"
1711
+ // src/internal/order/types.ts
1712
+ var ORDER_DIRECTION = {
1713
+ ASCENDING: "asc",
1714
+ DESCENDING: "desc"
1101
1715
  };
1102
1716
 
1103
- // src/constraints/index.ts
1104
- var CONSTRAINT_TYPE = {
1105
- ASAP: "asap",
1106
- ALAP: "alap",
1107
- SNET: "snet",
1108
- SNLT: "snlt",
1109
- FNET: "fnet",
1110
- FNLT: "fnlt",
1111
- MSO: "mso",
1112
- MFO: "mfo"
1113
- };
1114
- var VIOLATION_RULES = {
1115
- mso: () => true,
1116
- mfo: () => true,
1117
- snlt: (constraint, projected) => constraint < projected,
1118
- snet: (constraint, projected) => constraint > projected,
1119
- fnlt: (constraint, projected) => constraint < projected,
1120
- fnet: (constraint, projected) => constraint > projected
1121
- };
1122
- function checkConstraintViolation(constraintType, constraintDate, projectedDate) {
1123
- if (!constraintDate) return { violated: false };
1124
- const rule = VIOLATION_RULES[constraintType];
1125
- if (!rule) return { violated: false };
1126
- if (rule(constraintDate, projectedDate)) {
1127
- return { violated: true, constraintType, constraintDate };
1128
- }
1129
- return { violated: false };
1717
+ // src/internal/hierarchy/root-parent.ts
1718
+ var ROOT_PARENT_ID = "0";
1719
+ var ROOT_PROJECT_CORRELATIVE_ID = 0;
1720
+ function isRootParent(parent) {
1721
+ return parent == null || parent === 0 || parent === ROOT_PARENT_ID;
1130
1722
  }
1131
- var START_BASED_CONSTRAINTS = /* @__PURE__ */ new Set([
1132
- "mso",
1133
- "snet",
1134
- "snlt"
1135
- ]);
1136
- function pickProjectedDateForConstraint(constraintType, projectedStart, projectedEnd) {
1137
- return START_BASED_CONSTRAINTS.has(constraintType) ? projectedStart : projectedEnd;
1723
+ function normalizeParentKey(parent) {
1724
+ return isRootParent(parent) ? ROOT_PARENT_ID : String(parent);
1138
1725
  }
1139
- function buildConstraintNotification(constraintType, constraintDate, projectedDate) {
1140
- return {
1141
- type: "constraint",
1142
- messageKey: "constraint_violation",
1143
- data: {
1144
- constraintType,
1145
- constraintDate,
1146
- ...projectedDate ? { projectedDate } : {}
1726
+
1727
+ // src/internal/hierarchy/visual-order.ts
1728
+ var NOT_SET_SORT_VALUE = Number.MAX_SAFE_INTEGER;
1729
+ function getChildrenInVisualOrder(parentId, adapter) {
1730
+ const children = collectChildrenSnapshots(parentId, adapter);
1731
+ const userOrder = adapter.getOrderComparator?.() ?? null;
1732
+ children.sort(
1733
+ userOrder === null ? compareActivitiesInVisualOrder : (a, b) => userOrder(a, b) || compareActivitiesInVisualOrder(a, b)
1734
+ );
1735
+ return children.map((activity) => String(activity.id));
1736
+ }
1737
+ function iterateInVisualOrder(adapter) {
1738
+ const result = [];
1739
+ const visit = (activity) => {
1740
+ result.push(activity);
1741
+ const childIds = getChildrenInVisualOrder(String(activity.id), adapter);
1742
+ for (const childId of childIds) {
1743
+ const child = adapter.getActivity(childId);
1744
+ if (child) visit(child);
1147
1745
  }
1148
1746
  };
1149
- }
1150
- var CONSTRAINT_CASES = {
1151
- snet: { startOfDay: true, direction: WORK_TIME_DIRECTION.FUTURE },
1152
- snlt: { startOfDay: true, direction: WORK_TIME_DIRECTION.PAST },
1153
- fnet: { startOfDay: false, direction: WORK_TIME_DIRECTION.FUTURE },
1154
- fnlt: { startOfDay: false, direction: WORK_TIME_DIRECTION.PAST },
1155
- mso: { startOfDay: true, direction: WORK_TIME_DIRECTION.FUTURE },
1156
- mfo: { startOfDay: false, direction: WORK_TIME_DIRECTION.PAST }
1157
- };
1158
- var startOfUtcDay = (d) => new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
1159
- var addUtcDays = (d, n) => new Date(d.getTime() + n * 864e5);
1160
- var sameUtcDay = (a, b) => a.getUTCFullYear() === b.getUTCFullYear() && a.getUTCMonth() === b.getUTCMonth() && a.getUTCDate() === b.getUTCDate();
1161
- function getEffectiveConstraintDate(activity, adapter) {
1162
- if (!activity.constraintDate || !activity.constraintType) return null;
1163
- const config = CONSTRAINT_CASES[activity.constraintType];
1164
- if (!config) return activity.constraintDate;
1165
- const cd = activity.constraintDate;
1166
- const firstWorkOfDay = adapter.getClosestWorkTime({
1167
- date: startOfUtcDay(cd),
1168
- dir: WORK_TIME_DIRECTION.FUTURE,
1169
- task: activity
1170
- });
1171
- if (sameUtcDay(firstWorkOfDay, cd)) {
1172
- if (cd.getTime() !== startOfUtcDay(cd).getTime()) return cd;
1173
- if (config.startOfDay) return firstWorkOfDay;
1174
- return adapter.getClosestWorkTime({
1175
- date: addUtcDays(startOfUtcDay(cd), 1),
1176
- dir: WORK_TIME_DIRECTION.PAST,
1177
- task: activity
1178
- });
1747
+ const rootIds = getChildrenInVisualOrder(ROOT_PARENT_ID, adapter);
1748
+ for (const rootId of rootIds) {
1749
+ const root = adapter.getActivity(rootId);
1750
+ if (root) visit(root);
1179
1751
  }
1180
- const effectiveMidnight = startOfUtcDay(
1181
- adapter.getClosestWorkTime({
1182
- date: cd,
1183
- dir: config.direction,
1184
- task: activity
1185
- })
1186
- );
1187
- if (config.startOfDay) {
1188
- return adapter.getClosestWorkTime({
1189
- date: effectiveMidnight,
1190
- dir: WORK_TIME_DIRECTION.FUTURE,
1191
- task: activity
1192
- });
1752
+ return result;
1753
+ }
1754
+ function findPreviousNonSelectedSibling(taskId, selected, adapter) {
1755
+ const activity = adapter.getActivity(taskId);
1756
+ if (!activity) return null;
1757
+ const parentKey = parentKeyOf(activity);
1758
+ const siblings = getChildrenInVisualOrder(parentKey, adapter);
1759
+ const idx = siblings.findIndex((id) => String(id) === String(taskId));
1760
+ if (idx <= 0) return null;
1761
+ for (let i = idx - 1; i >= 0; i--) {
1762
+ const candidateId = siblings[i];
1763
+ if (candidateId === void 0) continue;
1764
+ if (!setHas(selected, candidateId)) return candidateId;
1193
1765
  }
1194
- return adapter.getClosestWorkTime({
1195
- date: addUtcDays(effectiveMidnight, 1),
1196
- dir: WORK_TIME_DIRECTION.PAST,
1197
- task: activity
1198
- });
1766
+ return null;
1199
1767
  }
1200
- function computeConstraintBounds(activity, adapter) {
1201
- const empty = {
1202
- earliestStart: null,
1203
- latestStart: null,
1204
- earliestEnd: null,
1205
- latestEnd: null
1206
- };
1207
- const type = activity.constraintType;
1208
- if (!type || type === "asap" || type === "alap") return empty;
1209
- const constraintDate = getEffectiveConstraintDate(activity, adapter);
1210
- if (!constraintDate) return empty;
1211
- const endFromStart = (start) => adapter.calculateEndDate({
1212
- startDate: start,
1213
- durationHours: activity.durationHours,
1214
- task: activity
1215
- });
1216
- const startFromEnd = (end) => adapter.calculateEndDate({
1217
- startDate: end,
1218
- durationHours: -activity.durationHours,
1219
- task: activity
1220
- });
1221
- switch (type) {
1222
- case "snet":
1223
- return {
1224
- earliestStart: constraintDate,
1225
- latestStart: null,
1226
- earliestEnd: endFromStart(constraintDate),
1227
- latestEnd: null
1228
- };
1229
- case "snlt":
1230
- return {
1231
- earliestStart: null,
1232
- latestStart: constraintDate,
1233
- earliestEnd: null,
1234
- latestEnd: endFromStart(constraintDate)
1235
- };
1236
- case "fnet":
1237
- return {
1238
- earliestStart: startFromEnd(constraintDate),
1239
- latestStart: null,
1240
- earliestEnd: constraintDate,
1241
- latestEnd: null
1242
- };
1243
- case "fnlt":
1244
- return {
1245
- earliestStart: null,
1246
- latestStart: startFromEnd(constraintDate),
1247
- earliestEnd: null,
1248
- latestEnd: constraintDate
1249
- };
1250
- case "mso": {
1251
- const end = endFromStart(constraintDate);
1252
- return {
1253
- earliestStart: constraintDate,
1254
- latestStart: constraintDate,
1255
- earliestEnd: end,
1256
- latestEnd: end
1257
- };
1768
+ function visualIndexInParent(taskId, adapter) {
1769
+ const activity = adapter.getActivity(taskId);
1770
+ if (!activity) return -1;
1771
+ const parentKey = parentKeyOf(activity);
1772
+ const siblings = getChildrenInVisualOrder(parentKey, adapter);
1773
+ return siblings.findIndex((id) => String(id) === String(taskId));
1774
+ }
1775
+ function collectChildrenSnapshots(parentId, adapter) {
1776
+ const childIds = String(parentId) === ROOT_PARENT_ID ? adapter.getRootIds?.() ?? adapter.getChildren(ROOT_PARENT_ID) : adapter.getChildren(parentId);
1777
+ const out = [];
1778
+ for (const id of childIds) {
1779
+ const snap = adapter.getActivity(id);
1780
+ if (snap) out.push(snap);
1781
+ }
1782
+ return out;
1783
+ }
1784
+ function compareActivitiesInVisualOrder(a, b) {
1785
+ const ac = correlativeIdOf(a);
1786
+ const bc = correlativeIdOf(b);
1787
+ if (ac !== bc) return ac - bc;
1788
+ return String(a.id).localeCompare(String(b.id));
1789
+ }
1790
+ function correlativeIdOf(activity) {
1791
+ const raw = activity.correlativeId;
1792
+ const n = typeof raw === "number" ? raw : Number(raw);
1793
+ return Number.isFinite(n) ? n : NOT_SET_SORT_VALUE;
1794
+ }
1795
+ function parentKeyOf(activity) {
1796
+ const parentId = activity.parentId;
1797
+ if (parentId === null) return "0";
1798
+ return parentId;
1799
+ }
1800
+ function setHas(set, id) {
1801
+ if (set.has(id)) return true;
1802
+ return set.has(String(id));
1803
+ }
1804
+
1805
+ // src/dispatch/shared/collect-branch-order.ts
1806
+ function collectBranchOrder(adapter) {
1807
+ const branches = [];
1808
+ const visit = (parentId) => {
1809
+ const childIds = getChildrenInVisualOrder(parentId, adapter);
1810
+ if (childIds.length > 1) {
1811
+ branches.push({ parentId, childIds });
1258
1812
  }
1259
- case "mfo": {
1260
- const start = startFromEnd(constraintDate);
1261
- return {
1262
- earliestStart: start,
1263
- latestStart: start,
1264
- earliestEnd: constraintDate,
1265
- latestEnd: constraintDate
1266
- };
1813
+ for (const childId of childIds) {
1814
+ visit(childId);
1267
1815
  }
1268
- default:
1269
- return empty;
1270
- }
1816
+ };
1817
+ visit(ROOT_PARENT_ID);
1818
+ return branches;
1271
1819
  }
1272
- function isStartWithinBounds(start, bounds) {
1273
- if (bounds.earliestStart && start < bounds.earliestStart) return false;
1274
- if (bounds.latestStart && start > bounds.latestStart) return false;
1275
- return true;
1820
+ function collectBranchOrderForParents(adapter, parentIds) {
1821
+ const branches = [];
1822
+ for (const parentId of parentIds) {
1823
+ const childIds = getChildrenInVisualOrder(parentId, adapter);
1824
+ if (childIds.length > 1) branches.push({ parentId, childIds });
1825
+ }
1826
+ return branches;
1276
1827
  }
1277
- function clampStartToBounds(candidate, bounds) {
1278
- if (bounds.latestStart && candidate > bounds.latestStart) {
1279
- return bounds.latestStart;
1828
+
1829
+ // src/dispatch/order.ts
1830
+ function validateRule(rule) {
1831
+ if (getFieldDescriptor(rule.field) === null) {
1832
+ return FILTER_REJECTION_REASON.UNKNOWN_FIELD;
1280
1833
  }
1281
- if (bounds.earliestStart && candidate < bounds.earliestStart) {
1282
- return bounds.earliestStart;
1834
+ if (rule.direction !== ORDER_DIRECTION.ASCENDING && rule.direction !== ORDER_DIRECTION.DESCENDING) {
1835
+ return FILTER_REJECTION_REASON.UNKNOWN_OPERATOR;
1283
1836
  }
1284
- return candidate;
1837
+ return null;
1838
+ }
1839
+ function dispatchSortSet(action, deps) {
1840
+ const { adapter } = deps;
1841
+ for (const rule of action.rules) {
1842
+ const rejection = validateRule(rule);
1843
+ if (rejection !== null) return { ok: false, reason: rejection };
1844
+ }
1845
+ const order = action.rules.length === 0 ? null : cloneDomainValue({ rules: action.rules });
1846
+ adapter.setActiveOrder(order);
1847
+ const changes = {
1848
+ source: action,
1849
+ activities: [],
1850
+ links: [],
1851
+ calendars: [],
1852
+ trackingEvents: [],
1853
+ order: collectBranchOrder(adapter)
1854
+ };
1855
+ return { ok: true, changes };
1285
1856
  }
1286
1857
 
1287
- // src/autoscheduler/types.ts
1288
- var LINK_TYPE = {
1289
- FINISH_TO_START: "0",
1290
- START_TO_START: "1",
1291
- FINISH_TO_FINISH: "2",
1292
- START_TO_FINISH: "3"
1293
- };
1858
+ // src/shared/assert-never.ts
1859
+ function assertNever(value, message) {
1860
+ throw new Error(message);
1861
+ }
1294
1862
 
1295
- // src/autoscheduler/constants.ts
1296
- var ACTIVITY_TYPE = {
1297
- TASK: "task",
1298
- PROJECT: "project",
1299
- MILESTONE: "milestone"
1300
- };
1301
- var TIMING = {
1302
- YIELD_SLICE_MS: 8
1303
- };
1863
+ // src/autoscheduler/utils/cancellation.ts
1864
+ function createIsCurrent(id, getCurrentId) {
1865
+ return () => getCurrentId() === id;
1866
+ }
1304
1867
 
1305
1868
  // src/shared/timing.ts
1306
1869
  var isNode = typeof window === "undefined";
@@ -1815,9 +2378,10 @@ function findConnectedGroupForTrigger(triggerId, links) {
1815
2378
  }
1816
2379
 
1817
2380
  // src/constants/progress.ts
2381
+ var NOT_STARTED_PROGRESS = 0;
1818
2382
  var COMPLETED_PROGRESS = 100;
1819
2383
  function isAutoSchedulingEnabledForProgress(progress) {
1820
- return progress === 0;
2384
+ return progress === NOT_STARTED_PROGRESS;
1821
2385
  }
1822
2386
 
1823
2387
  // src/autoscheduler/engine/link-calculator.ts
@@ -2759,11 +3323,11 @@ function corruptActivityIds(edges) {
2759
3323
  // src/autoscheduler/links/apply-link-operation.ts
2760
3324
  function applyLinkOperation(op, deps) {
2761
3325
  switch (op.kind) {
2762
- case "create":
3326
+ case LINK_OPERATION_KIND.CREATE:
2763
3327
  return applyCreate(op, deps);
2764
- case "update":
3328
+ case LINK_OPERATION_KIND.UPDATE:
2765
3329
  return applyLinkUpdate(op, deps.port);
2766
- case "delete":
3330
+ case LINK_OPERATION_KIND.DELETE:
2767
3331
  return applyDelete(op, deps);
2768
3332
  }
2769
3333
  }
@@ -2781,15 +3345,24 @@ function applyLinkCreates(links, deps) {
2781
3345
  let rejected = null;
2782
3346
  for (const { operation, linkId } of links) {
2783
3347
  if (String(operation.source) === String(operation.target)) {
2784
- rejected = { applied: false, rejected: "self-link" };
3348
+ rejected = {
3349
+ applied: false,
3350
+ rejected: LINK_REJECTION_REASON.SELF_LINK
3351
+ };
2785
3352
  break;
2786
3353
  }
2787
3354
  if (!deps.port.getActivity(operation.source) || !deps.port.getActivity(operation.target)) {
2788
- rejected = { applied: false, rejected: "activity-missing" };
3355
+ rejected = {
3356
+ applied: false,
3357
+ rejected: LINK_REJECTION_REASON.ACTIVITY_MISSING
3358
+ };
2789
3359
  break;
2790
3360
  }
2791
3361
  if (isSummaryHierarchyLink(operation.source, operation.target, deps.port)) {
2792
- rejected = { applied: false, rejected: "hierarchy-link" };
3362
+ rejected = {
3363
+ applied: false,
3364
+ rejected: LINK_REJECTION_REASON.HIERARCHY_LINK
3365
+ };
2793
3366
  break;
2794
3367
  }
2795
3368
  const key = linkKey(operation);
@@ -2797,7 +3370,7 @@ function applyLinkCreates(links, deps) {
2797
3370
  if (duplicateId !== void 0) {
2798
3371
  rejected = {
2799
3372
  applied: false,
2800
- rejected: "duplicate",
3373
+ rejected: LINK_REJECTION_REASON.DUPLICATE,
2801
3374
  linkId: duplicateId
2802
3375
  };
2803
3376
  break;
@@ -2807,12 +3380,12 @@ function applyLinkCreates(links, deps) {
2807
3380
  source: operation.source,
2808
3381
  target: operation.target
2809
3382
  })) {
2810
- return { applied: false, rejected: "cycle" };
3383
+ return { applied: false, rejected: LINK_REJECTION_REASON.CYCLE };
2811
3384
  }
2812
3385
  edges.push({ source: operation.source, target: operation.target });
2813
3386
  }
2814
3387
  if (!existingGraphHasCycle && hasDirectedCycle(edges)) {
2815
- return { applied: false, rejected: "cycle" };
3388
+ return { applied: false, rejected: LINK_REJECTION_REASON.CYCLE };
2816
3389
  }
2817
3390
  if (rejected) return rejected;
2818
3391
  const proposedLinks = [
@@ -2833,7 +3406,7 @@ function applyLinkCreates(links, deps) {
2833
3406
  proposedLinks
2834
3407
  });
2835
3408
  if (!effectiveVerdict.ok) {
2836
- return { applied: false, rejected: "cycle" };
3409
+ return { applied: false, rejected: LINK_REJECTION_REASON.CYCLE };
2837
3410
  }
2838
3411
  for (const { operation, linkId } of links) {
2839
3412
  const preserved = deps.preserved?.get(linkId);
@@ -2858,20 +3431,30 @@ function linkKey(link) {
2858
3431
  function applyCreate(op, deps) {
2859
3432
  const { port } = deps;
2860
3433
  if (String(op.source) === String(op.target)) {
2861
- return { applied: false, rejected: "self-link" };
3434
+ return { applied: false, rejected: LINK_REJECTION_REASON.SELF_LINK };
2862
3435
  }
2863
3436
  const src = port.getActivity(op.source);
2864
3437
  const tgt = port.getActivity(op.target);
2865
3438
  if (!src || !tgt) {
2866
- return { applied: false, rejected: "activity-missing" };
3439
+ return {
3440
+ applied: false,
3441
+ rejected: LINK_REJECTION_REASON.ACTIVITY_MISSING
3442
+ };
2867
3443
  }
2868
3444
  if (isSummaryHierarchyLink(op.source, op.target, port)) {
2869
- return { applied: false, rejected: "hierarchy-link" };
3445
+ return {
3446
+ applied: false,
3447
+ rejected: LINK_REJECTION_REASON.HIERARCHY_LINK
3448
+ };
2870
3449
  }
2871
3450
  const existingLinks = port.getAllLinks();
2872
3451
  for (const l of existingLinks) {
2873
3452
  if (String(l.source) === String(op.source) && String(l.target) === String(op.target) && l.type === op.type) {
2874
- return { applied: false, rejected: "duplicate", linkId: l.id };
3453
+ return {
3454
+ applied: false,
3455
+ rejected: LINK_REJECTION_REASON.DUPLICATE,
3456
+ linkId: l.id
3457
+ };
2875
3458
  }
2876
3459
  }
2877
3460
  const asEdges = existingLinks.map((l) => ({
@@ -2879,7 +3462,7 @@ function applyCreate(op, deps) {
2879
3462
  target: l.target
2880
3463
  }));
2881
3464
  if (wouldIntroduceCycle(asEdges, { source: op.source, target: op.target })) {
2882
- return { applied: false, rejected: "cycle" };
3465
+ return { applied: false, rejected: LINK_REJECTION_REASON.CYCLE };
2883
3466
  }
2884
3467
  const id = (deps.newLinkId ?? defaultNewLinkId)();
2885
3468
  const link = {
@@ -2897,14 +3480,16 @@ function applyCreate(op, deps) {
2897
3480
  proposedLinks: [...existingLinks, link]
2898
3481
  });
2899
3482
  if (!effectiveVerdict.ok) {
2900
- return { applied: false, rejected: "cycle" };
3483
+ return { applied: false, rejected: LINK_REJECTION_REASON.CYCLE };
2901
3484
  }
2902
3485
  port.addLink(link);
2903
3486
  return { applied: true, linkId: id };
2904
3487
  }
2905
3488
  function applyLinkUpdate(op, port) {
2906
3489
  const link = port.getLink(op.linkId);
2907
- if (!link) return { applied: false, rejected: "link-missing" };
3490
+ if (!link) {
3491
+ return { applied: false, rejected: LINK_REJECTION_REASON.LINK_MISSING };
3492
+ }
2908
3493
  if (op.lag !== void 0) port.setLinkField(op.linkId, "lag", op.lag);
2909
3494
  if (op.type !== void 0) port.setLinkField(op.linkId, "type", op.type);
2910
3495
  return { applied: true, linkId: op.linkId };
@@ -2912,7 +3497,9 @@ function applyLinkUpdate(op, port) {
2912
3497
  function applyDelete(op, deps) {
2913
3498
  const { port } = deps;
2914
3499
  const link = port.getLink(op.linkId);
2915
- if (!link) return { applied: false, rejected: "link-missing" };
3500
+ if (!link) {
3501
+ return { applied: false, rejected: LINK_REJECTION_REASON.LINK_MISSING };
3502
+ }
2916
3503
  port.removeLink(op.linkId);
2917
3504
  return { applied: true, linkId: op.linkId };
2918
3505
  }
@@ -3104,8 +3691,8 @@ var currentImpl = {
3104
3691
  };
3105
3692
 
3106
3693
  // src/autoscheduler/date-math/types.ts
3107
- function pickDatesForLinkType(source, target, linkType) {
3108
- switch (linkType) {
3694
+ function pickDatesForLinkType(source, target, linkType2) {
3695
+ switch (linkType2) {
3109
3696
  case "0":
3110
3697
  return { sourceDate: source.endDate, targetDate: target.startDate };
3111
3698
  case "1":
@@ -4848,13 +5435,34 @@ function findPipelineForColumn(columnName) {
4848
5435
  return COLUMN_PIPELINES.get(columnName);
4849
5436
  }
4850
5437
 
5438
+ // src/dispatch/types.ts
5439
+ var ACTIVITY_BATCH_MODE = {
5440
+ APPEND: "append",
5441
+ REPLACE: "replace"
5442
+ };
5443
+ var SCHEDULE_EFFECT_KIND = {
5444
+ SIR_AUTO_REJECT: "sir-auto-reject"
5445
+ };
5446
+ var SIR_AUTO_REJECT_REASON = {
5447
+ DATE_CHANGED: "date_changed",
5448
+ ACTIVITY_DELETED: "activity_deleted"
5449
+ };
5450
+ var CONSTRAINT_WARNING_KIND = {
5451
+ VIOLATION: "constraint_violation"
5452
+ };
5453
+ var CHANGE_SET_SOURCE_KIND = {
5454
+ INIT: "init",
5455
+ UNDO: "undo",
5456
+ REDO: "redo"
5457
+ };
5458
+
4851
5459
  // src/dispatch/shared/constraint-warnings.ts
4852
5460
  function toConstraintWarning(activityId, notification) {
4853
5461
  if (!notification || notification.type !== "constraint") return null;
4854
5462
  const data = notification.data;
4855
5463
  if (!data?.constraintType || !data.constraintDate) return null;
4856
5464
  return {
4857
- kind: "constraint_violation",
5465
+ kind: CONSTRAINT_WARNING_KIND.VIOLATION,
4858
5466
  activityId,
4859
5467
  constraintType: data.constraintType,
4860
5468
  constraintDate: data.constraintDate,
@@ -5230,13 +5838,6 @@ function applyExpectedProgressLive(state, now) {
5230
5838
  computeExpectedProgressLive(rootIds, now, state);
5231
5839
  }
5232
5840
 
5233
- // src/propagations/shared/get-active-baseline.ts
5234
- function getActiveBaseline(activity) {
5235
- const points = activity?.baselinePoints;
5236
- if (!Array.isArray(points) || points.length === 0) return null;
5237
- return points.find((point) => point.isActiveVersion) ?? null;
5238
- }
5239
-
5240
5841
  // src/columns/expected-progress-base/compute.ts
5241
5842
  var isProject2 = (a) => a.type === "project";
5242
5843
  var activeBaselineOf = (a) => getActiveBaseline(a);
@@ -5295,15 +5896,15 @@ function runExpectedProgressBase(state, now, defaultBaseCalendarId = null) {
5295
5896
  }
5296
5897
 
5297
5898
  // src/columns/status/constants.ts
5298
- var DEFAULT_STATUS_CRITERIA = "Baseline";
5899
+ var DEFAULT_STATUS_CRITERIA = STATUS_CRITERIA.BASELINE;
5299
5900
  function resolveStatusCriteria(value) {
5300
- return value === "Actual" ? "Actual" : DEFAULT_STATUS_CRITERIA;
5901
+ return value === STATUS_CRITERIA.ACTUAL ? STATUS_CRITERIA.ACTUAL : DEFAULT_STATUS_CRITERIA;
5301
5902
  }
5302
5903
 
5303
5904
  // src/columns/status/compute.ts
5304
5905
  var roundToTwoDecimals = (value) => Math.round(value * 100) / 100;
5305
5906
  function resolveExpectedForStatus(activity, criteria) {
5306
- const value = criteria === "Baseline" ? activity.expectedProgressBaseline : activity.expectedProgress;
5907
+ const value = criteria === STATUS_CRITERIA.BASELINE ? activity.expectedProgressBaseline : activity.expectedProgress;
5307
5908
  return value ?? void 0;
5308
5909
  }
5309
5910
  function deriveActivityStatus(progress, expectedProgress) {
@@ -5430,7 +6031,7 @@ var CONSTRAINT_TYPES = Object.freeze({
5430
6031
  });
5431
6032
 
5432
6033
  // src/critical-path/legacy/constants/linkTypes.js
5433
- var LINK_TYPES = Object.freeze({
6034
+ var LINK_TYPES2 = Object.freeze({
5434
6035
  FS: "fs",
5435
6036
  SS: "ss",
5436
6037
  FF: "ff",
@@ -5718,13 +6319,13 @@ function getMaxEarlyStartSet(arrayCalculatedLinks) {
5718
6319
 
5719
6320
  // src/critical-path/legacy/base/parents-calculations/helpers.js
5720
6321
  function mutateDate({
5721
- linkType,
6322
+ linkType: linkType2,
5722
6323
  lag,
5723
6324
  predecessorTime,
5724
6325
  activityCalendar,
5725
6326
  activity
5726
6327
  }) {
5727
- if (linkType === LINK_TYPES.FS && lag === 0) {
6328
+ if (linkType2 === LINK_TYPES2.FS && lag === 0) {
5728
6329
  return getNextWorkingHour({
5729
6330
  activityCalendar,
5730
6331
  direction: "future",
@@ -5733,7 +6334,7 @@ function mutateDate({
5733
6334
  } else {
5734
6335
  return mutateTheDateToFutureOrPastInBaseRestriction(
5735
6336
  predecessorTime,
5736
- linkType,
6337
+ linkType2,
5737
6338
  activityCalendar,
5738
6339
  activity
5739
6340
  );
@@ -5760,10 +6361,10 @@ function calculateRestrictionSnet({
5760
6361
  return { es, ef };
5761
6362
  }
5762
6363
  function mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar, activity) {
5763
- if (![LINK_TYPES.FS, LINK_TYPES.SS, LINK_TYPES.FF].includes(restrictionOfLink)) {
6364
+ if (![LINK_TYPES2.FS, LINK_TYPES2.SS, LINK_TYPES2.FF].includes(restrictionOfLink)) {
5764
6365
  return dateBaseToCalculate;
5765
6366
  }
5766
- let constraintThatGoToNextWorkingHour = [LINK_TYPES.FS, LINK_TYPES.SS];
6367
+ let constraintThatGoToNextWorkingHour = [LINK_TYPES2.FS, LINK_TYPES2.SS];
5767
6368
  let direction = constraintThatGoToNextWorkingHour.includes(restrictionOfLink) ? "future" : "past";
5768
6369
  return getNextWorkingHour({
5769
6370
  dateBaseToCalculate,
@@ -5803,18 +6404,18 @@ var CalculateForwardParentsWithLinks = class {
5803
6404
  const calculations = [];
5804
6405
  for (const linkedActivity of this.linkedActivitiesData) {
5805
6406
  const linkTypeCode = linkedActivity.linkType;
5806
- const linkType = getLinkNameByCode(linkTypeCode);
6407
+ const linkType2 = getLinkNameByCode(linkTypeCode);
5807
6408
  const lag = linkedActivity.linkLag;
5808
6409
  const predecessorEs = linkedActivity.es;
5809
6410
  const predecessorEf = linkedActivity.ef;
5810
6411
  let calculation = null;
5811
- if (linkType === "ss") {
6412
+ if (linkType2 === "ss") {
5812
6413
  calculation = this.calculateSSLink({ lag, predecessorEs });
5813
- } else if (linkType === "ff") {
6414
+ } else if (linkType2 === "ff") {
5814
6415
  calculation = this.calculateFFLink({ lag, predecessorEf });
5815
- } else if (linkType === "fs") {
6416
+ } else if (linkType2 === "fs") {
5816
6417
  calculation = this.calculateFSLink({ lag, predecessorEf });
5817
- } else if (linkType === "sf") {
6418
+ } else if (linkType2 === "sf") {
5818
6419
  calculation = this.calculateSFLink({
5819
6420
  lag,
5820
6421
  predecessorEs,
@@ -5983,7 +6584,7 @@ var CalculateBackwardParentsLinks = class {
5983
6584
  }
5984
6585
  const calculationsFromLinks = [];
5985
6586
  for (let linkedActivity of this.linkedActivitiesData) {
5986
- const linkType = getLinkNameByCode(linkedActivity.linkType);
6587
+ const linkType2 = getLinkNameByCode(linkedActivity.linkType);
5987
6588
  if (linkedActivity.type === "task" && Number(linkedActivity.progress) > 0) {
5988
6589
  continue;
5989
6590
  }
@@ -5993,7 +6594,7 @@ var CalculateBackwardParentsLinks = class {
5993
6594
  const lag = linkedActivity.linkLag;
5994
6595
  let sucessorLs = linkedActivity.ls;
5995
6596
  let sucessorLf = linkedActivity.lf;
5996
- if (linkType === "ss") {
6597
+ if (linkType2 === "ss") {
5997
6598
  const valuesToDoCalculation = {
5998
6599
  lag,
5999
6600
  workTime: sucessorLs,
@@ -6003,7 +6604,7 @@ var CalculateBackwardParentsLinks = class {
6003
6604
  let { ls, lf } = this.calculateSSLink(valuesToDoCalculation);
6004
6605
  calculationsFromLinks.push({ ls, lf });
6005
6606
  }
6006
- if (linkType === "ff") {
6607
+ if (linkType2 === "ff") {
6007
6608
  const valuesToDoCalculation = {
6008
6609
  lag,
6009
6610
  workTime: sucessorLf,
@@ -6013,7 +6614,7 @@ var CalculateBackwardParentsLinks = class {
6013
6614
  let { ls, lf } = this.calculateFFLink(valuesToDoCalculation);
6014
6615
  calculationsFromLinks.push({ ls, lf });
6015
6616
  }
6016
- if (linkType === "fs") {
6617
+ if (linkType2 === "fs") {
6017
6618
  const valuesToDoCalculation = {
6018
6619
  lag,
6019
6620
  workTime: sucessorLs,
@@ -6023,7 +6624,7 @@ var CalculateBackwardParentsLinks = class {
6023
6624
  let { ls, lf } = this.calculateFsLink(valuesToDoCalculation);
6024
6625
  calculationsFromLinks.push({ ls, lf });
6025
6626
  }
6026
- if (linkType === "sf") {
6627
+ if (linkType2 === "sf") {
6027
6628
  const valuesToDoCalculation = {
6028
6629
  lag,
6029
6630
  workTime: sucessorLf,
@@ -7213,7 +7814,7 @@ var LinksRulesCalculationsMethods = class {
7213
7814
  }
7214
7815
  return this.calculatedActivities.get(Number(activity));
7215
7816
  }
7216
- calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES.FS) {
7817
+ calculateSucessorTimes(predecessorTime, esDataCalculation, efDataCalculation = 0, lag, restrictionOfLink = LINK_TYPES2.FS) {
7217
7818
  const activityCalendar = this.gantt.getCalendar(
7218
7819
  this.referenceActivity.calendar_id
7219
7820
  );
@@ -7227,7 +7828,7 @@ var LinksRulesCalculationsMethods = class {
7227
7828
  let ef = null;
7228
7829
  const isAMilestone = this.referenceActivity.type === "milestone";
7229
7830
  if (!isAMilestone) {
7230
- if (restrictionOfLink === LINK_TYPES.FS && lag === 0) {
7831
+ if (restrictionOfLink === LINK_TYPES2.FS && lag === 0) {
7231
7832
  dateBaseToCalculate = getNextWorkingHour({
7232
7833
  dateBaseToCalculate,
7233
7834
  activityCalendar,
@@ -7242,7 +7843,7 @@ var LinksRulesCalculationsMethods = class {
7242
7843
  );
7243
7844
  }
7244
7845
  }
7245
- if ([LINK_TYPES.FF, LINK_TYPES.SF].includes(restrictionOfLink)) {
7846
+ if ([LINK_TYPES2.FF, LINK_TYPES2.SF].includes(restrictionOfLink)) {
7246
7847
  ef = addDurationToDate(
7247
7848
  activityCalendar,
7248
7849
  dateBaseToCalculate,
@@ -7296,7 +7897,7 @@ var LinksRulesCalculationsMethods = class {
7296
7897
  esDataCalculation,
7297
7898
  efDataCalculation,
7298
7899
  lag,
7299
- LINK_TYPES.SS
7900
+ LINK_TYPES2.SS
7300
7901
  );
7301
7902
  }
7302
7903
  calculateFF(link) {
@@ -7310,7 +7911,7 @@ var LinksRulesCalculationsMethods = class {
7310
7911
  esDataCalculation,
7311
7912
  efDataCalculation,
7312
7913
  lag,
7313
- LINK_TYPES.FF
7914
+ LINK_TYPES2.FF
7314
7915
  );
7315
7916
  }
7316
7917
  calculateFS(link) {
@@ -7324,7 +7925,7 @@ var LinksRulesCalculationsMethods = class {
7324
7925
  esDataCalculation,
7325
7926
  efDataCalculation,
7326
7927
  lag,
7327
- LINK_TYPES.FS
7928
+ LINK_TYPES2.FS
7328
7929
  );
7329
7930
  }
7330
7931
  calculateSF(link) {
@@ -7338,14 +7939,14 @@ var LinksRulesCalculationsMethods = class {
7338
7939
  esDataCalculation,
7339
7940
  efDataCalculation,
7340
7941
  lag,
7341
- LINK_TYPES.SF
7942
+ LINK_TYPES2.SF
7342
7943
  );
7343
7944
  }
7344
7945
  mutateTheDateToFutureOrPastInBaseRestriction(dateBaseToCalculate, restrictionOfLink, activityCalendar) {
7345
- if (![LINK_TYPES.FS, LINK_TYPES.SS, LINK_TYPES.FF].includes(restrictionOfLink)) {
7946
+ if (![LINK_TYPES2.FS, LINK_TYPES2.SS, LINK_TYPES2.FF].includes(restrictionOfLink)) {
7346
7947
  return dateBaseToCalculate;
7347
7948
  }
7348
- const constraintThatGoToNextWorkingHour = [LINK_TYPES.FS, LINK_TYPES.SS];
7949
+ const constraintThatGoToNextWorkingHour = [LINK_TYPES2.FS, LINK_TYPES2.SS];
7349
7950
  const direction = constraintThatGoToNextWorkingHour.includes(
7350
7951
  restrictionOfLink
7351
7952
  ) ? "future" : "past";
@@ -7880,7 +8481,7 @@ var CalculationsGenericMethods = class {
7880
8481
  }
7881
8482
  return this.calculatedActivities.get(activity);
7882
8483
  }
7883
- calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES.FS) {
8484
+ calculateSuccessorTimes(sucessorTime, lsDataCalculation, lfDataCalculation = 0, lag, type = LINK_TYPES2.FS) {
7884
8485
  let activityCalendar = this.gantt.getCalendar(this.activity.calendar_id);
7885
8486
  if (!activityCalendar) {
7886
8487
  throw new Error(
@@ -7912,19 +8513,19 @@ var CalculationsGenericMethods = class {
7912
8513
  lfDataCalculation,
7913
8514
  isMilestone
7914
8515
  };
7915
- if (type === LINK_TYPES.FS) {
8516
+ if (type === LINK_TYPES2.FS) {
7916
8517
  let { ls, lf } = this.calculateFsLink(valuesToDoCalculation);
7917
8518
  return { ls, lf };
7918
8519
  }
7919
- if (type === LINK_TYPES.FF) {
8520
+ if (type === LINK_TYPES2.FF) {
7920
8521
  let { ls, lf } = this.calculateFFLink(valuesToDoCalculation);
7921
8522
  return { ls, lf };
7922
8523
  }
7923
- if (type === LINK_TYPES.SS) {
8524
+ if (type === LINK_TYPES2.SS) {
7924
8525
  let { ls, lf } = this.calculateSSlink(valuesToDoCalculation);
7925
8526
  return { ls, lf };
7926
8527
  }
7927
- if (type === LINK_TYPES.SF) {
8528
+ if (type === LINK_TYPES2.SF) {
7928
8529
  let { ls, lf } = this.calculateSFLink(valuesToDoCalculation);
7929
8530
  return { ls, lf };
7930
8531
  }
@@ -7939,7 +8540,7 @@ var CalculationsGenericMethods = class {
7939
8540
  lsDataForCalculation,
7940
8541
  lfDataForCalculation,
7941
8542
  lag,
7942
- LINK_TYPES.SS
8543
+ LINK_TYPES2.SS
7943
8544
  );
7944
8545
  }
7945
8546
  calculateFF(link, constraint) {
@@ -7956,7 +8557,7 @@ var CalculationsGenericMethods = class {
7956
8557
  lsDataForCalculation,
7957
8558
  lfDataForCalculation,
7958
8559
  lag,
7959
- LINK_TYPES.FF
8560
+ LINK_TYPES2.FF
7960
8561
  );
7961
8562
  }
7962
8563
  calculateFS(link, constraint) {
@@ -7974,7 +8575,7 @@ var CalculationsGenericMethods = class {
7974
8575
  lsDataForCalculation,
7975
8576
  lfDataForCalculation,
7976
8577
  lag,
7977
- LINK_TYPES.FS
8578
+ LINK_TYPES2.FS
7978
8579
  );
7979
8580
  }
7980
8581
  calculateSF(link, getFromForward = false) {
@@ -7987,7 +8588,7 @@ var CalculationsGenericMethods = class {
7987
8588
  lsDataForCalculation,
7988
8589
  lfDataForCalculation,
7989
8590
  lag,
7990
- LINK_TYPES.SF
8591
+ LINK_TYPES2.SF
7991
8592
  );
7992
8593
  }
7993
8594
  getEarlyStartFromForwardPath(link) {
@@ -9175,7 +9776,7 @@ var FreeFloat = class {
9175
9776
  }
9176
9777
  return constraint_type;
9177
9778
  }
9178
- getDatesFromSucessorAndPredecessor(linkType, constraint, sucessor) {
9779
+ getDatesFromSucessorAndPredecessor(linkType2, constraint, sucessor) {
9179
9780
  const isSuscessorAlap = sucessor.constraint_type === CONSTRAINT_TYPES.ALAP;
9180
9781
  const constraintData = this.getSucessorAndPredecessorDates({
9181
9782
  constraint,
@@ -9185,8 +9786,8 @@ var FreeFloat = class {
9185
9786
  });
9186
9787
  let sucessorDateToCalculate = /* @__PURE__ */ new Date();
9187
9788
  let predecessorDateToCalculate = /* @__PURE__ */ new Date();
9188
- sucessorDateToCalculate = constraintData[linkType].sucessor;
9189
- predecessorDateToCalculate = constraintData[linkType].predecessor;
9789
+ sucessorDateToCalculate = constraintData[linkType2].sucessor;
9790
+ predecessorDateToCalculate = constraintData[linkType2].predecessor;
9190
9791
  return {
9191
9792
  sucessorDateToCalculate,
9192
9793
  predecessorDateToCalculate
@@ -10358,10 +10959,10 @@ function detectSirAutoReject(beforeSnap, adapter, touchedIds) {
10358
10959
  if (adapter.getActivity(id) != null) continue;
10359
10960
  for (const pending of pendingRequestIds) {
10360
10961
  effects.push({
10361
- kind: "sir-auto-reject",
10962
+ kind: SCHEDULE_EFFECT_KIND.SIR_AUTO_REJECT,
10362
10963
  activityId: id,
10363
10964
  sirId: pending,
10364
- reason: "activity_deleted"
10965
+ reason: SIR_AUTO_REJECT_REASON.ACTIVITY_DELETED
10365
10966
  });
10366
10967
  }
10367
10968
  }
@@ -10802,11 +11403,57 @@ async function dispatchInlineEdit(action, options, deps) {
10802
11403
  }
10803
11404
 
10804
11405
  // src/dispatch/handlers/link.ts
11406
+ var LINK_TYPE_VALUES = new Set(Object.values(LINK_TYPE));
11407
+ function isValidLinkType(value) {
11408
+ return typeof value === "string" && LINK_TYPE_VALUES.has(value);
11409
+ }
11410
+ function hasOwn(value, property) {
11411
+ return Object.hasOwn(value, property);
11412
+ }
11413
+ function validateLinkAction(action) {
11414
+ if (action.kind === DISPATCH_ACTION_KIND.LINK_CREATE) {
11415
+ if (!isValidLinkType(action.type)) {
11416
+ return REJECTION_REASON.INVALID_LINK_TYPE;
11417
+ }
11418
+ return action.lag === void 0 || Number.isFinite(action.lag) ? null : REJECTION_REASON.INVALID_LINK_LAG;
11419
+ }
11420
+ if (action.kind === DISPATCH_ACTION_KIND.LINK_UPDATE) {
11421
+ if (hasOwn(action, "type") && !isValidLinkType(action.type)) {
11422
+ return REJECTION_REASON.INVALID_LINK_TYPE;
11423
+ }
11424
+ if (hasOwn(action, "lag") && !Number.isFinite(action.lag)) {
11425
+ return REJECTION_REASON.INVALID_LINK_LAG;
11426
+ }
11427
+ }
11428
+ return null;
11429
+ }
11430
+ function validateLinkBatchOperation(operation) {
11431
+ if (operation.kind === DISPATCH_LINK_OPERATION_KIND.CREATE) {
11432
+ if (!isValidLinkType(operation.type)) {
11433
+ return REJECTION_REASON.INVALID_LINK_TYPE;
11434
+ }
11435
+ return operation.lag === void 0 || Number.isFinite(operation.lag) ? null : REJECTION_REASON.INVALID_LINK_LAG;
11436
+ }
11437
+ if (operation.kind === DISPATCH_LINK_OPERATION_KIND.UPDATE) {
11438
+ if (hasOwn(operation, "type") && !isValidLinkType(operation.type)) {
11439
+ return REJECTION_REASON.INVALID_LINK_TYPE;
11440
+ }
11441
+ return !hasOwn(operation, "lag") || Number.isFinite(operation.lag) ? null : REJECTION_REASON.INVALID_LINK_LAG;
11442
+ }
11443
+ return operation.kind === DISPATCH_LINK_OPERATION_KIND.DELETE ? null : REJECTION_REASON.INVALID_VALUE;
11444
+ }
11445
+ function validateLinkBatch(operations) {
11446
+ for (const operation of operations) {
11447
+ const error = validateLinkBatchOperation(operation);
11448
+ if (error !== null) return error;
11449
+ }
11450
+ return null;
11451
+ }
10805
11452
  function collectBatchContext(operations, adapter) {
10806
11453
  const activityIds = /* @__PURE__ */ new Set();
10807
11454
  const links = /* @__PURE__ */ new Map();
10808
11455
  for (const operation of operations) {
10809
- if (operation.kind === "create") {
11456
+ if (operation.kind === DISPATCH_LINK_OPERATION_KIND.CREATE) {
10810
11457
  activityIds.add(String(operation.source));
10811
11458
  activityIds.add(String(operation.target));
10812
11459
  continue;
@@ -10821,7 +11468,7 @@ function collectBatchContext(operations, adapter) {
10821
11468
  }
10822
11469
  function applyBatchOperations(operations, adapter, linkIdGen, deterministicIds) {
10823
11470
  return operations.map((operation, index) => {
10824
- const deterministicId = operation.kind === "create" ? deterministicIds?.get(index) : void 0;
11471
+ const deterministicId = operation.kind === DISPATCH_LINK_OPERATION_KIND.CREATE ? deterministicIds?.get(index) : void 0;
10825
11472
  const result = applyLinkOperation(operation, {
10826
11473
  port: adapter,
10827
11474
  newLinkId: deterministicId ? () => deterministicId : linkIdGen.next
@@ -10829,7 +11476,7 @@ function applyBatchOperations(operations, adapter, linkIdGen, deterministicIds)
10829
11476
  return {
10830
11477
  op: operation,
10831
11478
  finalLinkId: result.applied ? result.linkId : null,
10832
- rejected: result.applied ? null : result.rejected ?? "link_op_rejected"
11479
+ rejected: result.applied ? null : result.rejected ?? REJECTION_REASON.INVALID
10833
11480
  };
10834
11481
  });
10835
11482
  }
@@ -10837,25 +11484,19 @@ function stringKeyedLinkSnapshots(links) {
10837
11484
  return new Map([...links].map(([id, link]) => [String(id), link]));
10838
11485
  }
10839
11486
  async function dispatchLink(action, options, deps) {
10840
- if (action.kind === "link-create" || action.kind === "link-update") {
10841
- const type = action.type;
10842
- if (type !== void 0 && !Object.values(LINK_TYPE).some((t) => t === type)) {
10843
- return { ok: false, reason: REJECTION_REASON.INVALID_LINK_TYPE };
10844
- }
10845
- const lag = action.lag;
10846
- if (lag !== void 0 && !Number.isFinite(lag)) {
10847
- return { ok: false, reason: REJECTION_REASON.INVALID_LINK_LAG };
10848
- }
10849
- }
11487
+ const validationError = validateLinkAction(action);
11488
+ if (validationError !== null) return { ok: false, reason: validationError };
10850
11489
  return dispatchLinkBatch(
10851
11490
  [toLinkOperation(action, deps.sector.hoursPerDay)],
10852
11491
  action,
10853
11492
  options,
10854
11493
  deps,
10855
- action.kind === "link-create" && action.linkId ? /* @__PURE__ */ new Map([[0, action.linkId]]) : void 0
11494
+ action.kind === DISPATCH_ACTION_KIND.LINK_CREATE && action.linkId ? /* @__PURE__ */ new Map([[0, action.linkId]]) : void 0
10856
11495
  );
10857
11496
  }
10858
11497
  async function dispatchLinksBatch(action, options, deps) {
11498
+ const validationError = validateLinkBatch(action.operations);
11499
+ if (validationError !== null) return { ok: false, reason: validationError };
10859
11500
  const { hoursPerDay } = deps.sector;
10860
11501
  const operations = action.operations.map(
10861
11502
  (op) => batchOpToLinkOperation(op, hoursPerDay)
@@ -10866,7 +11507,9 @@ async function dispatchLinksBatch(action, options, deps) {
10866
11507
  function collectDeterministicIds(operations) {
10867
11508
  const ids = /* @__PURE__ */ new Map();
10868
11509
  operations.forEach((op, index) => {
10869
- if (op.kind === "create" && op.linkId) ids.set(index, op.linkId);
11510
+ if (op.kind === DISPATCH_LINK_OPERATION_KIND.CREATE && op.linkId) {
11511
+ ids.set(index, op.linkId);
11512
+ }
10870
11513
  });
10871
11514
  return ids.size > 0 ? ids : void 0;
10872
11515
  }
@@ -10891,24 +11534,24 @@ function resolveDeterministicIds(deterministicIds, deps) {
10891
11534
  return resolved;
10892
11535
  }
10893
11536
  function batchOpToLinkOperation(op, hoursPerDay) {
10894
- if (op.kind === "create") {
11537
+ if (op.kind === DISPATCH_LINK_OPERATION_KIND.CREATE) {
10895
11538
  return {
10896
- kind: "create",
11539
+ kind: DISPATCH_LINK_OPERATION_KIND.CREATE,
10897
11540
  source: op.source,
10898
11541
  target: op.target,
10899
11542
  type: op.type,
10900
11543
  lag: lagDaysToHours(op.lag ?? 0, hoursPerDay)
10901
11544
  };
10902
11545
  }
10903
- if (op.kind === "update") {
11546
+ if (op.kind === DISPATCH_LINK_OPERATION_KIND.UPDATE) {
10904
11547
  return {
10905
- kind: "update",
11548
+ kind: DISPATCH_LINK_OPERATION_KIND.UPDATE,
10906
11549
  linkId: op.linkId,
10907
11550
  type: op.type,
10908
11551
  lag: op.lag === void 0 ? void 0 : lagDaysToHours(op.lag, hoursPerDay)
10909
11552
  };
10910
11553
  }
10911
- return { kind: "delete", linkId: op.linkId };
11554
+ return { kind: DISPATCH_LINK_OPERATION_KIND.DELETE, linkId: op.linkId };
10912
11555
  }
10913
11556
  async function dispatchLinkBatch(operations, source, options, deps, deterministicIds) {
10914
11557
  const { adapter, scheduler, sector, linkIdGen } = deps;
@@ -10924,7 +11567,7 @@ async function dispatchLinkBatch(operations, source, options, deps, deterministi
10924
11567
  linkIdGen,
10925
11568
  resolveDeterministicIds(deterministicIds, deps)
10926
11569
  );
10927
- if (operations.length === 1 && applied[0] && applied[0].rejected !== null && source.kind !== "inline-edit") {
11570
+ if (operations.length === 1 && applied[0] && applied[0].rejected !== null && source.kind !== DISPATCH_ACTION_KIND.INLINE_EDIT) {
10928
11571
  return { ok: false, reason: applied[0].rejected };
10929
11572
  }
10930
11573
  const triggerId = pickAutoscheduleTrigger(applied, beforeLinks, adapter);
@@ -10980,31 +11623,36 @@ function pickAutoscheduleTrigger(applied, beforeLinks, adapter) {
10980
11623
  return null;
10981
11624
  }
10982
11625
  function autoscheduleTarget(operation, beforeLinks, adapter) {
10983
- if (operation.kind === "create") return operation.target;
10984
- if (operation.kind === "delete") {
11626
+ if (operation.kind === DISPATCH_LINK_OPERATION_KIND.CREATE) {
11627
+ return operation.target;
11628
+ }
11629
+ if (operation.kind === DISPATCH_LINK_OPERATION_KIND.DELETE) {
10985
11630
  return beforeLinks.get(operation.linkId)?.target ?? null;
10986
11631
  }
10987
11632
  return adapter.getLink(operation.linkId)?.target ?? null;
10988
11633
  }
10989
11634
  function toLinkOperation(action, hoursPerDay) {
10990
- if (action.kind === "link-create") {
11635
+ if (action.kind === DISPATCH_ACTION_KIND.LINK_CREATE) {
10991
11636
  return {
10992
- kind: "create",
11637
+ kind: DISPATCH_LINK_OPERATION_KIND.CREATE,
10993
11638
  source: action.source,
10994
11639
  target: action.target,
10995
11640
  type: action.type,
10996
- lag: lagDaysToHours(action.lag, hoursPerDay)
11641
+ lag: lagDaysToHours(action.lag ?? 0, hoursPerDay)
10997
11642
  };
10998
11643
  }
10999
- if (action.kind === "link-update") {
11644
+ if (action.kind === DISPATCH_ACTION_KIND.LINK_UPDATE) {
11000
11645
  return {
11001
- kind: "update",
11646
+ kind: DISPATCH_LINK_OPERATION_KIND.UPDATE,
11002
11647
  linkId: action.linkId,
11003
11648
  type: action.type,
11004
11649
  lag: action.lag === void 0 ? void 0 : lagDaysToHours(action.lag, hoursPerDay)
11005
11650
  };
11006
11651
  }
11007
- return { kind: "delete", linkId: action.linkId };
11652
+ return {
11653
+ kind: DISPATCH_LINK_OPERATION_KIND.DELETE,
11654
+ linkId: action.linkId
11655
+ };
11008
11656
  }
11009
11657
  async function dispatchInlineEditLinks(action, options, deps) {
11010
11658
  const { adapter, sector } = deps;
@@ -12130,16 +12778,16 @@ async function dispatchActivityBatch(action, options, deps) {
12130
12778
  if (validationError) return { ok: false, reason: validationError };
12131
12779
  const plan = buildBatchPlan(action, deps);
12132
12780
  if (!plan.ok) return plan;
12133
- const existingActivityIds = action.mode === "replace" ? new Set(deps.adapter.getAllIds().map((id) => String(id))) : /* @__PURE__ */ new Set();
12134
- const beforeSnap = action.mode === "replace" ? await snapshotActivities(deps.adapter, existingActivityIds) : /* @__PURE__ */ new Map();
12135
- const beforeLinks = action.mode === "replace" ? snapshotAllLinks(deps) : /* @__PURE__ */ new Map();
12136
- const viewState = action.mode === "replace" ? captureDeletedViewState(deps.adapter, existingActivityIds) : [];
12781
+ const existingActivityIds = action.mode === ACTIVITY_BATCH_MODE.REPLACE ? new Set(deps.adapter.getAllIds().map((id) => String(id))) : /* @__PURE__ */ new Set();
12782
+ const beforeSnap = action.mode === ACTIVITY_BATCH_MODE.REPLACE ? await snapshotActivities(deps.adapter, existingActivityIds) : /* @__PURE__ */ new Map();
12783
+ const beforeLinks = action.mode === ACTIVITY_BATCH_MODE.REPLACE ? snapshotAllLinks(deps) : /* @__PURE__ */ new Map();
12784
+ const viewState = action.mode === ACTIVITY_BATCH_MODE.REPLACE ? captureDeletedViewState(deps.adapter, existingActivityIds) : [];
12137
12785
  deps.scheduler.invalidateAllCaches();
12138
12786
  const appliedLinks = [];
12139
- if (action.mode === "replace") {
12787
+ if (action.mode === ACTIVITY_BATCH_MODE.REPLACE) {
12140
12788
  for (const linkId of beforeLinks.keys()) {
12141
12789
  const deleted = applyLinkOperation(
12142
- { kind: "delete", linkId },
12790
+ { kind: DISPATCH_LINK_OPERATION_KIND.DELETE, linkId },
12143
12791
  { port: deps.adapter }
12144
12792
  );
12145
12793
  if (!deleted.applied) {
@@ -12149,7 +12797,7 @@ async function dispatchActivityBatch(action, options, deps) {
12149
12797
  };
12150
12798
  }
12151
12799
  appliedLinks.push({
12152
- op: { kind: "delete", linkId },
12800
+ op: { kind: DISPATCH_LINK_OPERATION_KIND.DELETE, linkId },
12153
12801
  finalLinkId: linkId,
12154
12802
  rejected: null
12155
12803
  });
@@ -12171,7 +12819,7 @@ async function dispatchActivityBatch(action, options, deps) {
12171
12819
  const existingCorrelativeShifts = correlativeShifts.filter(
12172
12820
  (shift) => !createdIdSet.has(shift.activityId)
12173
12821
  );
12174
- const touchedIds = action.mode === "replace" ? new Set(existingActivityIds) : /* @__PURE__ */ new Set();
12822
+ const touchedIds = action.mode === ACTIVITY_BATCH_MODE.REPLACE ? new Set(existingActivityIds) : /* @__PURE__ */ new Set();
12175
12823
  foldCorrelativeShifts(
12176
12824
  deps.adapter,
12177
12825
  correlativeShifts,
@@ -12184,11 +12832,11 @@ async function dispatchActivityBatch(action, options, deps) {
12184
12832
  }
12185
12833
  const linkCreates = plan.plan.links.map((link) => ({
12186
12834
  operation: {
12187
- kind: "create",
12835
+ kind: DISPATCH_LINK_OPERATION_KIND.CREATE,
12188
12836
  source: link.source,
12189
12837
  target: link.target,
12190
12838
  type: link.type,
12191
- lag: lagDaysToHours(link.lag, deps.sector.hoursPerDay)
12839
+ lag: lagDaysToHours(link.lag ?? 0, deps.sector.hoursPerDay)
12192
12840
  },
12193
12841
  linkId: link.linkId
12194
12842
  }));
@@ -12233,19 +12881,19 @@ async function dispatchActivityBatch(action, options, deps) {
12233
12881
  links: buildLinkChangesForBatch(appliedLinks, beforeLinks, deps.adapter),
12234
12882
  hoursPerDay: deps.sector.hoursPerDay,
12235
12883
  correlativeShifts: existingCorrelativeShifts,
12236
- ...action.mode === "replace" ? { sirDetection: "after-diff" } : {}
12884
+ ...action.mode === ACTIVITY_BATCH_MODE.REPLACE ? { sirDetection: "after-diff" } : {}
12237
12885
  });
12238
12886
  return {
12239
12887
  ok: true,
12240
12888
  changes: viewState.length > 0 ? { ...changes, viewState } : changes,
12241
- ...action.mode === "replace" ? {
12889
+ ...action.mode === ACTIVITY_BATCH_MODE.REPLACE ? {
12242
12890
  __beforeSnap: beforeSnap,
12243
12891
  __beforeLinks: stringKeyedLinks(beforeLinks)
12244
12892
  } : {}
12245
12893
  };
12246
12894
  }
12247
12895
  function validateBatch(action, deps) {
12248
- if (action.mode !== "append" && action.mode !== "replace") {
12896
+ if (action.mode !== ACTIVITY_BATCH_MODE.APPEND && action.mode !== ACTIVITY_BATCH_MODE.REPLACE) {
12249
12897
  return REJECTION_REASON.INVALID;
12250
12898
  }
12251
12899
  const batchIds = /* @__PURE__ */ new Set();
@@ -12260,7 +12908,7 @@ function validateBatch(action, deps) {
12260
12908
  }
12261
12909
  if (item.activityId !== void 0) {
12262
12910
  const activityId = String(item.activityId);
12263
- if (activityId.length === 0 || activityId === "0" || explicitActivityIds.has(activityId)) {
12911
+ if (activityId.length === 0 || activityId === ROOT_PARENT_ID || explicitActivityIds.has(activityId)) {
12264
12912
  return REJECTION_REASON.INVALID;
12265
12913
  }
12266
12914
  explicitActivityIds.add(activityId);
@@ -12274,8 +12922,11 @@ function validateBatch(action, deps) {
12274
12922
  if (hasParentCycle(action.items)) return REJECTION_REASON.INVALID;
12275
12923
  const explicitLinkIds = /* @__PURE__ */ new Set();
12276
12924
  for (const link of action.links) {
12277
- if (!Object.values(LINK_TYPE).includes(link.type) || !Number.isFinite(link.lag)) {
12278
- return !Number.isFinite(link.lag) ? REJECTION_REASON.INVALID_LINK_LAG : REJECTION_REASON.INVALID_LINK_TYPE;
12925
+ if (!Object.values(LINK_TYPE).includes(link.type)) {
12926
+ return REJECTION_REASON.INVALID_LINK_TYPE;
12927
+ }
12928
+ if (link.lag !== void 0 && !Number.isFinite(link.lag)) {
12929
+ return REJECTION_REASON.INVALID_LINK_LAG;
12279
12930
  }
12280
12931
  if (!validReference(link.source, false, action.mode, batchIds, deps) || !validReference(link.target, false, action.mode, batchIds, deps)) {
12281
12932
  return REJECTION_REASON.ACTIVITY_NOT_FOUND;
@@ -12292,8 +12943,8 @@ function validateBatch(action, deps) {
12292
12943
  }
12293
12944
  function validReference(reference, allowRoot, mode, batchIds, deps) {
12294
12945
  if (typeof reference === "string") {
12295
- if (reference === "0") return allowRoot;
12296
- return mode === "append" && deps.adapter.getActivity(String(reference)) !== null;
12946
+ if (reference === ROOT_PARENT_ID) return allowRoot;
12947
+ return mode === ACTIVITY_BATCH_MODE.APPEND && deps.adapter.getActivity(String(reference)) !== null;
12297
12948
  }
12298
12949
  return reference !== null && reference.batchId.length > 0 && batchIds.has(reference.batchId);
12299
12950
  }
@@ -12388,32 +13039,32 @@ function buildBatchPlan(action, deps) {
12388
13039
  source,
12389
13040
  target,
12390
13041
  type: link.type,
12391
- lag: link.lag,
13042
+ lag: link.lag ?? 0,
12392
13043
  linkId
12393
13044
  });
12394
13045
  }
12395
13046
  return { ok: true, plan: { items, links } };
12396
13047
  }
12397
13048
  function resolvePlannedActivityId(explicitId, mode, plannedIds, deps) {
12398
- const explicitIsAvailable = explicitId !== void 0 && (mode === "replace" || deps.adapter.getActivity(explicitId) === null && !deps.isActivityIdReserved(String(explicitId))) && !plannedIds.has(String(explicitId));
13049
+ const explicitIsAvailable = explicitId !== void 0 && (mode === ACTIVITY_BATCH_MODE.REPLACE || deps.adapter.getActivity(explicitId) === null && !deps.isActivityIdReserved(String(explicitId))) && !plannedIds.has(String(explicitId));
12399
13050
  if (explicitIsAvailable) {
12400
13051
  deps.activityIdGen.bump(explicitId);
12401
13052
  return explicitId;
12402
13053
  }
12403
13054
  let candidate = deps.activityIdGen.next();
12404
- while (plannedIds.has(String(candidate)) || mode === "append" && (deps.adapter.getActivity(candidate) !== null || deps.isActivityIdReserved(String(candidate)))) {
13055
+ while (plannedIds.has(String(candidate)) || mode === ACTIVITY_BATCH_MODE.APPEND && (deps.adapter.getActivity(candidate) !== null || deps.isActivityIdReserved(String(candidate)))) {
12405
13056
  candidate = deps.activityIdGen.next();
12406
13057
  }
12407
13058
  return candidate;
12408
13059
  }
12409
13060
  function resolvePlannedLinkId(explicitId, mode, plannedIds, deps) {
12410
- const explicitIsAvailable = explicitId !== void 0 && (mode === "replace" || deps.adapter.getLink(explicitId) === null && !deps.isLinkIdReserved(String(explicitId))) && !plannedIds.has(String(explicitId));
13061
+ const explicitIsAvailable = explicitId !== void 0 && (mode === ACTIVITY_BATCH_MODE.REPLACE || deps.adapter.getLink(explicitId) === null && !deps.isLinkIdReserved(String(explicitId))) && !plannedIds.has(String(explicitId));
12411
13062
  if (explicitIsAvailable) {
12412
13063
  deps.linkIdGen.bump(explicitId);
12413
13064
  return explicitId;
12414
13065
  }
12415
13066
  let candidate = deps.linkIdGen.next();
12416
- while (plannedIds.has(String(candidate)) || mode === "append" && (deps.adapter.getLink(candidate) !== null || deps.isLinkIdReserved(String(candidate)))) {
13067
+ while (plannedIds.has(String(candidate)) || mode === ACTIVITY_BATCH_MODE.APPEND && (deps.adapter.getLink(candidate) !== null || deps.isLinkIdReserved(String(candidate)))) {
12417
13068
  candidate = deps.linkIdGen.next();
12418
13069
  }
12419
13070
  return candidate;
@@ -12440,7 +13091,7 @@ function planInsertionCorrelatives(action, activityIdsByBatchId, deps) {
12440
13091
  const parentKey = String(parentId);
12441
13092
  let plan = plansByParent.get(parentKey);
12442
13093
  if (!plan) {
12443
- const existing = action.mode === "replace" || typeof item.parent !== "string" && activityIdsByBatchId.has(item.parent.batchId) ? [] : collectSiblings(deps.adapter, parentKey).sort((left, right) => {
13094
+ const existing = action.mode === ACTIVITY_BATCH_MODE.REPLACE || typeof item.parent !== "string" && activityIdsByBatchId.has(item.parent.batchId) ? [] : collectSiblings(deps.adapter, parentKey).sort((left, right) => {
12444
13095
  const diff = readCorrelativeId(left) - readCorrelativeId(right);
12445
13096
  return diff || String(left.id).localeCompare(String(right.id));
12446
13097
  }).map((activity) => String(activity.id));
@@ -12493,8 +13144,8 @@ function planInsertionCorrelatives(action, activityIdsByBatchId, deps) {
12493
13144
  return result;
12494
13145
  }
12495
13146
  function isSimpleRootAppend(action) {
12496
- return action.mode === "append" && action.items.every(
12497
- (item) => item.parent === "0" && item.index === void 0
13147
+ return action.mode === ACTIVITY_BATCH_MODE.APPEND && action.items.every(
13148
+ (item) => item.parent === ROOT_PARENT_ID && item.index === void 0
12498
13149
  );
12499
13150
  }
12500
13151
  function activityCorrelative(activityId, deps) {
@@ -12525,6 +13176,7 @@ async function createPlannedActivities(action, plannedItems, deps) {
12525
13176
  const item = ready[index];
12526
13177
  const core = await createActivityCore(
12527
13178
  {
13179
+ kind: DISPATCH_ACTION_KIND.ACTIVITY_CREATE,
12528
13180
  parentId: item.parentId,
12529
13181
  activityId: item.activityId,
12530
13182
  overrides: item.overrides,
@@ -12550,7 +13202,9 @@ async function createPlannedActivities(action, plannedItems, deps) {
12550
13202
  const recomputedParents = /* @__PURE__ */ new Set();
12551
13203
  for (let index = ready.length - 1; index >= 0; index -= 1) {
12552
13204
  const parentId = ready[index].parentId;
12553
- if (parentId === "0" || recomputedParents.has(String(parentId))) continue;
13205
+ if (parentId === ROOT_PARENT_ID || recomputedParents.has(String(parentId))) {
13206
+ continue;
13207
+ }
12554
13208
  recomputedParents.add(String(parentId));
12555
13209
  recomputeRollupCascadesForParent(parentId, deps.adapter);
12556
13210
  }
@@ -13702,7 +14356,13 @@ async function dispatchActivitySetProgress(action, options, deps) {
13702
14356
  }
13703
14357
 
13704
14358
  // src/dispatch/handlers/dates-batch.ts
14359
+ function isDateColumn(column) {
14360
+ return column === COLUMN.START_DATE || column === COLUMN.END_DATE;
14361
+ }
13705
14362
  async function dispatchDatesBatch(action, options, deps) {
14363
+ if (action.edits.some((edit) => !isDateColumn(edit.column))) {
14364
+ return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
14365
+ }
13706
14366
  const { adapter, scheduler, sector } = deps;
13707
14367
  const verdicts = [];
13708
14368
  const beforeSnap = /* @__PURE__ */ new Map();
@@ -14219,7 +14879,7 @@ function applyBaselineOverlay(state, points, now, reporter, defaultBaseCalendarI
14219
14879
 
14220
14880
  // src/propagations/downward/recompute-ponderator-for-parent.ts
14221
14881
  function recomputePonderatorsForParent(parentId, criterion, adapter) {
14222
- if (!parentId || parentId === "0") return;
14882
+ if (!parentId || parentId === ROOT_PARENT_ID) return;
14223
14883
  const childIds = adapter.getChildren(parentId);
14224
14884
  if (childIds.length === 0) return;
14225
14885
  const pesoById = /* @__PURE__ */ new Map();
@@ -14252,12 +14912,16 @@ function criterionValue(childId, criterion, adapter) {
14252
14912
  if (!child) return 0;
14253
14913
  const active = getActiveBaseline(child);
14254
14914
  if (!active) return 0;
14255
- if (criterion === "COST") return toNumber(active.cost);
14256
- if (criterion === "HH") return toNumber(active.workHours);
14257
- const type = child.type;
14258
- if (type === "project")
14915
+ if (criterion === ACTIVITY_PONDERATOR_CRITERION.COST) {
14916
+ return toNumber(active.cost);
14917
+ }
14918
+ if (criterion === ACTIVITY_PONDERATOR_CRITERION.WORK_HOURS) {
14919
+ return toNumber(active.workHours);
14920
+ }
14921
+ const { type } = child;
14922
+ if (type === ACTIVITY_TYPE.PROJECT)
14259
14923
  return sumRecursiveBaselineDurationDays(childId, adapter);
14260
- if (type === "milestone") return 0;
14924
+ if (type === ACTIVITY_TYPE.MILESTONE) return 0;
14261
14925
  return toNumber(active.durationDays);
14262
14926
  }
14263
14927
  function sumRecursiveBaselineDurationDays(activityId, adapter) {
@@ -14267,10 +14931,10 @@ function sumRecursiveBaselineDurationDays(activityId, adapter) {
14267
14931
  if (!child) continue;
14268
14932
  const active = getActiveBaseline(child);
14269
14933
  if (!active) continue;
14270
- const type = child.type;
14271
- if (type === "project") {
14934
+ const { type } = child;
14935
+ if (type === ACTIVITY_TYPE.PROJECT) {
14272
14936
  sum += sumRecursiveBaselineDurationDays(String(childId), adapter);
14273
- } else if (type !== "milestone") {
14937
+ } else if (type !== ACTIVITY_TYPE.MILESTONE) {
14274
14938
  sum += toNumber(active.durationDays);
14275
14939
  }
14276
14940
  }
@@ -14345,7 +15009,7 @@ async function dispatchBaselineApply(action, deps) {
14345
15009
  if (activeBaselineSignature(deps) !== activeBaselineBefore) {
14346
15010
  recomputeBaselineWeightedFields(
14347
15011
  deps,
14348
- deps.sector.activityCreter ?? "DURATION"
15012
+ deps.sector.activityCreter ?? ACTIVITY_PONDERATOR_CRITERION.DURATION
14349
15013
  );
14350
15014
  }
14351
15015
  return {
@@ -14361,14 +15025,15 @@ async function dispatchBaselineApply(action, deps) {
14361
15025
  }
14362
15026
 
14363
15027
  // src/dispatch/handlers/ponderator-criterion-set.ts
14364
- function assertValidCriterion(value) {
14365
- if (value === "DURATION" || value === "COST" || value === "HH") return;
14366
- throw new Error(
14367
- `ponderator-criterion-set: invalid criterion "${String(value)}"`
15028
+ function isValidCriterion(value) {
15029
+ return Object.values(ACTIVITY_PONDERATOR_CRITERION).includes(
15030
+ value
14368
15031
  );
14369
15032
  }
14370
15033
  async function dispatchPonderatorCriterionSet(action, deps) {
14371
- assertValidCriterion(action.criterion);
15034
+ if (!isValidCriterion(action.criterion)) {
15035
+ return { ok: false, reason: REJECTION_REASON.INVALID_VALUE };
15036
+ }
14372
15037
  const allIds = new Set(deps.adapter.getAllIds());
14373
15038
  const beforeSnap = await snapshotActivities(deps.adapter, allIds);
14374
15039
  recomputeBaselineWeightedFields(deps, action.criterion);
@@ -14404,6 +15069,64 @@ async function dispatchStatusCriteriaSet(action, deps) {
14404
15069
  };
14405
15070
  }
14406
15071
 
15072
+ // src/dispatch/handlers/calendar-reconcile.ts
15073
+ async function dispatchCalendarReconcile(action, options, deps) {
15074
+ const beforeSnap = /* @__PURE__ */ new Map();
15075
+ const touchedIds = /* @__PURE__ */ new Set();
15076
+ for (const activity of deps.adapter.getAllActivities()) {
15077
+ if (!shouldReconcile(activity, deps)) continue;
15078
+ const calendar = deps.ctx.calendars.getCalendar(activity.calendarId);
15079
+ if (!calendar) continue;
15080
+ const startDate = calendar.getClosestWorkTime({
15081
+ date: activity.startDate,
15082
+ direction: WORK_TIME_DIRECTION.FUTURE,
15083
+ unit: CALENDAR_UNIT.HOUR
15084
+ });
15085
+ const endDate = calendar.calculateEndDate(
15086
+ startDate,
15087
+ activity.durationHours
15088
+ );
15089
+ if (sameInstant(startDate, activity.startDate) && sameInstant(endDate, activity.endDate)) {
15090
+ continue;
15091
+ }
15092
+ const activityId = String(activity.id);
15093
+ beforeSnap.set(activityId, structuredCloneActivity(activity));
15094
+ touchedIds.add(activityId);
15095
+ deps.adapter.setActivityFields(activityId, { startDate, endDate });
15096
+ }
15097
+ const { scheduledIds } = await runPostMutation(
15098
+ {
15099
+ adapter: deps.adapter,
15100
+ scheduler: deps.scheduler,
15101
+ sector: deps.sector,
15102
+ defaultBaseCalendarId: deps.defaultBaseCalendarId
15103
+ },
15104
+ {
15105
+ action,
15106
+ autoscheduleFrom: "roots",
15107
+ recomputeParentsFrom: touchedIds,
15108
+ now: deps.now,
15109
+ options
15110
+ }
15111
+ );
15112
+ return {
15113
+ ok: true,
15114
+ changes: await assembleChangeSet(deps.adapter, {
15115
+ source: action,
15116
+ beforeSnap,
15117
+ touchedIds,
15118
+ scheduledIds,
15119
+ hoursPerDay: deps.sector.hoursPerDay
15120
+ })
15121
+ };
15122
+ }
15123
+ function shouldReconcile(activity, deps) {
15124
+ return activity.progress === 0 && !isSummary(activity.type, deps.adapter.hasChildren(activity.id));
15125
+ }
15126
+ function sameInstant(first, second) {
15127
+ return first.getTime() === second.getTime();
15128
+ }
15129
+
14407
15130
  // src/activity-copy-paste/policy.ts
14408
15131
  var ACTIVITY_COPY_FIELDS = [
14409
15132
  "name",
@@ -14613,6 +15336,9 @@ async function performDispatch(action, options, deps) {
14613
15336
  clipboard: deps.activityClipboard
14614
15337
  });
14615
15338
  }
15339
+ if (action.kind === "calendar-reconcile") {
15340
+ return dispatchCalendarReconcile(action, options, deps);
15341
+ }
14616
15342
  if (action.kind === "activity-clipboard-clear") {
14617
15343
  return dispatchActivityClipboardClear(action, deps.activityClipboard);
14618
15344
  }
@@ -18533,7 +19259,7 @@ function captureCreatedSnapshots(state, changeSet) {
18533
19259
  return { afterSnap, afterLinks };
18534
19260
  }
18535
19261
  function computeCoalesceKey(action) {
18536
- if (action.kind !== "inline-edit") return null;
19262
+ if (action.kind !== DISPATCH_ACTION_KIND.INLINE_EDIT) return null;
18537
19263
  if (!NON_SCHEDULING_INLINE_COLUMNS.has(action.column)) return null;
18538
19264
  return `inline-edit:${String(action.activityId)}:${action.column}`;
18539
19265
  }
@@ -18568,10 +19294,10 @@ function mergeCoalesced(top, next) {
18568
19294
  return buildUndoEntry(changeSet);
18569
19295
  }
18570
19296
  function getDispatchHistoryPolicy(action) {
18571
- if (action.kind === "persistence-acknowledge") {
19297
+ if (action.kind === DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE) {
18572
19298
  return "checkpoint-on-success";
18573
19299
  }
18574
- if (action.kind === "sir-sync" || action.kind === "activity-lookahead-sync" || action.kind === "baseline-apply" || action.kind === "ponderator-criterion-set" || action.kind === "status-criteria-set" || action.kind === "activity-clipboard-clear" || action.kind === "activity-copy" || action.kind === "selection-toggle" || action.kind === "selection-replace" || action.kind === "visibility-set" || action.kind === "filter-set" || action.kind === "sort-set") {
19300
+ if (action.kind === DISPATCH_ACTION_KIND.SIR_SYNC || action.kind === DISPATCH_ACTION_KIND.CALENDAR_RECONCILE || action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC || action.kind === DISPATCH_ACTION_KIND.BASELINE_APPLY || action.kind === DISPATCH_ACTION_KIND.PONDERATOR_CRITERION_SET || action.kind === DISPATCH_ACTION_KIND.STATUS_CRITERIA_SET || action.kind === DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR || action.kind === DISPATCH_ACTION_KIND.ACTIVITY_COPY || action.kind === DISPATCH_ACTION_KIND.SELECTION_TOGGLE || action.kind === DISPATCH_ACTION_KIND.SELECTION_REPLACE || action.kind === DISPATCH_ACTION_KIND.VISIBILITY_SET || action.kind === DISPATCH_ACTION_KIND.FILTER_SET || action.kind === DISPATCH_ACTION_KIND.SORT_SET) {
18575
19301
  return "skip";
18576
19302
  }
18577
19303
  return "record";
@@ -18659,7 +19385,9 @@ function buildInverseChangeSet(state, entry, side) {
18659
19385
  (change) => side === "before" ? invertViewStateChange(change) : change
18660
19386
  );
18661
19387
  return {
18662
- source: { kind: side === "before" ? "undo" : "redo" },
19388
+ source: {
19389
+ kind: side === "before" ? CHANGE_SET_SOURCE_KIND.UNDO : CHANGE_SET_SOURCE_KIND.REDO
19390
+ },
18663
19391
  activities,
18664
19392
  links,
18665
19393
  calendars: [],
@@ -19494,7 +20222,7 @@ var WORKING_DAY_TRUE_VALUES = /* @__PURE__ */ new Set([
19494
20222
  "1",
19495
20223
  "true"
19496
20224
  ]);
19497
- var DEFAULT_ACTIVITY_CRETER = "DURATION";
20225
+ var DEFAULT_ACTIVITY_CRETER = ACTIVITY_PONDERATOR_CRITERION.DURATION;
19498
20226
  var DEFAULT_CONSTRAINT_TYPE = "asap";
19499
20227
  var CONSTRAINT_LABEL_MAP = {
19500
20228
  ASAP: "asap",
@@ -20001,12 +20729,12 @@ function linkIdAsNumber(link) {
20001
20729
  function parseActivityCreter(raw) {
20002
20730
  if (typeof raw !== "string") return DEFAULT_ACTIVITY_CRETER;
20003
20731
  switch (raw.toUpperCase()) {
20004
- case "DURATION":
20005
- return "DURATION";
20006
- case "COST":
20007
- return "COST";
20008
- case "HH":
20009
- return "HH";
20732
+ case ACTIVITY_PONDERATOR_CRITERION.DURATION:
20733
+ return ACTIVITY_PONDERATOR_CRITERION.DURATION;
20734
+ case ACTIVITY_PONDERATOR_CRITERION.COST:
20735
+ return ACTIVITY_PONDERATOR_CRITERION.COST;
20736
+ case ACTIVITY_PONDERATOR_CRITERION.WORK_HOURS:
20737
+ return ACTIVITY_PONDERATOR_CRITERION.WORK_HOURS;
20010
20738
  default:
20011
20739
  return DEFAULT_ACTIVITY_CRETER;
20012
20740
  }
@@ -20733,8 +21461,8 @@ function compareByRule(rule, context) {
20733
21461
  const valueB = descriptor.extract(b, context);
20734
21462
  const missing = compareMissing(isMissing(valueA), isMissing(valueB));
20735
21463
  if (missing !== null) return missing;
20736
- const result = descriptor.valueKind === "enum" ? enumRank(valueA, descriptor.order) - enumRank(valueB, descriptor.order) : compareValues(valueA, valueB, context.locale);
20737
- return rule.direction === "desc" ? -result : result;
21464
+ const result = descriptor.valueKind === FILTER_VALUE_KIND.ENUM ? enumRank(valueA, descriptor.order) - enumRank(valueB, descriptor.order) : compareValues(valueA, valueB, context.locale);
21465
+ return rule.direction === ORDER_DIRECTION.DESCENDING ? -result : result;
20738
21466
  };
20739
21467
  }
20740
21468
  function buildComparator(order, context) {
@@ -21105,7 +21833,7 @@ function viewStateChanges(target, source) {
21105
21833
  function createProjectionChangeSet(target, source) {
21106
21834
  const orderChanged = serializeCanonicalSchedule(target.order) !== serializeCanonicalSchedule(source.order);
21107
21835
  return {
21108
- source: { kind: "init" },
21836
+ source: { kind: CHANGE_SET_SOURCE_KIND.INIT },
21109
21837
  activities: entityChanges(target.activities, source.activities),
21110
21838
  links: entityChanges(target.links, source.links),
21111
21839
  calendars: entityChanges(target.calendars, source.calendars),
@@ -21117,6 +21845,11 @@ function createProjectionChangeSet(target, source) {
21117
21845
  }
21118
21846
 
21119
21847
  // src/propagations/upward/date-gesture-preview.ts
21848
+ var DATE_GESTURE_KIND = {
21849
+ MOVE: "move",
21850
+ RESIZE_START: "resize-start",
21851
+ RESIZE_END: "resize-end"
21852
+ };
21120
21853
  var emptyFormula = () => ({
21121
21854
  constantStart: null,
21122
21855
  variableStartOffset: null,
@@ -21128,7 +21861,7 @@ var max = (left, right) => left === null ? right : Math.max(left, right);
21128
21861
  function createDateGesturePreview(adapter, gesture, assertCurrent) {
21129
21862
  const participantIds = [
21130
21863
  ...new Set(
21131
- gesture.kind === "move" ? gesture.activityIds.map(String) : [String(gesture.activityId)]
21864
+ gesture.kind === DATE_GESTURE_KIND.MOVE ? gesture.activityIds.map(String) : [String(gesture.activityId)]
21132
21865
  )
21133
21866
  ];
21134
21867
  if (participantIds.length === 0) {
@@ -21157,14 +21890,14 @@ function createDateGesturePreview(adapter, gesture, assertCurrent) {
21157
21890
  }
21158
21891
  function buildParticipantFormulas(adapter, gesture, participantIds) {
21159
21892
  const formulas = /* @__PURE__ */ new Map();
21160
- const anchorId = gesture.kind === "move" ? String(gesture.anchorActivityId) : null;
21893
+ const anchorId = gesture.kind === DATE_GESTURE_KIND.MOVE ? String(gesture.anchorActivityId) : null;
21161
21894
  const anchor = anchorId === null ? null : requireLeafActivity(adapter, anchorId);
21162
21895
  if (anchorId !== null && !participantIds.includes(anchorId)) {
21163
21896
  throw new Error("[ScheduleCore] move anchor is not a participant");
21164
21897
  }
21165
21898
  for (const activityId of participantIds) {
21166
21899
  const activity = requireLeafActivity(adapter, activityId);
21167
- if (gesture.kind === "move") {
21900
+ if (gesture.kind === DATE_GESTURE_KIND.MOVE) {
21168
21901
  const anchorStart = anchor.startDate.getTime();
21169
21902
  formulas.set(activityId, {
21170
21903
  constantStart: null,
@@ -21172,7 +21905,7 @@ function buildParticipantFormulas(adapter, gesture, participantIds) {
21172
21905
  constantEnd: null,
21173
21906
  variableEndOffset: activity.endDate.getTime() - anchorStart
21174
21907
  });
21175
- } else if (gesture.kind === "resize-start") {
21908
+ } else if (gesture.kind === DATE_GESTURE_KIND.RESIZE_START) {
21176
21909
  formulas.set(activityId, {
21177
21910
  constantStart: null,
21178
21911
  variableStartOffset: 0,
@@ -21263,7 +21996,7 @@ function evaluateEnd(formula, proposedEdgeTimeMs) {
21263
21996
  // src/init/schedule-core.ts
21264
21997
  var FORK_SOURCE = /* @__PURE__ */ Symbol("ScheduleCore.fork.source");
21265
21998
  function acknowledgesPersistence(action) {
21266
- return action.kind === "persistence-acknowledge" || action.kind === "activity-lookahead-sync" && action.acknowledgePersistedLookahead === true;
21999
+ return action.kind === DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE || action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC && action.acknowledgePersistedLookahead === true;
21267
22000
  }
21268
22001
  function changesRequireFilterProjectionRebuild(changes) {
21269
22002
  for (const change of changes.activities) {
@@ -21289,6 +22022,30 @@ function isCurrentFilterProjection(projection, filter, context) {
21289
22022
  return hasCurrentHours && hasCurrentLocale;
21290
22023
  }
21291
22024
  var ScheduleCore = class _ScheduleCore {
22025
+ /** Activity reads and mutations. */
22026
+ activities;
22027
+ /** Dependency-link reads and mutations. */
22028
+ links;
22029
+ /** Calendar reads and reconciliation. */
22030
+ calendars;
22031
+ /** Core-owned activity selection. */
22032
+ selection;
22033
+ /** Visibility, filtering, and order projection. */
22034
+ view;
22035
+ /** Baseline overlays and selection. */
22036
+ baselines;
22037
+ /** Pending impact-request synchronization. */
22038
+ impactRequests;
22039
+ /** External persistence tracking; no storage I/O is performed. */
22040
+ persistence;
22041
+ /** Undo and redo history. */
22042
+ history;
22043
+ /** Cross-instance projection change sets. */
22044
+ projection;
22045
+ /** Critical-path job lifecycle. */
22046
+ criticalPath;
22047
+ /** Effective-graph, revision, and digest diagnostics. */
22048
+ diagnostics;
21292
22049
  _activityClipboard = { value: null };
21293
22050
  _status = SCHEDULE_CORE_STATUS.READY;
21294
22051
  coreRuntime;
@@ -21300,6 +22057,7 @@ var ScheduleCore = class _ScheduleCore {
21300
22057
  _criticalPathRevision = -1;
21301
22058
  _activeCriticalPath = null;
21302
22059
  constructor(input) {
22060
+ Object.assign(this, createScheduleNamespaces(this));
21303
22061
  if (FORK_SOURCE in input) {
21304
22062
  this._isFork = true;
21305
22063
  const source = input[FORK_SOURCE];
@@ -21365,9 +22123,21 @@ var ScheduleCore = class _ScheduleCore {
21365
22123
  const waitForCriticalPathOnLoad = input.criticalPathOnLoad === true;
21366
22124
  this._ready = waitForCriticalPathOnLoad ? this._criticalPathReady.then(() => void 0) : this._initPromise;
21367
22125
  }
22126
+ /**
22127
+ * Resolves after initialization, and after initial critical path when
22128
+ * `criticalPathOnLoad` is enabled.
22129
+ */
21368
22130
  get ready() {
21369
22131
  return this._ready;
21370
22132
  }
22133
+ /**
22134
+ * Creates an isolated schedule with copied state, history, and generators.
22135
+ *
22136
+ * The fork runs the same mutation logic but disables dirty tracking:
22137
+ * `persistence.hasChanges()` stays false and all dirty collections stay
22138
+ * empty. It cannot acknowledge persistence and is never merged automatically.
22139
+ * @returns A ready isolated schedule.
22140
+ */
21371
22141
  fork() {
21372
22142
  return this._enqueue(async () => {
21373
22143
  await this._ready;
@@ -21377,19 +22147,48 @@ var ScheduleCore = class _ScheduleCore {
21377
22147
  });
21378
22148
  });
21379
22149
  }
22150
+ /**
22151
+ * Tracks the critical-path job current when this property is read.
22152
+ *
22153
+ * Later automatic work, including undo or redo recomputation, can replace
22154
+ * the promise returned by subsequent reads. Use `whenSettled()` to wait for
22155
+ * the current schedule revision.
22156
+ * Apply a non-null `changes` value to the consumer-owned projection.
22157
+ */
21380
22158
  get criticalPathReady() {
21381
22159
  return this._criticalPathReady;
21382
22160
  }
22161
+ /**
22162
+ * Current lifecycle health; `ready` can be observed before initialization
22163
+ * finishes, so await {@link ScheduleCore.ready} before normal use.
22164
+ */
21383
22165
  get status() {
21384
22166
  return this._status;
21385
22167
  }
22168
+ /**
22169
+ * Reads a defensive sector metadata snapshot without a readiness guard.
22170
+ *
22171
+ * @returns Cloned metadata, including values available after destruction.
22172
+ */
21386
22173
  getSector() {
21387
22174
  return cloneDomainValue(this.coreRuntime.sector);
21388
22175
  }
22176
+ /**
22177
+ * Reads a defensive activity snapshot from a ready schedule.
22178
+ *
22179
+ * @param id - Canonical activity ID.
22180
+ * @returns The activity, or `null` when absent.
22181
+ */
21389
22182
  getActivityView(id) {
21390
22183
  this.assertReady();
21391
22184
  return readActivity(this.coreRuntime.state, id);
21392
22185
  }
22186
+ /**
22187
+ * Creates a read-only date prediction bound to the current revision.
22188
+ *
22189
+ * @param gesture - Move or resize gesture to preview.
22190
+ * @returns A preview that throws after schedule state changes.
22191
+ */
21393
22192
  createDateGesturePreview(gesture) {
21394
22193
  this.assertReady();
21395
22194
  const revision = this._scheduleRevision;
@@ -21400,10 +22199,16 @@ var ScheduleCore = class _ScheduleCore {
21400
22199
  }
21401
22200
  });
21402
22201
  }
22202
+ /** @returns Defensive snapshots of every activity in the ready schedule. */
21403
22203
  getAllActivitiesView() {
21404
22204
  this.assertReady();
21405
22205
  return readAllActivities(this.coreRuntime.state);
21406
22206
  }
22207
+ /**
22208
+ * Computes the unique parent IDs allowed by the current indent plan.
22209
+ *
22210
+ * @param activityIds - Activities considered for indentation.
22211
+ */
21407
22212
  getIndentTargetParentIds(activityIds) {
21408
22213
  this.assertReady();
21409
22214
  const plan = planIndentMoves(
@@ -21414,14 +22219,30 @@ var ScheduleCore = class _ScheduleCore {
21414
22219
  ...new Set(plan.allowedMoves.map((move) => String(move.newParentId)))
21415
22220
  ];
21416
22221
  }
22222
+ /**
22223
+ * Reads defensive direct-child snapshots in correlative order.
22224
+ *
22225
+ * @param parentId - Parent activity ID, or the root ID.
22226
+ */
21417
22227
  getChildrenView(parentId) {
21418
22228
  this.assertReady();
21419
22229
  return readChildren(this.coreRuntime.state, parentId);
21420
22230
  }
22231
+ /**
22232
+ * Reads a defensive link snapshot.
22233
+ *
22234
+ * @param id - Canonical link ID.
22235
+ * @returns The link, or `null` when absent. Stored lag is in working hours.
22236
+ */
21421
22237
  getLinkView(id) {
21422
22238
  this.assertReady();
21423
22239
  return readLink(this.coreRuntime.state, id);
21424
22240
  }
22241
+ /**
22242
+ * Reads unique incoming and outgoing link snapshots for an activity.
22243
+ *
22244
+ * @param activityId - Activity whose links should be read.
22245
+ */
21425
22246
  getLinksForActivityView(activityId) {
21426
22247
  this.assertReady();
21427
22248
  const state = this.coreRuntime.state;
@@ -21437,10 +22258,12 @@ var ScheduleCore = class _ScheduleCore {
21437
22258
  for (const linkId of state.getIncomingLinkIds(activityId)) append(linkId);
21438
22259
  return links;
21439
22260
  }
22261
+ /** @returns Defensive snapshots of every link; stored lag is in working hours. */
21440
22262
  getAllLinksView() {
21441
22263
  this.assertReady();
21442
22264
  return readAllLinks(this.coreRuntime.state);
21443
22265
  }
22266
+ /** @returns Counts and circular components from the effective dependency graph. */
21444
22267
  auditEffectiveGraph() {
21445
22268
  this.assertReady();
21446
22269
  const state = this.coreRuntime.state;
@@ -21461,58 +22284,90 @@ var ScheduleCore = class _ScheduleCore {
21461
22284
  largestComponentSize
21462
22285
  };
21463
22286
  }
22287
+ /**
22288
+ * Reads and clones one activity property.
22289
+ *
22290
+ * @param activityId - Canonical activity ID.
22291
+ * @param property - Property to read.
22292
+ * @returns The cloned value, or `null` when the activity is absent.
22293
+ */
21464
22294
  getProperty(activityId, property) {
21465
22295
  this.assertReady();
21466
22296
  const snapshot = this.coreRuntime.state.getActivity(activityId);
21467
22297
  if (!snapshot) return null;
21468
22298
  return cloneDomainValue(snapshot[property]);
21469
22299
  }
22300
+ /** @returns A read-only snapshot of all current activity IDs. */
21470
22301
  getAllIds() {
21471
22302
  this.assertReady();
21472
22303
  return readAllIds(this.coreRuntime.state);
21473
22304
  }
22305
+ /**
22306
+ * Visits each current activity ID without exposing mutable state.
22307
+ *
22308
+ * @param visit - Callback invoked once per current ID.
22309
+ */
21474
22310
  forEachActivityId(visit) {
21475
22311
  this.assertReady();
21476
22312
  forEachActivityId(this.coreRuntime.state, visit);
21477
22313
  }
22314
+ /**
22315
+ * Reads direct child IDs in visual order.
22316
+ *
22317
+ * @param parentId - Parent activity ID, or the root ID.
22318
+ */
21478
22319
  getChildrenIds(parentId) {
21479
22320
  this.assertReady();
21480
22321
  return readChildrenIds(this.coreRuntime.state, parentId);
21481
22322
  }
22323
+ /** @returns A defensive snapshot of selected activity IDs. */
21482
22324
  getSelectedActivityIds() {
21483
22325
  this.assertReady();
21484
22326
  return readSelectedActivityIds(this.coreRuntime.state);
21485
22327
  }
22328
+ /** @returns A defensive snapshot of explicitly hidden activity IDs. */
21486
22329
  getHiddenActivityIds() {
21487
22330
  this.assertReady();
21488
22331
  return this.coreRuntime.state.hiddenIds().map(String);
21489
22332
  }
22333
+ /** @returns A defensive snapshot of activity IDs not currently hidden. */
21490
22334
  getVisibleActivityIds() {
21491
22335
  this.assertReady();
21492
22336
  const hiddenIds = new Set(this.coreRuntime.state.hiddenIds().map(String));
21493
22337
  return this.coreRuntime.state.getAllIds().map(String).filter((activityId) => !hiddenIds.has(activityId));
21494
22338
  }
22339
+ /** @returns A defensive active-filter snapshot, or `null`. */
21495
22340
  getActiveFilter() {
21496
22341
  this.assertReady();
21497
22342
  return cloneDomainValue(this.coreRuntime.state.getActiveFilter());
21498
22343
  }
22344
+ /** @returns A defensive active-order snapshot, or `null`. */
21499
22345
  getActiveOrder() {
21500
22346
  this.assertReady();
21501
22347
  return cloneDomainValue(this.coreRuntime.state.getActiveOrder());
21502
22348
  }
22349
+ /** @returns Activity IDs in the current projected traversal order. */
21503
22350
  getVisualOrderIds() {
21504
22351
  this.assertReady();
21505
22352
  return [...this.coreRuntime.state.getVisualOrderIds()];
21506
22353
  }
22354
+ /** @returns Whether the parent currently has a direct child. */
21507
22355
  hasChild(parentId) {
21508
22356
  this.assertReady();
21509
22357
  return readHasChild(this.coreRuntime.state, parentId);
21510
22358
  }
22359
+ /**
22360
+ * Reads a defensive schedule-calendar snapshot.
22361
+ *
22362
+ * @param id - Canonical calendar ID.
22363
+ * @returns The calendar, or `null` when absent.
22364
+ */
21511
22365
  getCalendar(id) {
21512
22366
  this.assertReady();
21513
22367
  const calendar = this.coreRuntime.calendars.get(id);
21514
22368
  return calendar ? cloneDomainValue(calendar) : null;
21515
22369
  }
22370
+ /** @returns Defensive snapshots of every schedule calendar. */
21516
22371
  getAllCalendars() {
21517
22372
  this.assertReady();
21518
22373
  return Array.from(
@@ -21520,12 +22375,19 @@ var ScheduleCore = class _ScheduleCore {
21520
22375
  (calendar) => cloneDomainValue(calendar)
21521
22376
  );
21522
22377
  }
22378
+ /** @returns Defensive snapshots of every base calendar. */
21523
22379
  getBaseCalendars() {
21524
22380
  this.assertReady();
21525
22381
  return this.coreRuntime.baseCalendars.map(
21526
22382
  (calendar) => cloneDomainValue(calendar)
21527
22383
  );
21528
22384
  }
22385
+ /**
22386
+ * Checks custom-ID uniqueness while optionally excluding the current value.
22387
+ *
22388
+ * @param customId - Candidate custom ID.
22389
+ * @param currentCustomId - Existing value to ignore, or `null`.
22390
+ */
21529
22391
  isCustomIdInUse(customId, currentCustomId = null) {
21530
22392
  this.assertReady();
21531
22393
  return this.coreRuntime.customIdTracker.isCustomIdInUse(
@@ -21533,24 +22395,29 @@ var ScheduleCore = class _ScheduleCore {
21533
22395
  currentCustomId
21534
22396
  );
21535
22397
  }
22398
+ /** @returns The default calendar's earliest start/latest end, or `null`. */
21536
22399
  getProjectWorkHours() {
21537
22400
  this.assertReady();
21538
22401
  return computeProjectWorkHours(this.coreRuntime.calendars.values());
21539
22402
  }
22403
+ /** @returns Defensive snapshots of modified persisted links; no I/O occurs. */
21540
22404
  getModifiedLinks() {
21541
22405
  this.assertReady();
21542
22406
  return this._saveTracker.modifiedLinks((linkId) => this.coreRuntime.state.getLink(linkId)).map(cloneDomainValue);
21543
22407
  }
22408
+ /** @returns Defensive snapshots of not-yet-persisted links; no I/O occurs. */
21544
22409
  getNewLinks() {
21545
22410
  this.assertReady();
21546
22411
  return this._saveTracker.newLinks((linkId) => this.coreRuntime.state.getLink(linkId)).map(cloneDomainValue);
21547
22412
  }
22413
+ /** @returns Defensive snapshots of modified persisted activities; no I/O occurs. */
21548
22414
  getModifiedActivities() {
21549
22415
  this.assertReady();
21550
22416
  return this._saveTracker.modifiedActivities(
21551
22417
  (activityId) => this.coreRuntime.state.getActivity(activityId)
21552
22418
  ).map(cloneDomainValue);
21553
22419
  }
22420
+ /** @returns Modified persisted fields grouped by activity ID; no I/O occurs. */
21554
22421
  getModifiedActivityFields() {
21555
22422
  this.assertReady();
21556
22423
  return cloneDomainValue(
@@ -21559,23 +22426,28 @@ var ScheduleCore = class _ScheduleCore {
21559
22426
  )
21560
22427
  );
21561
22428
  }
22429
+ /** @returns Defensive snapshots of not-yet-persisted activities; no I/O occurs. */
21562
22430
  getNewActivities() {
21563
22431
  this.assertReady();
21564
22432
  return this._saveTracker.newActivities(
21565
22433
  (activityId) => this.coreRuntime.state.getActivity(activityId)
21566
22434
  ).map(cloneDomainValue);
21567
22435
  }
22436
+ /** @returns Whether tracked state differs from the acknowledged save baseline. */
21568
22437
  hasUnsavedChanges() {
21569
22438
  this.assertReady();
21570
22439
  return this._saveTracker.hasUnsavedChanges();
21571
22440
  }
22441
+ /** @returns The monotonic scheduling revision without a readiness guard. */
21572
22442
  getScheduleRevision() {
21573
22443
  return this._scheduleRevision;
21574
22444
  }
22445
+ /** @returns The undo-history boundary for an external save checkpoint. */
21575
22446
  capturePersistenceHistoryBoundary() {
21576
22447
  this.assertReady();
21577
22448
  return this._undo.capturePersistenceBoundary();
21578
22449
  }
22450
+ /** @returns A deterministic serialization digest of canonical schedule state. */
21579
22451
  getCanonicalDigest() {
21580
22452
  this.assertReady();
21581
22453
  const byId = (left, right) => String(left.id).localeCompare(String(right.id));
@@ -21587,6 +22459,13 @@ var ScheduleCore = class _ScheduleCore {
21587
22459
  baseCalendars: [...this.getBaseCalendars()].sort(byId)
21588
22460
  });
21589
22461
  }
22462
+ /**
22463
+ * Produces changes that transform a projection of `source` into this schedule.
22464
+ *
22465
+ * Both schedules must be ready. Neither instance is mutated or merged.
22466
+ * @param source - Schedule currently represented by the consumer projection.
22467
+ * @returns A complete consumer projection change set.
22468
+ */
21590
22469
  createProjectionChangeSetFrom(source) {
21591
22470
  this.assertReady();
21592
22471
  source.assertReady();
@@ -21600,12 +22479,14 @@ var ScheduleCore = class _ScheduleCore {
21600
22479
  });
21601
22480
  return createProjectionChangeSet(projectionOf(this), projectionOf(source));
21602
22481
  }
22482
+ /** @returns Deleted persisted activity identities since the last save. */
21603
22483
  getDeletedActivitiesSinceLastSave() {
21604
22484
  this.assertReady();
21605
22485
  return this._saveTracker.deletedActivities(
21606
22486
  (activityId) => this.coreRuntime.state.getActivity(activityId)
21607
22487
  ).map(cloneDomainValue);
21608
22488
  }
22489
+ /** @returns Deleted persisted link identities since the last save. */
21609
22490
  getDeletedLinksSinceLastSave() {
21610
22491
  this.assertReady();
21611
22492
  return this._saveTracker.deletedLinks((linkId) => this.coreRuntime.state.getLink(linkId)).map(cloneDomainValue);
@@ -21645,10 +22526,27 @@ var ScheduleCore = class _ScheduleCore {
21645
22526
  );
21646
22527
  });
21647
22528
  }
22529
+ /**
22530
+ * Serializes and applies one public command to core-owned state.
22531
+ *
22532
+ * @param action - Public command. Activity-batch commands use
22533
+ * {@link ScheduleCore.applyActivityBatch} instead.
22534
+ * @param options - Per-operation autoschedule and critical-path controls.
22535
+ * @returns The complete dispatch result unchanged, including change sets,
22536
+ * verdicts, effects, tracking events, and warnings when present.
22537
+ */
21648
22538
  async dispatch(action, options = {}) {
21649
22539
  const admitted = this._beginScheduleMutation(action);
21650
22540
  return this._enqueue(() => this._dispatchInner(action, options, admitted));
21651
22541
  }
22542
+ /**
22543
+ * Serializes and applies an activity creation batch.
22544
+ *
22545
+ * @param action - Append/replace batch using working-day link lags and
22546
+ * activity-creation overrides. Dispatch converts lags to stored hours.
22547
+ * @param options - Per-operation autoschedule and critical-path controls.
22548
+ * @returns The complete dispatch result unchanged.
22549
+ */
21652
22550
  async applyActivityBatch(action, options = {}) {
21653
22551
  const admitted = this._beginScheduleMutation(action);
21654
22552
  return this._enqueue(() => this._dispatchInner(action, options, admitted));
@@ -21747,7 +22645,7 @@ var ScheduleCore = class _ScheduleCore {
21747
22645
  }
21748
22646
  if (result.ok) {
21749
22647
  if (historyPolicy === "checkpoint-on-success") {
21750
- if (action.kind !== "persistence-acknowledge") {
22648
+ if (action.kind !== DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE) {
21751
22649
  throw new Error(
21752
22650
  "checkpoint-on-success requires persistence acknowledge"
21753
22651
  );
@@ -21769,7 +22667,7 @@ var ScheduleCore = class _ScheduleCore {
21769
22667
  action.activities ?? [],
21770
22668
  action.links ?? []
21771
22669
  );
21772
- } else if (action.kind === "activity-lookahead-sync" && action.acknowledgePersistedLookahead === true) {
22670
+ } else if (action.kind === DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC && action.acknowledgePersistedLookahead === true) {
21773
22671
  this._saveTracker.acknowledgePersistedLookahead(
21774
22672
  result.changes.activities,
21775
22673
  (activityId) => this.coreRuntime.state.getActivity(activityId)
@@ -21796,6 +22694,12 @@ var ScheduleCore = class _ScheduleCore {
21796
22694
  }
21797
22695
  return { result: toPublicDispatchResult(result), changedState: false };
21798
22696
  }
22697
+ /**
22698
+ * Queues critical-path calculation for the current revision.
22699
+ *
22700
+ * @returns A complete projection update, or `null` when already current,
22701
+ * destroyed, or superseded.
22702
+ */
21799
22703
  recomputeCriticalPath() {
21800
22704
  const operation = this._enqueue(async () => ({
21801
22705
  job: this._startCriticalPathForCurrentRevision()
@@ -21803,9 +22707,11 @@ var ScheduleCore = class _ScheduleCore {
21803
22707
  this._criticalPathReady = operation;
21804
22708
  return operation;
21805
22709
  }
22710
+ /** @returns Whether no mutation or calculation remains for the current revision. */
21806
22711
  isCriticalPathSettled() {
21807
22712
  return this._criticalPathRevision === this._scheduleRevision && this._pendingScheduleRevision === this._scheduleRevision && this._activeCriticalPath === null;
21808
22713
  }
22714
+ /** Resolves after repeatedly recomputing until the current revision is settled. */
21809
22715
  async whenCriticalPathSettled() {
21810
22716
  while (!this.isCriticalPathSettled()) {
21811
22717
  await this.recomputeCriticalPath();
@@ -21813,7 +22719,7 @@ var ScheduleCore = class _ScheduleCore {
21813
22719
  }
21814
22720
  _withReappliedViewState(action, result) {
21815
22721
  if (!result.ok) return result;
21816
- if (action.kind === "visibility-set") {
22722
+ if (action.kind === DISPATCH_ACTION_KIND.VISIBILITY_SET) {
21817
22723
  this.coreRuntime.state.setFilterProjection(null);
21818
22724
  }
21819
22725
  if (!reappliesViewState(action)) return result;
@@ -21972,7 +22878,7 @@ var ScheduleCore = class _ScheduleCore {
21972
22878
  );
21973
22879
  }
21974
22880
  changes = await assembleChangeSet(this.coreRuntime.state, {
21975
- source: { kind: "init" },
22881
+ source: { kind: CHANGE_SET_SOURCE_KIND.INIT },
21976
22882
  beforeSnap: /* @__PURE__ */ new Map(),
21977
22883
  touchedIds: [],
21978
22884
  scheduledIds: [],
@@ -21998,6 +22904,13 @@ var ScheduleCore = class _ScheduleCore {
21998
22904
  void promise.then(clearIfActive, clearIfActive);
21999
22905
  return promise;
22000
22906
  }
22907
+ /**
22908
+ * Applies the latest inverse operation through the serialized queue.
22909
+ *
22910
+ * @param options - Optional depth guard and critical-path suppression.
22911
+ * @returns The complete projection change set, or `null` when unavailable or
22912
+ * when the expected depth does not match.
22913
+ */
22001
22914
  undo(options = {}) {
22002
22915
  const admitted = this._admitScheduleMutation();
22003
22916
  let changedState = false;
@@ -22053,6 +22966,12 @@ var ScheduleCore = class _ScheduleCore {
22053
22966
  return this._reapplyViewState(changes) ?? changes;
22054
22967
  }
22055
22968
  }
22969
+ /**
22970
+ * Reapplies the latest undone operation through the serialized queue.
22971
+ *
22972
+ * @param options - Optional critical-path suppression.
22973
+ * @returns The complete projection change set, or `null` when unavailable.
22974
+ */
22056
22975
  redo(options = {}) {
22057
22976
  const admitted = this._admitScheduleMutation();
22058
22977
  let changedState = false;
@@ -22103,15 +23022,19 @@ var ScheduleCore = class _ScheduleCore {
22103
23022
  );
22104
23023
  return this._reapplyViewState(changes) ?? changes;
22105
23024
  }
23025
+ /** @returns Whether an undo entry is available; readiness is not required. */
22106
23026
  canUndo() {
22107
23027
  return this._undo.canUndo();
22108
23028
  }
23029
+ /** @returns Whether a redo entry is available; readiness is not required. */
22109
23030
  canRedo() {
22110
23031
  return this._undo.canRedo();
22111
23032
  }
23033
+ /** Clears undo and redo history without changing schedule state. */
22112
23034
  clearHistory() {
22113
23035
  this._undo.clear();
22114
23036
  }
23037
+ /** @returns Current undo depth; readiness is not required. */
22115
23038
  undoDepth() {
22116
23039
  return this._undo.undoDepth();
22117
23040
  }
@@ -22121,6 +23044,10 @@ var ScheduleCore = class _ScheduleCore {
22121
23044
  this.coreRuntime.state.getAllActivities()
22122
23045
  );
22123
23046
  }
23047
+ /**
23048
+ * Cancels active critical-path work, clears caches, and permanently destroys
23049
+ * this instance. Guarded reads and operations throw afterward.
23050
+ */
22124
23051
  destroy() {
22125
23052
  if (this._activeCriticalPath) {
22126
23053
  this._activeCriticalPath.cancellation.cancelled = true;
@@ -22173,6 +23100,13 @@ function toPublicDispatchResult(result) {
22173
23100
  return publicResult;
22174
23101
  }
22175
23102
 
23103
+ // src/api/create-schedule.ts
23104
+ async function createSchedule(input) {
23105
+ const schedule = new ScheduleCore(input);
23106
+ await schedule.ready;
23107
+ return schedule;
23108
+ }
23109
+
22176
23110
  // src/boundary/save/unsaved.ts
22177
23111
  var getUnsavedActivities = (activities = []) => (activities ?? []).filter((activity) => !activity.proplannerId);
22178
23112
 
@@ -22191,67 +23125,6 @@ var CONSTRAINT_TYPE_TO_LABEL = {
22191
23125
  // src/constants/workday.ts
22192
23126
  var DEFAULT_HOURS_PER_DAY = 8;
22193
23127
 
22194
- // src/dispatch/action-kinds.ts
22195
- var DISPATCH_ACTION_KIND = {
22196
- ACTIVITY_CLIPBOARD_CLEAR: "activity-clipboard-clear",
22197
- ACTIVITY_COPY: "activity-copy",
22198
- ACTIVITY_PASTE_COPIED: "activity-paste-copied",
22199
- PERSISTENCE_ACKNOWLEDGE: "persistence-acknowledge",
22200
- BASELINE_APPLY: "baseline-apply",
22201
- PONDERATOR_CRITERION_SET: "ponderator-criterion-set",
22202
- STATUS_CRITERIA_SET: "status-criteria-set",
22203
- INLINE_EDIT: "inline-edit",
22204
- DATES_BATCH: "dates-batch",
22205
- BULK_EDIT: "bulk-edit",
22206
- LINK_CREATE: "link-create",
22207
- LINK_UPDATE: "link-update",
22208
- LINK_DELETE: "link-delete",
22209
- LINKS_BATCH: "links-batch",
22210
- ACTIVITY_CREATE: "activity-create",
22211
- ACTIVITY_DELETE: "activity-delete",
22212
- ACTIVITY_MOVE: "activity-move",
22213
- ACTIVITY_INDENT: "activity-indent",
22214
- ACTIVITY_OUTDENT: "activity-outdent",
22215
- ACTIVITY_SET_PROGRESS: "activity-set-progress",
22216
- SELECTION_TOGGLE: "selection-toggle",
22217
- SELECTION_REPLACE: "selection-replace",
22218
- VISIBILITY_SET: "visibility-set",
22219
- FILTER_SET: "filter-set",
22220
- SORT_SET: "sort-set",
22221
- SIR_SYNC: "sir-sync",
22222
- ACTIVITY_LOOKAHEAD_SYNC: "activity-lookahead-sync"
22223
- };
22224
- var KIND_CATALOG_COVERS_UNION = {
22225
- [DISPATCH_ACTION_KIND.ACTIVITY_CLIPBOARD_CLEAR]: true,
22226
- [DISPATCH_ACTION_KIND.ACTIVITY_COPY]: true,
22227
- [DISPATCH_ACTION_KIND.ACTIVITY_PASTE_COPIED]: true,
22228
- [DISPATCH_ACTION_KIND.PERSISTENCE_ACKNOWLEDGE]: true,
22229
- [DISPATCH_ACTION_KIND.BASELINE_APPLY]: true,
22230
- [DISPATCH_ACTION_KIND.PONDERATOR_CRITERION_SET]: true,
22231
- [DISPATCH_ACTION_KIND.STATUS_CRITERIA_SET]: true,
22232
- [DISPATCH_ACTION_KIND.INLINE_EDIT]: true,
22233
- [DISPATCH_ACTION_KIND.DATES_BATCH]: true,
22234
- [DISPATCH_ACTION_KIND.BULK_EDIT]: true,
22235
- [DISPATCH_ACTION_KIND.LINK_CREATE]: true,
22236
- [DISPATCH_ACTION_KIND.LINK_UPDATE]: true,
22237
- [DISPATCH_ACTION_KIND.LINK_DELETE]: true,
22238
- [DISPATCH_ACTION_KIND.LINKS_BATCH]: true,
22239
- [DISPATCH_ACTION_KIND.ACTIVITY_CREATE]: true,
22240
- [DISPATCH_ACTION_KIND.ACTIVITY_DELETE]: true,
22241
- [DISPATCH_ACTION_KIND.ACTIVITY_MOVE]: true,
22242
- [DISPATCH_ACTION_KIND.ACTIVITY_INDENT]: true,
22243
- [DISPATCH_ACTION_KIND.ACTIVITY_OUTDENT]: true,
22244
- [DISPATCH_ACTION_KIND.ACTIVITY_SET_PROGRESS]: true,
22245
- [DISPATCH_ACTION_KIND.SELECTION_TOGGLE]: true,
22246
- [DISPATCH_ACTION_KIND.SELECTION_REPLACE]: true,
22247
- [DISPATCH_ACTION_KIND.VISIBILITY_SET]: true,
22248
- [DISPATCH_ACTION_KIND.FILTER_SET]: true,
22249
- [DISPATCH_ACTION_KIND.SORT_SET]: true,
22250
- [DISPATCH_ACTION_KIND.SIR_SYNC]: true,
22251
- [DISPATCH_ACTION_KIND.ACTIVITY_LOOKAHEAD_SYNC]: true
22252
- };
22253
- var DISPATCH_ACTION_KINDS = Object.keys(KIND_CATALOG_COVERS_UNION);
22254
-
22255
23128
  // src/creation/creation-kinds.ts
22256
23129
  var CREATION_KIND = {
22257
23130
  CHILD: "child",
@@ -22260,6 +23133,6 @@ var CREATION_KIND = {
22260
23133
  ROOT: "root"
22261
23134
  };
22262
23135
 
22263
- export { ACTIVITY_TYPE, CALENDAR_UNIT, COLUMN, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CREATION_KIND, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_TRACK_EVENT, LINK_CODE_TO_TYPE, LINK_TYPE, LINK_TYPE_CODE, NEW_ACTIVITY_DEFAULTS, REJECTION_REASON, ROOT_PARENT_ID, SCHEDULE_CORE_STATUS, STATUS, ScheduleCore, WORK_TIME_DIRECTION, checkNoUpdatedLinks, computeExpectedProgress, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
23136
+ export { ACTIVITY_BATCH_ACTION_KIND, ACTIVITY_BATCH_MODE, ACTIVITY_DATE_EDGE, ACTIVITY_FIELD, ACTIVITY_PONDERATOR_CRITERION, ACTIVITY_TYPE, CALENDAR_UNIT, CHANGE_SET_SOURCE_KIND, COLUMN, COMPLETED_PROGRESS, CONSTRAINT_TYPE, CONSTRAINT_TYPE_TO_LABEL, CONSTRAINT_WARNING_KIND, CREATION_KIND, DATE_GESTURE_KIND, DEFAULT_HOURS_PER_DAY, DISPATCH_ACTION_KIND, DISPATCH_ACTION_KINDS, DISPATCH_LINK_OPERATION_KIND, DISPATCH_TRACK_EVENT, FILTER_FIELD, FILTER_LOGIC, FILTER_OPERATOR, FILTER_REJECTION_REASON, FILTER_VALUE_KIND, LINK_BATCH_OPERATION_KIND, LINK_CODE_TO_TYPE, LINK_REJECTION_REASON, LINK_RELATIONSHIP, LINK_TYPE, LINK_TYPE_CODE, NEW_ACTIVITY_DEFAULTS, NOT_STARTED_PROGRESS, ORDER_DIRECTION, REJECTION_REASON, ROOT_PARENT_ID, SCHEDULE_CORE_STATUS, SCHEDULE_EFFECT_KIND, SIR_AUTO_REJECT_REASON, STATUS, STATUS_CRITERIA, ScheduleCore, WORK_TIME_DIRECTION, checkNoUpdatedLinks, computeExpectedProgress, createSchedule, expectedProgressFromBaseline, getActiveBaseline, getUnsavedActivities, isRootParent, normalizeParentKey, parseFromBackend, willRunCriticalPath, yieldToBrowser };
22264
23137
  //# sourceMappingURL=index.js.map
22265
23138
  //# sourceMappingURL=index.js.map