dabke 0.81.1 → 0.83.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +45 -27
  3. package/dist/client.d.ts +20 -2
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +4 -1
  6. package/dist/client.js.map +1 -1
  7. package/dist/client.types.d.ts +9 -0
  8. package/dist/client.types.d.ts.map +1 -1
  9. package/dist/client.types.js +1 -0
  10. package/dist/client.types.js.map +1 -1
  11. package/dist/cpsat/model-builder.d.ts +9 -0
  12. package/dist/cpsat/model-builder.d.ts.map +1 -1
  13. package/dist/cpsat/model-builder.js +36 -34
  14. package/dist/cpsat/model-builder.js.map +1 -1
  15. package/dist/cpsat/response.d.ts +13 -1
  16. package/dist/cpsat/response.d.ts.map +1 -1
  17. package/dist/cpsat/response.js +4 -0
  18. package/dist/cpsat/response.js.map +1 -1
  19. package/dist/cpsat/rules/cost-utils.d.ts +11 -0
  20. package/dist/cpsat/rules/cost-utils.d.ts.map +1 -0
  21. package/dist/cpsat/rules/cost-utils.js +24 -0
  22. package/dist/cpsat/rules/cost-utils.js.map +1 -0
  23. package/dist/cpsat/rules/day-cost-multiplier.d.ts.map +1 -1
  24. package/dist/cpsat/rules/day-cost-multiplier.js +3 -14
  25. package/dist/cpsat/rules/day-cost-multiplier.js.map +1 -1
  26. package/dist/cpsat/rules/day-cost-surcharge.d.ts.map +1 -1
  27. package/dist/cpsat/rules/day-cost-surcharge.js +3 -7
  28. package/dist/cpsat/rules/day-cost-surcharge.js.map +1 -1
  29. package/dist/cpsat/rules/index.d.ts +3 -0
  30. package/dist/cpsat/rules/index.d.ts.map +1 -1
  31. package/dist/cpsat/rules/index.js +3 -0
  32. package/dist/cpsat/rules/index.js.map +1 -1
  33. package/dist/cpsat/rules/max-consecutive-days.d.ts.map +1 -1
  34. package/dist/cpsat/rules/max-consecutive-days.js +16 -2
  35. package/dist/cpsat/rules/max-consecutive-days.js.map +1 -1
  36. package/dist/cpsat/rules/max-days-week.d.ts +44 -0
  37. package/dist/cpsat/rules/max-days-week.d.ts.map +1 -0
  38. package/dist/cpsat/rules/max-days-week.js +95 -0
  39. package/dist/cpsat/rules/max-days-week.js.map +1 -0
  40. package/dist/cpsat/rules/max-hours-day.d.ts.map +1 -1
  41. package/dist/cpsat/rules/max-hours-day.js +15 -2
  42. package/dist/cpsat/rules/max-hours-day.js.map +1 -1
  43. package/dist/cpsat/rules/max-hours-week.d.ts.map +1 -1
  44. package/dist/cpsat/rules/max-hours-week.js +16 -2
  45. package/dist/cpsat/rules/max-hours-week.js.map +1 -1
  46. package/dist/cpsat/rules/max-shifts-day.d.ts.map +1 -1
  47. package/dist/cpsat/rules/max-shifts-day.js +15 -2
  48. package/dist/cpsat/rules/max-shifts-day.js.map +1 -1
  49. package/dist/cpsat/rules/min-consecutive-days.d.ts.map +1 -1
  50. package/dist/cpsat/rules/min-consecutive-days.js +15 -2
  51. package/dist/cpsat/rules/min-consecutive-days.js.map +1 -1
  52. package/dist/cpsat/rules/min-days-week.d.ts +34 -0
  53. package/dist/cpsat/rules/min-days-week.d.ts.map +1 -0
  54. package/dist/cpsat/rules/min-days-week.js +84 -0
  55. package/dist/cpsat/rules/min-days-week.js.map +1 -0
  56. package/dist/cpsat/rules/min-hours-day.d.ts.map +1 -1
  57. package/dist/cpsat/rules/min-hours-day.js +15 -2
  58. package/dist/cpsat/rules/min-hours-day.js.map +1 -1
  59. package/dist/cpsat/rules/min-hours-week.d.ts.map +1 -1
  60. package/dist/cpsat/rules/min-hours-week.js +16 -2
  61. package/dist/cpsat/rules/min-hours-week.js.map +1 -1
  62. package/dist/cpsat/rules/min-rest-between-shifts.d.ts.map +1 -1
  63. package/dist/cpsat/rules/min-rest-between-shifts.js +72 -2
  64. package/dist/cpsat/rules/min-rest-between-shifts.js.map +1 -1
  65. package/dist/cpsat/rules/minimize-cost.d.ts.map +1 -1
  66. package/dist/cpsat/rules/minimize-cost.js +2 -23
  67. package/dist/cpsat/rules/minimize-cost.js.map +1 -1
  68. package/dist/cpsat/rules/must-assign.d.ts +49 -0
  69. package/dist/cpsat/rules/must-assign.d.ts.map +1 -0
  70. package/dist/cpsat/rules/must-assign.js +86 -0
  71. package/dist/cpsat/rules/must-assign.js.map +1 -0
  72. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts.map +1 -1
  73. package/dist/cpsat/rules/overtime-daily-multiplier.js +1 -12
  74. package/dist/cpsat/rules/overtime-daily-multiplier.js.map +1 -1
  75. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts.map +1 -1
  76. package/dist/cpsat/rules/overtime-daily-surcharge.js +1 -5
  77. package/dist/cpsat/rules/overtime-daily-surcharge.js.map +1 -1
  78. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts +5 -1
  79. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts.map +1 -1
  80. package/dist/cpsat/rules/overtime-tiered-multiplier.js +1 -12
  81. package/dist/cpsat/rules/overtime-tiered-multiplier.js.map +1 -1
  82. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts.map +1 -1
  83. package/dist/cpsat/rules/overtime-weekly-multiplier.js +1 -12
  84. package/dist/cpsat/rules/overtime-weekly-multiplier.js.map +1 -1
  85. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts.map +1 -1
  86. package/dist/cpsat/rules/overtime-weekly-surcharge.js +1 -5
  87. package/dist/cpsat/rules/overtime-weekly-surcharge.js.map +1 -1
  88. package/dist/cpsat/rules/registry.d.ts +28 -2
  89. package/dist/cpsat/rules/registry.d.ts.map +1 -1
  90. package/dist/cpsat/rules/registry.js +4 -1
  91. package/dist/cpsat/rules/registry.js.map +1 -1
  92. package/dist/cpsat/rules/resolver.js +2 -2
  93. package/dist/cpsat/rules/resolver.js.map +1 -1
  94. package/dist/cpsat/rules/rules.types.d.ts +3 -0
  95. package/dist/cpsat/rules/rules.types.d.ts.map +1 -1
  96. package/dist/cpsat/rules/scope.types.d.ts +18 -1
  97. package/dist/cpsat/rules/scope.types.d.ts.map +1 -1
  98. package/dist/cpsat/rules/scope.types.js +59 -16
  99. package/dist/cpsat/rules/scope.types.js.map +1 -1
  100. package/dist/cpsat/rules/time-cost-surcharge.d.ts.map +1 -1
  101. package/dist/cpsat/rules/time-cost-surcharge.js +2 -1
  102. package/dist/cpsat/rules/time-cost-surcharge.js.map +1 -1
  103. package/dist/cpsat/rules/time-off.d.ts.map +1 -1
  104. package/dist/cpsat/rules/time-off.js +6 -3
  105. package/dist/cpsat/rules/time-off.js.map +1 -1
  106. package/dist/cpsat/semantic-time.d.ts +44 -42
  107. package/dist/cpsat/semantic-time.d.ts.map +1 -1
  108. package/dist/cpsat/semantic-time.js +64 -46
  109. package/dist/cpsat/semantic-time.js.map +1 -1
  110. package/dist/cpsat/types.d.ts +37 -27
  111. package/dist/cpsat/types.d.ts.map +1 -1
  112. package/dist/cpsat/utils.d.ts.map +1 -1
  113. package/dist/cpsat/utils.js +7 -12
  114. package/dist/cpsat/utils.js.map +1 -1
  115. package/dist/cpsat/validation-reporter.d.ts +10 -7
  116. package/dist/cpsat/validation-reporter.d.ts.map +1 -1
  117. package/dist/cpsat/validation-reporter.js +44 -72
  118. package/dist/cpsat/validation-reporter.js.map +1 -1
  119. package/dist/cpsat/validation.types.d.ts +54 -44
  120. package/dist/cpsat/validation.types.d.ts.map +1 -1
  121. package/dist/cpsat/validation.types.js +15 -10
  122. package/dist/cpsat/validation.types.js.map +1 -1
  123. package/dist/datetime.utils.d.ts +3 -203
  124. package/dist/datetime.utils.d.ts.map +1 -1
  125. package/dist/datetime.utils.js +1 -288
  126. package/dist/datetime.utils.js.map +1 -1
  127. package/dist/index.d.ts +14 -83
  128. package/dist/index.d.ts.map +1 -1
  129. package/dist/index.js +11 -83
  130. package/dist/index.js.map +1 -1
  131. package/dist/schedule/cost.d.ts +204 -0
  132. package/dist/schedule/cost.d.ts.map +1 -0
  133. package/dist/schedule/cost.js +187 -0
  134. package/dist/schedule/cost.js.map +1 -0
  135. package/dist/schedule/coverage.d.ts +85 -0
  136. package/dist/schedule/coverage.d.ts.map +1 -0
  137. package/dist/schedule/coverage.js +33 -0
  138. package/dist/schedule/coverage.js.map +1 -0
  139. package/dist/schedule/definition.d.ts +227 -0
  140. package/dist/schedule/definition.d.ts.map +1 -0
  141. package/dist/schedule/definition.js +659 -0
  142. package/dist/schedule/definition.js.map +1 -0
  143. package/dist/schedule/index.d.ts +67 -0
  144. package/dist/schedule/index.d.ts.map +1 -0
  145. package/dist/schedule/index.js +69 -0
  146. package/dist/schedule/index.js.map +1 -0
  147. package/dist/schedule/rules.d.ts +353 -0
  148. package/dist/schedule/rules.d.ts.map +1 -0
  149. package/dist/schedule/rules.js +352 -0
  150. package/dist/schedule/rules.js.map +1 -0
  151. package/dist/schedule/shift-patterns.d.ts +34 -0
  152. package/dist/schedule/shift-patterns.d.ts.map +1 -0
  153. package/dist/schedule/shift-patterns.js +41 -0
  154. package/dist/schedule/shift-patterns.js.map +1 -0
  155. package/dist/schedule/time-periods.d.ts +69 -0
  156. package/dist/schedule/time-periods.d.ts.map +1 -0
  157. package/dist/schedule/time-periods.js +91 -0
  158. package/dist/schedule/time-periods.js.map +1 -0
  159. package/dist/types.d.ts +14 -78
  160. package/dist/types.d.ts.map +1 -1
  161. package/dist/types.js.map +1 -1
  162. package/package.json +4 -9
  163. package/solver/src/solver/app.py +1 -1
  164. package/solver/src/solver/solver.py +7 -4
  165. package/src/client.ts +6 -8
  166. package/src/client.types.ts +9 -0
  167. package/src/cpsat/model-builder.ts +44 -35
  168. package/src/cpsat/response.ts +13 -1
  169. package/src/cpsat/rules/cost-utils.ts +25 -0
  170. package/src/cpsat/rules/day-cost-multiplier.ts +3 -14
  171. package/src/cpsat/rules/day-cost-surcharge.ts +3 -8
  172. package/src/cpsat/rules/index.ts +3 -0
  173. package/src/cpsat/rules/max-consecutive-days.ts +17 -0
  174. package/src/cpsat/rules/max-days-week.ts +143 -0
  175. package/src/cpsat/rules/max-hours-day.ts +21 -1
  176. package/src/cpsat/rules/max-hours-week.ts +22 -1
  177. package/src/cpsat/rules/max-shifts-day.ts +21 -1
  178. package/src/cpsat/rules/min-consecutive-days.ts +16 -1
  179. package/src/cpsat/rules/min-days-week.ts +120 -0
  180. package/src/cpsat/rules/min-hours-day.ts +16 -1
  181. package/src/cpsat/rules/min-hours-week.ts +17 -1
  182. package/src/cpsat/rules/min-rest-between-shifts.ts +92 -2
  183. package/src/cpsat/rules/minimize-cost.ts +2 -29
  184. package/src/cpsat/rules/must-assign.ts +108 -0
  185. package/src/cpsat/rules/overtime-daily-multiplier.ts +1 -12
  186. package/src/cpsat/rules/overtime-daily-surcharge.ts +1 -6
  187. package/src/cpsat/rules/overtime-tiered-multiplier.ts +6 -13
  188. package/src/cpsat/rules/overtime-weekly-multiplier.ts +1 -12
  189. package/src/cpsat/rules/overtime-weekly-surcharge.ts +1 -6
  190. package/src/cpsat/rules/registry.ts +8 -2
  191. package/src/cpsat/rules/resolver.ts +2 -2
  192. package/src/cpsat/rules/rules.types.ts +3 -0
  193. package/src/cpsat/rules/scope.types.ts +73 -20
  194. package/src/cpsat/rules/time-cost-surcharge.ts +2 -1
  195. package/src/cpsat/rules/time-off.ts +6 -2
  196. package/src/cpsat/semantic-time.ts +115 -91
  197. package/src/cpsat/types.ts +37 -27
  198. package/src/cpsat/utils.ts +8 -12
  199. package/src/cpsat/validation-reporter.ts +51 -82
  200. package/src/cpsat/validation.types.ts +72 -47
  201. package/src/datetime.utils.ts +3 -334
  202. package/src/index.ts +35 -107
  203. package/src/schedule/cost.ts +242 -0
  204. package/src/schedule/coverage.ts +135 -0
  205. package/src/schedule/definition.ts +958 -0
  206. package/src/schedule/index.ts +112 -0
  207. package/src/schedule/rules.ts +529 -0
  208. package/src/schedule/shift-patterns.ts +46 -0
  209. package/src/schedule/time-periods.ts +110 -0
  210. package/src/types.ts +14 -88
  211. package/dist/errors.d.ts +0 -12
  212. package/dist/errors.d.ts.map +0 -1
  213. package/dist/errors.js +0 -17
  214. package/dist/errors.js.map +0 -1
  215. package/dist/llms.d.ts +0 -2
  216. package/dist/llms.d.ts.map +0 -1
  217. package/dist/llms.js +0 -3
  218. package/dist/llms.js.map +0 -1
  219. package/dist/schedule.d.ts +0 -724
  220. package/dist/schedule.d.ts.map +0 -1
  221. package/dist/schedule.js +0 -899
  222. package/dist/schedule.js.map +0 -1
  223. package/dist/validation.d.ts +0 -105
  224. package/dist/validation.d.ts.map +0 -1
  225. package/dist/validation.js +0 -130
  226. package/dist/validation.js.map +0 -1
  227. package/llms.txt +0 -925
  228. package/src/errors.ts +0 -17
  229. package/src/llms.ts +0 -3
  230. package/src/schedule.ts +0 -1419
  231. package/src/validation.ts +0 -188
