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