@@ -1,48 +1,6 @@
1
- import { CalendarDate, DateTime, DateTimeRange, DayOfWeek, SchedulingPeriod } from "./types.js";
1
+ import type { DayOfWeek, SchedulingPeriod } from "./types.js";
2
2
 
3
- /**
4
- * Converts a JavaScript Date to a CalendarDate
5
- */
6
- export function dateToCalendarDate(date: Date): CalendarDate {
7
- return {
8
- year: date.getFullYear(),
9
- month: date.getMonth() + 1, // JS months are 0-indexed
10
- day: date.getDate(),
11
- };
12
- }
13
-
14
- /**
15
- * Converts a DateTime to a JavaScript Date
16
- * Internal helper function
17
- */
18
- export function dateTimeToDate(dateTime: DateTime): Date {
19
- return new Date(
20
- dateTime.year || 0,
21
- (dateTime.month || 1) - 1,
22
- dateTime.day || 1,
23
- dateTime.hours || 0,
24
- dateTime.minutes || 0,
25
- dateTime.seconds || 0,
26
- );
27
- }
28
-
29
- /**
30
- * Compares two DateTimes
31
- * Returns:
32
- * -1 if dateTime1 < dateTime2
33
- * 0 if dateTime1 = dateTime2
34
- * 1 if dateTime1 > dateTime2
35
- */
36
- export function compareDateTimes(dateTime1: DateTime, dateTime2: DateTime): number {
37
- const date1 = dateTimeToDate(dateTime1);
38
- const date2 = dateTimeToDate(dateTime2);
39
-
40
- if (date1 < date2) return -1;
41
- if (date1 > date2) return 1;
42
- return 0;
43
- }
44
-
45
- export const DAY_OF_WEEK_MAP = {
3
+ export const DAY_OF_WEEK_MAP: Record<DayOfWeek, number> = {
46
4
  sunday: 0, // JavaScript Date week starts on Sunday
47
5
  monday: 1,
48
6
  tuesday: 2,
@@ -63,15 +21,7 @@ const DAY_NAMES = [
63
21
  ] as const;
64
22
 
65
23
  /**
66
- * Helper to get the day of week name from a Date (local time)
67
- */
68
- export function toDayOfWeek(date: Date): DayOfWeek {
69
- // getDay() always returns 0-6
70
- return DAY_NAMES[date.getDay()] as DayOfWeek;
71
- }
72
-
73
- /**
74
- * Helper to get the day of week name from a Date (UTC)
24
+ * Helper to get the day of week name from a Date (UTC).
75
25
  * Use this when working with date strings like "2026-01-10" that are timezone-agnostic.
76
26
  */
77
27
  export function toDayOfWeekUTC(date: Date): DayOfWeek {
@@ -79,287 +29,6 @@ export function toDayOfWeekUTC(date: Date): DayOfWeek {
79
29
  return DAY_NAMES[date.getUTCDay()] as DayOfWeek;
80
30
  }
81
31
 
82
- /**
83
- * Formats a date as YYYY-MM-DD string
84
- */
85
- export function formatDateString(date: Date): string {
86
- const year = date.getFullYear();
87
- const month = (date.getMonth() + 1).toString().padStart(2, "0");
88
- const day = date.getDate().toString().padStart(2, "0");
89
- return `${year}-${month}-${day}`;
90
- }
91
-
92
- /**
93
- * Generates an array of day strings (YYYY-MM-DD) from a time horizon.
94
- *
95
- * @param horizon - The time horizon with start (inclusive) and end (inclusive) dates
96
- * @returns Array of day strings in YYYY-MM-DD format
97
- *
98
- * @example
99
- * ```typescript
100
- * const days = generateDays({
101
- * start: new Date('2025-01-01'),
102
- * end: new Date('2025-01-04')
103
- * });
104
- * // Returns: ["2025-01-01", "2025-01-02", "2025-01-03", "2025-01-04"]
105
- * ```
106
- */
107
- export function generateDays(horizon: { start: Date; end: Date }): string[] {
108
- const days: string[] = [];
109
- const current = new Date(horizon.start);
110
-
111
- while (current <= horizon.end) {
112
- days.push(formatDateString(current));
113
- current.setDate(current.getDate() + 1);
114
- }
115
-
116
- return days;
117
- }
118
-
119
- /**
120
- * Splits a time period into consecutive day ranges.
121
- *
122
- * Each range represents a single calendar day within the period from start to end.
123
- * This is useful for rules that need to apply constraints on a per-day basis,
124
- * such as maximum or minimum hours per day.
125
- *
126
- * @param start - The start date of the period (inclusive)
127
- * @param end - The end date of the period (exclusive)
128
- * @returns An array of [startDate, endDate] tuples, where each tuple represents
129
- * a single day. The last range's end date will be the provided end date.
130
- *
131
- * @example
132
- * ```typescript
133
- * const ranges = splitPeriodIntoDays({
134
- * start: new Date('2025-01-01'),
135
- * end: new Date('2025-01-03')
136
- * });
137
- * // Returns:
138
- * // [
139
- * // [Date('2025-01-01'), Date('2025-01-02')],
140
- * // [Date('2025-01-02'), Date('2025-01-03')]
141
- * // ]
142
- * ```
143
- */
144
- export function splitPeriodIntoDays({ start, end }: { start: Date; end: Date }): [Date, Date][] {
145
- const ranges: [Date, Date][] = [];
146
-
147
- let leftBound = new Date(start);
148
- let done = false;
149
-
150
- // Loop through each day
151
- leftBound = new Date(start);
152
- while (!done) {
153
- // Create next day date
154
- let rightBound = new Date(leftBound);
155
- rightBound.setDate(rightBound.getDate() + 1);
156
-
157
- if (rightBound >= end) {
158
- rightBound = end;
159
- done = true;
160
- }
161
-
162
- ranges.push([leftBound, rightBound]);
163
- leftBound = rightBound;
164
- }
165
- return ranges;
166
- }
167
-
168
- /**
169
- * Splits a time period into consecutive week ranges.
170
- *
171
- * Each range represents a week period starting on the specified day of the week.
172
- * This is useful for rules that need to apply constraints on a per-week basis,
173
- * such as maximum or minimum hours per week.
174
- *
175
- * The first range starts at the provided start date (not necessarily on weekStartsOn).
176
- * Subsequent ranges align to the weekStartsOn day. The last range's end date will be
177
- * the provided end date.
178
- *
179
- * @param start - The start date of the period (inclusive)
180
- * @param end - The end date of the period (exclusive)
181
- * @param weekStartsOn - The day of the week that weeks start on (e.g., "monday", "sunday")
182
- * @returns An array of [startDate, endDate] tuples, where each tuple represents
183
- * a week period aligned to the specified week start day.
184
- *
185
- * @example
186
- * ```typescript
187
- * const ranges = splitPeriodIntoWeeks({
188
- * start: new Date('2025-01-01'), // Wednesday
189
- * end: new Date('2025-01-15'),
190
- * weekStartsOn: 'monday'
191
- * });
192
- * // Returns ranges starting from Jan 1 (Wed), then aligning to Mondays:
193
- * // [
194
- * // [Date('2025-01-01 Wed'), Date('2025-01-06 Mon')],
195
- * // [Date('2025-01-06 Mon'), Date('2025-01-13 Mon')],
196
- * // [Date('2025-01-13 Mon'), Date('2025-01-15 Wed')]
197
- * // ]
198
- * ```
199
- */
200
- export function splitPeriodIntoWeeks({
201
- start,
202
- end,
203
- weekStartsOn,
204
- }: {
205
- start: Date;
206
- end: Date;
207
- weekStartsOn: DayOfWeek;
208
- }): [Date, Date][] {
209
- const DAYS_OF_WEEK: DayOfWeek[] = [
210
- "sunday",
211
- "monday",
212
- "tuesday",
213
- "wednesday",
214
- "thursday",
215
- "friday",
216
- "saturday",
217
- ];
218
-
219
- const ranges: [Date, Date][] = [];
220
-
221
- let leftBound = new Date(start);
222
- let done = false;
223
-
224
- const startDayIndex = DAYS_OF_WEEK.indexOf(weekStartsOn);
225
-
226
- // Create weekly ranges
227
- while (!done) {
228
- const dayOfWeek = leftBound.getDay(); // 0 = Sunday, 1 = Monday, etc.
229
- const daysToNextWeek = (7 - ((dayOfWeek - startDayIndex) % 7)) % 7;
230
- const daysToAdd = daysToNextWeek === 0 ? 7 : daysToNextWeek;
231
-
232
- let rightBound = new Date(leftBound);
233
- rightBound.setDate(rightBound.getDate() + daysToAdd);
234
-
235
- if (rightBound >= end) {
236
- rightBound = end;
237
- done = true;
238
- }
239
-
240
- ranges.push([leftBound, rightBound]);
241
- leftBound = rightBound;
242
- }
243
- return ranges;
244
- }
245
-
246
- /**
247
- * Checks if two DateTime ranges overlap in both date and time.
248
- * Ranges overlap if they share any moment in time.
249
- *
250
- * Two ranges overlap if: range1.start < range2.end AND range2.start < range1.end
251
- *
252
- * @param range1 First time range with start (inclusive) and end (exclusive)
253
- * @param range2 Second time range with start (inclusive) and end (exclusive)
254
- * @returns true if ranges overlap, false otherwise
255
- *
256
- * @example
257
- * ```typescript
258
- * // Same day, overlapping times (9-17 overlaps with 12-20)
259
- * dateTimeRangesOverlap(
260
- * {
261
- * start: { year: 2025, month: 6, day: 1, hours: 9, minutes: 0 },
262
- * end: { year: 2025, month: 6, day: 1, hours: 17, minutes: 0 }
263
- * },
264
- * {
265
- * start: { year: 2025, month: 6, day: 1, hours: 12, minutes: 0 },
266
- * end: { year: 2025, month: 6, day: 1, hours: 20, minutes: 0 }
267
- * }
268
- * ); // true
269
- *
270
- * // Different days - no overlap
271
- * dateTimeRangesOverlap(
272
- * {
273
- * start: { year: 2025, month: 6, day: 1, hours: 9, minutes: 0 },
274
- * end: { year: 2025, month: 6, day: 1, hours: 17, minutes: 0 }
275
- * },
276
- * {
277
- * start: { year: 2025, month: 6, day: 2, hours: 9, minutes: 0 },
278
- * end: { year: 2025, month: 6, day: 2, hours: 17, minutes: 0 }
279
- * }
280
- * ); // false
281
- *
282
- * // Works naturally with Shift objects
283
- * dateTimeRangesOverlap(
284
- * { start: shift1.startDateTime, end: shift1.endDateTime },
285
- * { start: shift2.startDateTime, end: shift2.endDateTime }
286
- * );
287
- * ```
288
- */
289
- export function dateTimeRangesOverlap(range1: DateTimeRange, range2: DateTimeRange): boolean {
290
- // Use existing compareDateTimes for temporal comparison
291
- // Ranges overlap if: start1 < end2 AND start2 < end1
292
- return (
293
- compareDateTimes(range1.start, range2.end) < 0 && compareDateTimes(range2.start, range1.end) < 0
294
- );
295
- }
296
-
297
- /**
298
- * Calculates the number of complete days between two dates
299
- * @param start The start date
300
- * @param end The end date
301
- * @returns Number of complete days from start to end (can be negative if end < start)
302
- *
303
- * @example
304
- * ```typescript
305
- * daysBetween(new Date('2025-01-01'), new Date('2025-01-05')); // 4
306
- * ```
307
- */
308
- export function daysBetween(start: Date, end: Date): number {
309
- const ms = end.getTime() - start.getTime();
310
- return Math.floor(ms / (1000 * 60 * 60 * 24));
311
- }
312
-
313
- /**
314
- * Adds a number of minutes to a base date and returns a DateTime.
315
- * Treats the base date as a reference point (typically midnight of horizon start),
316
- * and the minutes parameter as absolute minutes from that point.
317
- *
318
- * @param baseDate The starting date (used as reference point)
319
- * @param minutes Absolute minutes from the base date
320
- * @returns DateTime representing the result
321
- *
322
- * @example
323
- * ```typescript
324
- * // Add 90 minutes from midnight
325
- * addMinutesToDate(new Date('2025-01-01'), 90);
326
- * // Returns: { year: 2025, month: 1, day: 1, hours: 1, minutes: 30 }
327
- *
328
- * // Add 1500 minutes (spans to next day)
329
- * addMinutesToDate(new Date('2025-01-01'), 1500);
330
- * // Returns: { year: 2025, month: 1, day: 2, hours: 1, minutes: 0 }
331
- * ```
332
- */
333
- export function addMinutesToDate(baseDate: Date, minutes: number): DateTime {
334
- const days = Math.floor(minutes / 1440);
335
- const minutesInDay = minutes % 1440;
336
-
337
- const targetDate = new Date(baseDate);
338
- targetDate.setDate(targetDate.getDate() + days);
339
-
340
- return {
341
- year: targetDate.getFullYear(),
342
- month: targetDate.getMonth() + 1,
343
- day: targetDate.getDate(),
344
- hours: Math.floor(minutesInDay / 60),
345
- minutes: minutesInDay % 60,
346
- };
347
- }
348
-
349
- /**
350
- * Returns the points where a range should be split, filtered to within [start, end).
351
- * Always includes range start. Sorted ascending.
352
- */
353
- export function splitPoints([start, end]: [number, number], splitAt: number[]): number[] {
354
- const points = new Set<number>([start]);
355
-
356
- for (const p of splitAt) {
357
- if (p > start && p < end) points.add(p);
358
- }
359
-
360
- return [...points].toSorted((a, b) => a - b);
361
- }
362
-
363
32
  /**
364
33
  * Computes the list of day strings (YYYY-MM-DD) from a SchedulingPeriod.
365
34
  *
package/src/index.ts CHANGED
@@ -1,15 +1,12 @@
1
1
  /**
2
2
  * Scheduling library powered by constraint programming (CP-SAT).
3
3
  *
4
- * Define teams, shifts, coverage, and rules declaratively. dabke compiles
5
- * them into a constraint model and solves for an optimized schedule.
6
- *
7
4
  * @remarks
8
5
  * ## Core Concepts
9
6
  *
10
- * **Schedule Definition**: The primary API. Small, composable functions
7
+ * **Schedule**: The primary API. Small, composable functions
11
8
  * ({@link time}, {@link cover}, {@link shift}, rule functions) produce a
12
- * complete scheduling configuration via {@link defineSchedule}. Each concept
9
+ * complete scheduling configuration via {@link schedule}. Each concept
13
10
  * is a single function call with full type safety.
14
11
  *
15
12
  * **Times vs Shift Patterns**: These are two distinct concepts.
@@ -28,73 +25,9 @@
28
25
  * - Scoping: apply rules globally, per person, per role, per skill, or per time period
29
26
  * - Priority: `MANDATORY` (hard constraint) vs `LOW`/`MEDIUM`/`HIGH` (soft preferences)
30
27
  *
31
- * **Solving**: {@link ScheduleDefinition.createSchedulerConfig} merges the
32
- * static definition with runtime data (members, scheduling period).
33
- * {@link ModelBuilder} compiles the config into a solver request;
34
- * {@link HttpSolverClient} sends it to the CP-SAT solver.
35
- *
36
- * @example Define a schedule
37
- * ```typescript
38
- * import {
39
- * defineSchedule, t, time, cover, shift,
40
- * maxHoursPerWeek, minRestBetweenShifts, timeOff,
41
- * weekdays, weekend,
42
- * } from "dabke";
43
- *
44
- * const schedule = defineSchedule({
45
- * roles: ["nurse", "doctor"],
46
- * skills: ["charge_nurse"],
47
- *
48
- * times: {
49
- * morning_round: time({ startTime: t(7), endTime: t(9) }),
50
- * day_ward: time({ startTime: t(7), endTime: t(15) }),
51
- * night_ward: time({ startTime: t(23), endTime: t(7) }),
52
- * },
53
- *
54
- * coverage: [
55
- * cover("morning_round", "doctor", 1),
56
- * cover("day_ward", "nurse", 3, { dayOfWeek: weekdays }),
57
- * cover("day_ward", "nurse", 2, { dayOfWeek: weekend }),
58
- * cover("night_ward", "nurse", 2),
59
- * cover("night_ward", "charge_nurse", 1),
60
- * ],
61
- *
62
- * shiftPatterns: [
63
- * shift("day", t(7), t(15)),
64
- * shift("night", t(23), t(7)),
65
- * ],
66
- *
67
- * rules: [
68
- * maxHoursPerWeek(40),
69
- * minRestBetweenShifts(11),
70
- * timeOff({ appliesTo: "alice", dayOfWeek: weekend }),
71
- * ],
72
- * });
73
- * ```
74
- *
75
- * @example Solve a schedule
76
- * ```typescript
77
- * import { ModelBuilder, HttpSolverClient, parseSolverResponse } from "dabke";
78
- *
79
- * const config = schedule.createSchedulerConfig({
80
- * schedulingPeriod: {
81
- * dateRange: { start: "2026-02-09", end: "2026-02-15" },
82
- * },
83
- * members: [
84
- * { id: "alice", roles: ["nurse"], skills: ["charge_nurse"] },
85
- * { id: "bob", roles: ["nurse"] },
86
- * { id: "carol", roles: ["doctor"] },
87
- * ],
88
- * });
89
- *
90
- * const builder = new ModelBuilder(config);
91
- * const { request, canSolve, validation } = builder.compile();
92
- * if (canSolve) {
93
- * const client = new HttpSolverClient(fetch, "http://localhost:8080");
94
- * const response = await client.solve(request);
95
- * const result = parseSolverResponse(response);
96
- * }
97
- * ```
28
+ * **Solving**: {@link Schedule.compile} compiles the config into a
29
+ * solver request; {@link Schedule.solve} sends it to the CP-SAT solver
30
+ * and returns a {@link SolveResult}.
98
31
  *
99
32
  * @packageDocumentation
100
33
  */
@@ -103,22 +36,10 @@
103
36
  // Time primitives
104
37
  // ============================================================================
105
38
 
106
- export type { TimeOfDay, DayOfWeek, DateTime, SchedulingPeriod } from "./types.js";
39
+ export type { TimeOfDay, DayOfWeek, SchedulingPeriod } from "./types.js";
107
40
 
108
41
  export { DayOfWeekSchema } from "./types.js";
109
42
 
110
- // ============================================================================
111
- // Date/time utilities
112
- // ============================================================================
113
-
114
- export { dateTimeToDate } from "./datetime.utils.js";
115
-
116
- // ============================================================================
117
- // Errors
118
- // ============================================================================
119
-
120
- export { ORSchedulingError } from "./errors.js";
121
-
122
43
  // ============================================================================
123
44
  // Solver client
124
45
  // ============================================================================
@@ -149,7 +70,6 @@ export type {
149
70
  CompilationResult,
150
71
  CompilationRule,
151
72
  RuleValidationContext,
152
- CostContext,
153
73
  CostEntry,
154
74
  CostContribution,
155
75
  } from "./cpsat/model-builder.js";
@@ -162,15 +82,22 @@ export { parseSolverResponse, resolveAssignments } from "./cpsat/response.js";
162
82
 
163
83
  export type { ShiftAssignment, ResolvedShiftAssignment, SolverResult } from "./cpsat/response.js";
164
84
 
85
+ // ============================================================================
86
+ // Cost calculation
87
+ // ============================================================================
88
+
89
+ export { calculateScheduleCost, COST_CATEGORY } from "./cpsat/cost.js";
90
+
91
+ export type { CostBreakdown, MemberCostDetail, CostCalculationConfig } from "./cpsat/cost.js";
92
+
165
93
  // ============================================================================
166
94
  // Rules (registry types)
167
95
  // ============================================================================
168
96
 
169
97
  export type {
170
- CpsatRuleRegistry,
171
- CpsatRuleName,
172
98
  CpsatRuleConfigEntry,
173
99
  CpsatRuleFactories,
100
+ CreateCpsatRuleFunction,
174
101
  } from "./cpsat/rules/rules.types.js";
175
102
 
176
103
  export type { RecurringPeriod } from "./cpsat/rules/scope.types.js";
@@ -186,9 +113,7 @@ export type {
186
113
  SalariedPay,
187
114
  SchedulingMember,
188
115
  ShiftPattern,
189
- CoverageRequirement,
190
116
  Priority,
191
- ModelBuilderOptions,
192
117
  } from "./cpsat/types.js";
193
118
 
194
119
  // ============================================================================
@@ -201,35 +126,32 @@ export { OBJECTIVE_WEIGHTS } from "./cpsat/utils.js";
201
126
  // Validation
202
127
  // ============================================================================
203
128
 
204
- export type { ValidationReporter } from "./cpsat/validation-reporter.js";
205
-
206
129
  export type {
130
+ ValidationGroup,
207
131
  ScheduleValidation,
208
132
  ScheduleError,
209
- ScheduleViolation,
210
- SchedulePassed,
211
133
  CoverageError,
212
- CoverageViolation,
213
- CoveragePassed,
214
134
  RuleError,
135
+ SolverError,
136
+ ScheduleViolation,
137
+ CoverageViolation,
215
138
  RuleViolation,
139
+ SchedulePassed,
140
+ CoveragePassed,
216
141
  RulePassed,
217
- SolverError,
218
- ValidationContext,
219
142
  ValidationSummary,
220
- GroupKey,
221
143
  } from "./cpsat/validation.types.js";
222
144
 
223
145
  export { summarizeValidation } from "./cpsat/validation-reporter.js";
224
146
 
225
- export { groupKey } from "./cpsat/validation.types.js";
226
-
227
147
  // ============================================================================
228
- // Schedule Definition API (v2)
148
+ // Schedule API
229
149
  // ============================================================================
230
150
 
231
151
  export {
232
- defineSchedule,
152
+ schedule,
153
+ partialSchedule,
154
+ Schedule,
233
155
  t,
234
156
  time,
235
157
  cover,
@@ -238,14 +160,18 @@ export {
238
160
  maxHoursPerWeek,
239
161
  minHoursPerDay,
240
162
  minHoursPerWeek,
163
+ maxDaysPerWeek,
164
+ minDaysPerWeek,
241
165
  maxShiftsPerDay,
242
166
  maxConsecutiveDays,
243
167
  minConsecutiveDays,
244
168
  minRestBetweenShifts,
169
+ mustAssign,
245
170
  preference,
246
171
  preferLocation,
247
172
  timeOff,
248
173
  assignTogether,
174
+ defineRule,
249
175
  minimizeCost,
250
176
  dayMultiplier,
251
177
  daySurcharge,
@@ -257,19 +183,21 @@ export {
257
183
  tieredOvertimeMultiplier,
258
184
  weekdays,
259
185
  weekend,
260
- } from "./schedule.js";
186
+ } from "./schedule/index.js";
261
187
 
262
188
  export type {
263
189
  CoverageEntry,
264
190
  CoverageOptions,
265
191
  CoverageVariant,
266
192
  RuleEntry,
193
+ RuleResolveContext,
267
194
  RuleOptions,
268
195
  EntityOnlyRuleOptions,
269
196
  TimeOffOptions,
270
197
  AssignTogetherOptions,
271
198
  CostRuleOptions,
272
- RuntimeArgs,
273
- ScheduleDefinition,
274
199
  ScheduleConfig,
275
- } from "./schedule.js";
200
+ SolveResult,
201
+ SolveStatus,
202
+ SolveOptions,
203
+ } from "./schedule/index.js";