dabke 0.81.0 → 0.82.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 (172) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +126 -302
  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/max-consecutive-days.d.ts.map +1 -1
  30. package/dist/cpsat/rules/max-consecutive-days.js +16 -2
  31. package/dist/cpsat/rules/max-consecutive-days.js.map +1 -1
  32. package/dist/cpsat/rules/max-hours-day.d.ts.map +1 -1
  33. package/dist/cpsat/rules/max-hours-day.js +15 -2
  34. package/dist/cpsat/rules/max-hours-day.js.map +1 -1
  35. package/dist/cpsat/rules/max-hours-week.d.ts.map +1 -1
  36. package/dist/cpsat/rules/max-hours-week.js +16 -2
  37. package/dist/cpsat/rules/max-hours-week.js.map +1 -1
  38. package/dist/cpsat/rules/max-shifts-day.d.ts.map +1 -1
  39. package/dist/cpsat/rules/max-shifts-day.js +15 -2
  40. package/dist/cpsat/rules/max-shifts-day.js.map +1 -1
  41. package/dist/cpsat/rules/min-consecutive-days.d.ts.map +1 -1
  42. package/dist/cpsat/rules/min-consecutive-days.js +15 -2
  43. package/dist/cpsat/rules/min-consecutive-days.js.map +1 -1
  44. package/dist/cpsat/rules/min-hours-day.d.ts.map +1 -1
  45. package/dist/cpsat/rules/min-hours-day.js +15 -2
  46. package/dist/cpsat/rules/min-hours-day.js.map +1 -1
  47. package/dist/cpsat/rules/min-hours-week.d.ts.map +1 -1
  48. package/dist/cpsat/rules/min-hours-week.js +16 -2
  49. package/dist/cpsat/rules/min-hours-week.js.map +1 -1
  50. package/dist/cpsat/rules/min-rest-between-shifts.d.ts.map +1 -1
  51. package/dist/cpsat/rules/min-rest-between-shifts.js +72 -2
  52. package/dist/cpsat/rules/min-rest-between-shifts.js.map +1 -1
  53. package/dist/cpsat/rules/minimize-cost.d.ts.map +1 -1
  54. package/dist/cpsat/rules/minimize-cost.js +2 -23
  55. package/dist/cpsat/rules/minimize-cost.js.map +1 -1
  56. package/dist/cpsat/rules/overtime-daily-multiplier.d.ts.map +1 -1
  57. package/dist/cpsat/rules/overtime-daily-multiplier.js +1 -12
  58. package/dist/cpsat/rules/overtime-daily-multiplier.js.map +1 -1
  59. package/dist/cpsat/rules/overtime-daily-surcharge.d.ts.map +1 -1
  60. package/dist/cpsat/rules/overtime-daily-surcharge.js +1 -5
  61. package/dist/cpsat/rules/overtime-daily-surcharge.js.map +1 -1
  62. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts +5 -1
  63. package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts.map +1 -1
  64. package/dist/cpsat/rules/overtime-tiered-multiplier.js +1 -12
  65. package/dist/cpsat/rules/overtime-tiered-multiplier.js.map +1 -1
  66. package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts.map +1 -1
  67. package/dist/cpsat/rules/overtime-weekly-multiplier.js +1 -12
  68. package/dist/cpsat/rules/overtime-weekly-multiplier.js.map +1 -1
  69. package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts.map +1 -1
  70. package/dist/cpsat/rules/overtime-weekly-surcharge.js +1 -5
  71. package/dist/cpsat/rules/overtime-weekly-surcharge.js.map +1 -1
  72. package/dist/cpsat/rules/registry.d.ts +25 -2
  73. package/dist/cpsat/rules/registry.d.ts.map +1 -1
  74. package/dist/cpsat/rules/registry.js.map +1 -1
  75. package/dist/cpsat/rules/resolver.js +2 -2
  76. package/dist/cpsat/rules/resolver.js.map +1 -1
  77. package/dist/cpsat/rules/scope.types.d.ts +18 -1
  78. package/dist/cpsat/rules/scope.types.d.ts.map +1 -1
  79. package/dist/cpsat/rules/scope.types.js +59 -16
  80. package/dist/cpsat/rules/scope.types.js.map +1 -1
  81. package/dist/cpsat/rules/time-cost-surcharge.d.ts.map +1 -1
  82. package/dist/cpsat/rules/time-cost-surcharge.js +2 -1
  83. package/dist/cpsat/rules/time-cost-surcharge.js.map +1 -1
  84. package/dist/cpsat/rules/time-off.d.ts.map +1 -1
  85. package/dist/cpsat/rules/time-off.js +6 -3
  86. package/dist/cpsat/rules/time-off.js.map +1 -1
  87. package/dist/cpsat/semantic-time.d.ts +44 -42
  88. package/dist/cpsat/semantic-time.d.ts.map +1 -1
  89. package/dist/cpsat/semantic-time.js +64 -46
  90. package/dist/cpsat/semantic-time.js.map +1 -1
  91. package/dist/cpsat/types.d.ts +37 -27
  92. package/dist/cpsat/types.d.ts.map +1 -1
  93. package/dist/cpsat/utils.d.ts.map +1 -1
  94. package/dist/cpsat/utils.js +7 -12
  95. package/dist/cpsat/utils.js.map +1 -1
  96. package/dist/cpsat/validation-reporter.d.ts +10 -7
  97. package/dist/cpsat/validation-reporter.d.ts.map +1 -1
  98. package/dist/cpsat/validation-reporter.js +44 -72
  99. package/dist/cpsat/validation-reporter.js.map +1 -1
  100. package/dist/cpsat/validation.types.d.ts +54 -44
  101. package/dist/cpsat/validation.types.d.ts.map +1 -1
  102. package/dist/cpsat/validation.types.js +15 -10
  103. package/dist/cpsat/validation.types.js.map +1 -1
  104. package/dist/datetime.utils.d.ts +3 -203
  105. package/dist/datetime.utils.d.ts.map +1 -1
  106. package/dist/datetime.utils.js +1 -288
  107. package/dist/datetime.utils.js.map +1 -1
  108. package/dist/index.d.ts +15 -86
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +12 -86
  111. package/dist/index.js.map +1 -1
  112. package/dist/llms.d.ts +1 -1
  113. package/dist/llms.d.ts.map +1 -1
  114. package/dist/llms.js +1 -1
  115. package/dist/llms.js.map +1 -1
  116. package/dist/schedule.d.ts +437 -244
  117. package/dist/schedule.d.ts.map +1 -1
  118. package/dist/schedule.js +729 -305
  119. package/dist/schedule.js.map +1 -1
  120. package/dist/types.d.ts +14 -78
  121. package/dist/types.d.ts.map +1 -1
  122. package/dist/types.js.map +1 -1
  123. package/llms.txt +346 -513
  124. package/package.json +1 -1
  125. package/solver/src/solver/app.py +1 -1
  126. package/solver/src/solver/solver.py +7 -4
  127. package/src/client.ts +6 -8
  128. package/src/client.types.ts +9 -0
  129. package/src/cpsat/model-builder.ts +44 -35
  130. package/src/cpsat/response.ts +13 -1
  131. package/src/cpsat/rules/cost-utils.ts +25 -0
  132. package/src/cpsat/rules/day-cost-multiplier.ts +3 -14
  133. package/src/cpsat/rules/day-cost-surcharge.ts +3 -8
  134. package/src/cpsat/rules/max-consecutive-days.ts +17 -0
  135. package/src/cpsat/rules/max-hours-day.ts +21 -1
  136. package/src/cpsat/rules/max-hours-week.ts +22 -1
  137. package/src/cpsat/rules/max-shifts-day.ts +21 -1
  138. package/src/cpsat/rules/min-consecutive-days.ts +16 -1
  139. package/src/cpsat/rules/min-hours-day.ts +16 -1
  140. package/src/cpsat/rules/min-hours-week.ts +17 -1
  141. package/src/cpsat/rules/min-rest-between-shifts.ts +92 -2
  142. package/src/cpsat/rules/minimize-cost.ts +2 -29
  143. package/src/cpsat/rules/overtime-daily-multiplier.ts +1 -12
  144. package/src/cpsat/rules/overtime-daily-surcharge.ts +1 -6
  145. package/src/cpsat/rules/overtime-tiered-multiplier.ts +6 -13
  146. package/src/cpsat/rules/overtime-weekly-multiplier.ts +1 -12
  147. package/src/cpsat/rules/overtime-weekly-surcharge.ts +1 -6
  148. package/src/cpsat/rules/registry.ts +2 -2
  149. package/src/cpsat/rules/resolver.ts +2 -2
  150. package/src/cpsat/rules/scope.types.ts +73 -20
  151. package/src/cpsat/rules/time-cost-surcharge.ts +2 -1
  152. package/src/cpsat/rules/time-off.ts +6 -2
  153. package/src/cpsat/semantic-time.ts +115 -91
  154. package/src/cpsat/types.ts +37 -27
  155. package/src/cpsat/utils.ts +8 -12
  156. package/src/cpsat/validation-reporter.ts +51 -82
  157. package/src/cpsat/validation.types.ts +72 -47
  158. package/src/datetime.utils.ts +3 -334
  159. package/src/index.ts +31 -108
  160. package/src/llms.ts +1 -1
  161. package/src/schedule.ts +1008 -467
  162. package/src/types.ts +14 -88
  163. package/dist/errors.d.ts +0 -12
  164. package/dist/errors.d.ts.map +0 -1
  165. package/dist/errors.js +0 -17
  166. package/dist/errors.js.map +0 -1
  167. package/dist/validation.d.ts +0 -105
  168. package/dist/validation.d.ts.map +0 -1
  169. package/dist/validation.js +0 -130
  170. package/dist/validation.js.map +0 -1
  171. package/src/errors.ts +0 -17
  172. package/src/validation.ts +0 -188
package/CHANGELOG.md CHANGED
@@ -5,6 +5,47 @@ All notable changes to this project will be documented in this file.
5
5
  This changelog was generated from the git history of the project when it was
6
6
  named `scheduling-core`, prior to the rename to `dabke` in v0.78.0.
7
7
 
8
+ ## 0.82.0 (2026-02-23)
9
+
10
+ ### Breaking Changes
11
+
12
+ - **Replace `defineSchedule` with `schedule`/`with`/`compile`/`solve` API**: the
13
+ `defineSchedule()` function, `ScheduleDefinition`, and `RuntimeArgs` are removed.
14
+ Use `schedule()` to create an immutable `Schedule`, compose data with `.with()`,
15
+ and execute via `.compile()` or `.solve()`.
16
+ - **Rename `roles`/`skills` back to `roleIds`/`skillIds`**: all public type fields and
17
+ function options (`SchedulingMember`, `ShiftPattern`, coverage types, `ScheduleConfig`)
18
+ revert to `roleIds`/`skillIds` for unambiguous signaling to LLM consumers.
19
+ - **Redesign validation message architecture**: `ValidationGroup` now uses deterministic
20
+ structural keys (e.g. `rule:max-hours-week:40:roles:nurse`) instead of counter-based
21
+ IDs. Validation items use a unified `message` field replacing `reason`/`description`.
22
+ `ValidationSummary.title` replaces `description`.
23
+ - **Trim public API surface** (102 to 86 exports): remove internal types
24
+ (`ValidationReporter`, `ValidationContext`, `CostContext`, `ModelBuilderOptions`,
25
+ `CoverageRequirement`, `CpsatRuleRegistry`, `DateTime`), legacy validation, and
26
+ unused datetime utilities.
27
+ - **`SolveResult` status** uses lowercase strings: `optimal`, `feasible`, `infeasible`,
28
+ `no_solution`.
29
+
30
+ ### Improvements
31
+
32
+ - `solve()` runs post-solve validation automatically; `SolveResult.validation` includes
33
+ soft constraint violations.
34
+ - `ScheduleConfig` requires `times`, `coverage`, `shiftPatterns`; `partialSchedule()`
35
+ allows partial configs for composition via `.with()`.
36
+ - Eager validation in `.with()` for role/skill disjointness and member references.
37
+ - All `dayOfWeek` fields typed as `readonly [DayOfWeek, ...DayOfWeek[]]` consistently.
38
+ - Add constraint IDs, group keys, and `trackConstraint()` to all soft rules for
39
+ post-solve verification.
40
+ - Add `@category` TSDoc tags to all public exports for structured documentation.
41
+ - Restructure docs reference nav with automated category-driven generation.
42
+
43
+ ## 0.81.1 (2026-02-20)
44
+
45
+ ### Documentation
46
+
47
+ - Rewrite README for the v2 `defineSchedule` API with a verified cafe scheduling example.
48
+
8
49
  ## 0.81.0 (2026-02-19)
9
50
 
10
51
  ### Breaking Changes
package/README.md CHANGED
@@ -4,378 +4,202 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
5
  [![CI](https://github.com/christianklotz/dabke/actions/workflows/ci.yml/badge.svg)](https://github.com/christianklotz/dabke/actions/workflows/ci.yml)
6
6
 
7
- Scheduling library powered by constraint programming (CP-SAT).
7
+ TypeScript scheduling library powered by constraint programming.
8
8
 
9
- Define your team, shifts, coverage, and rules dabke turns them into an optimized schedule.
9
+ Define teams, shifts, coverage, and rules declaratively. dabke compiles them into a CP-SAT model and solves for an optimized schedule.
10
10
 
11
11
  ```typescript
12
- import { ModelBuilder, HttpSolverClient } from "dabke";
12
+ import {
13
+ schedule,
14
+ t,
15
+ time,
16
+ cover,
17
+ shift,
18
+ maxHoursPerWeek,
19
+ minRestBetweenShifts,
20
+ timeOff,
21
+ minimizeCost,
22
+ weekdays,
23
+ weekend,
24
+ } from "dabke";
25
+
26
+ const venue = schedule({
27
+ roleIds: ["barista", "server"],
28
+
29
+ // Times: WHEN you need people (named periods for coverage + rules)
30
+ times: {
31
+ breakfast: time({ startTime: t(7), endTime: t(10) }),
32
+ lunch_rush: time(
33
+ { startTime: t(11, 30), endTime: t(14) },
34
+ { startTime: t(11), endTime: t(15), dayOfWeek: weekend },
35
+ ),
36
+ closing: time({ startTime: t(20), endTime: t(22) }),
37
+ },
13
38
 
14
- const builder = new ModelBuilder({
15
- employees: [
16
- { id: "alice", roleIds: ["server"] },
17
- { id: "bob", roleIds: ["server"] },
39
+ // Coverage: HOW MANY people you need during each time
40
+ coverage: [
41
+ cover("breakfast", "barista", 1),
42
+ cover("lunch_rush", "barista", 2, { dayOfWeek: weekdays }),
43
+ cover("lunch_rush", "barista", 3, { dayOfWeek: weekend }),
44
+ cover("lunch_rush", "server", 1),
45
+ cover("closing", "server", 1),
18
46
  ],
47
+
48
+ // Shifts: WHEN people CAN work (the actual time slots)
49
+ // An opener covers breakfast + lunch; a closer covers lunch + closing
19
50
  shiftPatterns: [
20
- { id: "morning", startTime: { hours: 8 }, endTime: { hours: 16 } },
21
- { id: "evening", startTime: { hours: 16 }, endTime: { hours: 23 } },
22
- ],
23
- coverage: [
24
- {
25
- day: "2026-02-09",
26
- startTime: { hours: 8 },
27
- endTime: { hours: 16 },
28
- roleIds: ["server"],
29
- targetCount: 1,
30
- priority: "MANDATORY",
31
- },
32
- {
33
- day: "2026-02-09",
34
- startTime: { hours: 16 },
35
- endTime: { hours: 23 },
36
- roleIds: ["server"],
37
- targetCount: 1,
38
- priority: "MANDATORY",
39
- },
51
+ shift("opener", t(6), t(14)),
52
+ shift("mid", t(10), t(18)),
53
+ shift("closer", t(14), t(22)),
40
54
  ],
41
- schedulingPeriod: {
42
- dateRange: { start: "2026-02-09", end: "2026-02-09" },
43
- },
44
- ruleConfigs: [
45
- { name: "max-hours-day", config: { hours: 8, priority: "MANDATORY" } },
46
- { name: "min-rest-between-shifts", config: { hours: 10, priority: "MANDATORY" } },
55
+
56
+ rules: [
57
+ maxHoursPerWeek(40),
58
+ minRestBetweenShifts(11),
59
+ timeOff({ appliesTo: "alice", dayOfWeek: weekend }),
60
+ minimizeCost(),
47
61
  ],
48
62
  });
49
-
50
- const { request } = builder.compile();
51
- const solver = new HttpSolverClient(fetch, "http://localhost:8080");
52
- const response = await solver.solve(request);
53
63
  ```
54
64
 
55
- ## Why dabke?
56
-
57
- Staff scheduling with constraint programming is dominated by Python ([OR-Tools](https://developers.google.com/optimization)) and Java ([Timefold](https://timefold.ai/)). If you're building in TypeScript, your options have been: call a Python service and figure out the model yourself, or write scheduling heuristics by hand.
58
-
59
- dabke gives you a **TypeScript-native API** for expressing scheduling problems declaratively — employees, shifts, coverage requirements, and rules — and compiles them into a CP-SAT model solved by OR-Tools. You describe _what_ you need, not _how_ to solve it.
60
-
61
- **Key differences from rolling your own:**
62
-
63
- - **Declarative rules** — express constraints like "max 8 hours/day" or "11 hours rest between shifts" as config, not code
64
- - **Semantic time** — define named periods ("lunch_rush", "closing") that vary by day of week
65
- - **Soft and hard constraints** — some rules are mandatory, others are preferences the solver optimizes for
66
- - **Scoped rules** — apply constraints globally, per person, per role, per skill, or during specific time periods
67
- - **Validation** — detailed reporting on coverage gaps and rule violations before and after solving
68
-
69
- ## Install
65
+ ## Quick Start
70
66
 
71
67
  ```bash
72
68
  npm install dabke
73
69
  ```
74
70
 
75
- ## Quick Start
76
-
77
- ### 1. Start the solver
78
-
79
- dabke compiles scheduling problems into a constraint model. You need a CP-SAT solver to solve it. A ready-to-use solver is included:
71
+ dabke compiles scheduling problems into a constraint model. You need a CP-SAT solver to find the solution:
80
72
 
81
73
  ```bash
82
- # Pull the solver image
83
74
  docker pull christianklotz/dabke-solver
84
-
85
- # Start it
86
75
  docker run -p 8080:8080 christianklotz/dabke-solver
87
76
  ```
88
77
 
89
- Or build from source:
90
-
91
- ```bash
92
- cd node_modules/dabke/solver
93
- docker build -t dabke-solver .
94
- docker run -p 8080:8080 dabke-solver
95
- ```
96
-
97
- ### 2. Build and solve a schedule
78
+ Once you have a schedule definition, add members and solve:
98
79
 
99
80
  ```typescript
100
- import { ModelBuilder, HttpSolverClient, parseSolverResponse, resolveAssignments } from "dabke";
101
-
102
- // Define team
103
- const employees = [
104
- { id: "alice", roleIds: ["server"] },
105
- { id: "bob", roleIds: ["server"] },
106
- ];
107
-
108
- // Define shift patterns
109
- const shiftPatterns = [
110
- { id: "morning", startTime: { hours: 8 }, endTime: { hours: 16 } },
111
- { id: "evening", startTime: { hours: 16 }, endTime: { hours: 23 } },
112
- ];
113
-
114
- // Define coverage requirements
115
- const coverage = [
116
- {
117
- day: "2026-02-09",
118
- startTime: { hours: 8 },
119
- endTime: { hours: 16 },
120
- roleIds: ["server"] as [string],
121
- targetCount: 1,
122
- priority: "MANDATORY" as const,
123
- },
124
- {
125
- day: "2026-02-09",
126
- startTime: { hours: 16 },
127
- endTime: { hours: 23 },
128
- roleIds: ["server"] as [string],
129
- targetCount: 1,
130
- priority: "MANDATORY" as const,
131
- },
132
- ];
133
-
134
- // Build the model
135
- const builder = new ModelBuilder({
136
- employees,
137
- shiftPatterns,
138
- coverage,
139
- schedulingPeriod: {
140
- dateRange: { start: "2026-02-09", end: "2026-02-09" },
141
- },
142
- ruleConfigs: [
143
- { name: "max-hours-day", config: { hours: 8, priority: "MANDATORY" } },
144
- { name: "min-rest-between-shifts", config: { hours: 10, priority: "MANDATORY" } },
145
- ],
146
- });
81
+ import { HttpSolverClient } from "dabke";
147
82
 
148
- const { request, canSolve, validation } = builder.compile();
83
+ const result = await venue
84
+ .with([
85
+ { id: "alice", roleIds: ["barista", "server"], pay: { hourlyRate: 1500 } },
86
+ { id: "bob", roleIds: ["barista"], pay: { hourlyRate: 1200 } },
87
+ { id: "carol", roleIds: ["barista", "server"], pay: { hourlyRate: 1400 } },
88
+ { id: "dave", roleIds: ["barista", "server"], pay: { hourlyRate: 1200 } },
89
+ { id: "eve", roleIds: ["barista", "server"], pay: { hourlyRate: 1300 } },
90
+ ])
91
+ .solve(new HttpSolverClient(fetch, "http://localhost:8080"), {
92
+ dateRange: { start: "2026-02-09", end: "2026-02-15" },
93
+ });
149
94
 
150
- if (!canSolve) {
151
- console.error("Cannot solve:", validation.errors);
152
- process.exit(1);
153
- }
154
-
155
- // Solve
156
- const solver = new HttpSolverClient(fetch, "http://localhost:8080");
157
- const response = await solver.solve(request);
158
- const result = parseSolverResponse(response);
159
-
160
- if (result.status === "OPTIMAL" || result.status === "FEASIBLE") {
161
- const shifts = resolveAssignments(result.assignments, shiftPatterns);
162
- for (const shift of shifts) {
163
- console.log(
164
- `${shift.employeeId}: ${shift.day} ${shift.startTime.hours}:00–${shift.endTime.hours}:00`,
165
- );
166
- }
167
- }
95
+ console.log(result.status); // "optimal" | "feasible" | "infeasible" | "no_solution"
96
+ console.log(result.assignments); // Shift assignments per member per day
168
97
  ```
169
98
 
170
- ## Semantic Time
171
-
172
- Define named time periods that can vary by day, then write coverage requirements in business terms:
99
+ Or compile and solve manually for more control:
173
100
 
174
101
  ```typescript
175
- import { defineSemanticTimes } from "dabke";
176
-
177
- const times = defineSemanticTimes({
178
- lunch: [
179
- {
180
- startTime: { hours: 11, minutes: 30 },
181
- endTime: { hours: 14 },
182
- dayOfWeek: ["monday", "tuesday", "wednesday", "thursday", "friday"],
183
- },
184
- {
185
- startTime: { hours: 12 },
186
- endTime: { hours: 15 },
187
- dayOfWeek: ["saturday", "sunday"],
188
- },
189
- ],
190
- closing: { startTime: { hours: 21 }, endTime: { hours: 23 } },
191
- });
192
-
193
- const coverage = times.coverage([
194
- { semanticTime: "lunch", roleIds: ["server"], targetCount: 3, priority: "MANDATORY" },
195
- { semanticTime: "closing", roleIds: ["server"], targetCount: 1, priority: "HIGH" },
196
- ]);
197
-
198
- // Resolve against actual scheduling days
199
- const days = ["2026-02-09", "2026-02-10", "2026-02-11"];
200
- const resolved = times.resolve(coverage, days);
102
+ const compiled = venue
103
+ .with([...members])
104
+ .compile({ dateRange: { start: "2026-02-09", end: "2026-02-15" } });
105
+
106
+ if (compiled.canSolve) {
107
+ const solver = new HttpSolverClient(fetch, "http://localhost:8080");
108
+ const response = await solver.solve(compiled.request);
109
+ // ...
110
+ }
201
111
  ```
202
112
 
203
- ## Built-in Rules
113
+ ---
204
114
 
205
- | Rule | Description |
206
- | ------------------------------ | ----------------------------------------- |
207
- | `max-hours-day` | Max hours per person per day |
208
- | `max-hours-week` | Max hours per person per week |
209
- | `min-hours-day` | Min hours per person per day |
210
- | `min-hours-week` | Min hours per person per week |
211
- | `max-shifts-day` | Max shift assignments per day |
212
- | `max-consecutive-days` | Max consecutive working days |
213
- | `min-consecutive-days` | Min consecutive working days |
214
- | `min-rest-between-shifts` | Min rest hours between shifts |
215
- | `time-off` | Block assignments during periods |
216
- | `employee-assignment-priority` | Prefer or avoid assigning team members |
217
- | `assign-together` | Keep team members on the same shifts |
218
- | `location-preference` | Prefer team members at specific locations |
115
+ ## Key Concepts
219
116
 
220
- All rules support scoping by person, role, skill, and time period (date ranges, days of week, recurring periods).
117
+ **Times vs shift patterns.** These are two distinct things. Times are named periods you need coverage for ("breakfast", "lunch_rush"). Shift patterns are the time slots people actually work ("opener 6-14", "closer 14-22"). They don't need to match. The solver assigns members to shift patterns whose hours overlap with times to satisfy coverage.
221
118
 
222
- ### Scoping Example
119
+ **Coverage.** How many people with which roles you need during each time. Coverage can vary by day of week or specific dates using scoping options or the variant form of `cover()`.
223
120
 
224
- ```typescript
225
- // Students can work max 4 hours on weekdays
226
- {
227
- name: "max-hours-day",
228
- config: {
229
- roleIds: ["student"],
230
- hours: 4,
231
- dayOfWeek: ["monday", "tuesday", "wednesday", "thursday", "friday"],
232
- priority: "MANDATORY",
233
- },
234
- }
235
-
236
- // Alice has time off next week
237
- {
238
- name: "time-off",
239
- config: {
240
- employeeIds: ["alice"],
241
- dateRange: { start: "2026-02-09", end: "2026-02-13" },
242
- priority: "MANDATORY",
243
- },
244
- }
245
- ```
121
+ **Rules.** Business constraints expressed as function calls. Rules with `priority: "MANDATORY"` (the default) are hard constraints the solver will never violate. Rules with `LOW`, `MEDIUM`, or `HIGH` priority are soft preferences the solver optimizes across.
246
122
 
247
- ### Soft vs. Hard Constraints
248
-
249
- Rules with `priority: "MANDATORY"` are hard constraints — the solver will not violate them. Rules with `LOW`, `MEDIUM`, or `HIGH` priority are soft constraints — the solver tries to satisfy them but will trade them off against each other to find the best overall schedule.
123
+ **Scoping.** Every rule accepts `appliesTo` (a role, skill, or member ID), plus time scoping (`dayOfWeek`, `dateRange`, `dates`, `recurringPeriods`) to target when and who:
250
124
 
251
125
  ```typescript
252
- // Hard: legally required rest period
253
- { name: "min-rest-between-shifts", config: { hours: 11, priority: "MANDATORY" } }
254
-
255
- // Soft: prefer to keep Bob under 30 hours/week
256
- { name: "max-hours-week", config: { employeeIds: ["bob"], hours: 30, weekStartsOn: "monday", priority: "MEDIUM" } }
126
+ maxHoursPerDay(8, { appliesTo: "barista", dayOfWeek: weekdays }),
127
+ timeOff({ appliesTo: "alice", dateRange: { start: "2026-02-09", end: "2026-02-13" } }),
128
+ maxHoursPerWeek(30, { appliesTo: "bob", priority: "MEDIUM" }),
257
129
  ```
258
130
 
259
- ## Validation
131
+ **Cost optimization.** Members declare `pay` as hourly or salaried. Cost rules (`minimizeCost`, `dayMultiplier`, `overtimeMultiplier`, `tieredOvertimeMultiplier`, etc.) tell the solver to minimize total labor cost, factoring in overtime, day premiums, and time-based surcharges.
260
132
 
261
- dabke validates schedules and reports coverage gaps and rule violations:
133
+ **Composition with `.with()`.** Schedule definitions are immutable. Use `.with()` to merge other schedules or add members at runtime. Each `.with()` returns a new `Schedule` instance:
262
134
 
263
135
  ```typescript
264
- import { ValidationReporterImpl, summarizeValidation } from "dabke";
265
-
266
- const reporter = new ValidationReporterImpl();
267
- const builder = new ModelBuilder({ ...config, reporter });
268
- const { request, validation, canSolve } = builder.compile();
269
-
270
- // Pre-solve validation
271
- if (!canSolve) {
272
- for (const error of validation.errors) {
273
- console.error(error.reason);
274
- }
275
- }
136
+ const ready = venue.with([
137
+ { id: "alice", roleIds: ["barista"], pay: { hourlyRate: 1500 } },
138
+ { id: "bob", roleIds: ["barista"], pay: { hourlyRate: 1200 } },
139
+ ]);
140
+ ```
276
141
 
277
- // Post-solve validation (after solving)
278
- reporter.analyzeSolution(response);
279
- const results = reporter.getValidation();
280
- const summaries = summarizeValidation(results);
142
+ ---
281
143
 
282
- for (const s of summaries) {
283
- console.log(
284
- `${s.description}: ${s.status} (${s.passedCount}/${s.passedCount + s.violatedCount})`,
285
- );
286
- }
287
- ```
144
+ ## Rules
288
145
 
289
- ## Custom Rules
146
+ ### Scheduling
290
147
 
291
- dabke's rule system is extensible. You can create custom rules that integrate with the model builder:
148
+ | Function | Description |
149
+ | -------------------------- | ------------------------------------ |
150
+ | `maxHoursPerDay(hours)` | Max hours per person per day |
151
+ | `maxHoursPerWeek(hours)` | Max hours per person per week |
152
+ | `minHoursPerDay(hours)` | Min hours per person per day |
153
+ | `minHoursPerWeek(hours)` | Min hours per person per week |
154
+ | `maxShiftsPerDay(n)` | Max shift assignments per day |
155
+ | `maxConsecutiveDays(n)` | Max consecutive working days |
156
+ | `minConsecutiveDays(n)` | Min consecutive working days |
157
+ | `minRestBetweenShifts(h)` | Min rest hours between shifts |
158
+ | `timeOff(opts)` | Block assignments during periods |
159
+ | `preference(level, opts)` | Prefer or avoid assigning members |
160
+ | `preferLocation(id, opts)` | Prefer members at specific locations |
161
+ | `assignTogether(opts)` | Keep members on the same shifts |
292
162
 
293
- ```typescript
294
- import { createCpsatRuleFactory, type CompilationRule } from "dabke";
295
-
296
- function createNoSundayWorkRule(config: { priority: "MANDATORY" | "HIGH" }): CompilationRule {
297
- return {
298
- compile(b) {
299
- for (const emp of b.employees) {
300
- for (const day of b.days) {
301
- const date = new Date(`${day}T00:00:00Z`);
302
- if (date.getUTCDay() !== 0) continue; // Sunday = 0
303
- for (const pattern of b.shiftPatterns) {
304
- if (!b.canAssign(emp, pattern)) continue;
305
- b.addLinear([{ var: b.assignment(emp.id, pattern.id, day), coeff: 1 }], "<=", 0);
306
- }
307
- }
308
- }
309
- },
310
- };
311
- }
163
+ ### Cost
312
164
 
313
- const customRules = createCpsatRuleFactory({
314
- "no-sunday-work": createNoSundayWorkRule,
315
- });
316
- ```
165
+ | Function | Description |
166
+ | ---------------------------------------- | ---------------------------------------- |
167
+ | `minimizeCost()` | Minimize total labor cost |
168
+ | `dayMultiplier(factor, opts?)` | Pay multiplier for specific days |
169
+ | `daySurcharge(amount, opts?)` | Flat surcharge per hour on specific days |
170
+ | `timeSurcharge(amount, window, opts?)` | Surcharge during a time-of-day window |
171
+ | `overtimeMultiplier(opts)` | Weekly overtime pay multiplier |
172
+ | `overtimeSurcharge(opts)` | Weekly overtime flat surcharge |
173
+ | `dailyOvertimeMultiplier(opts)` | Daily overtime pay multiplier |
174
+ | `dailyOvertimeSurcharge(opts)` | Daily overtime flat surcharge |
175
+ | `tieredOvertimeMultiplier(tiers, opts?)` | Graduated overtime rates |
317
176
 
318
- See [CONTRIBUTING.md](CONTRIBUTING.md) for the full guide on writing custom rules.
177
+ ---
319
178
 
320
179
  ## LLM Integration
321
180
 
322
- dabke ships an `llms.txt` file with complete API documentation, designed for AI code generation:
181
+ dabke ships an `llms.txt` with complete API documentation for AI code generation:
323
182
 
324
183
  ```typescript
325
184
  import { apiDocs } from "dabke/llms";
326
-
327
- // Pass to your LLM as context for generating scheduling code
328
185
  ```
329
186
 
330
- Or read the file directly:
331
-
332
- ```bash
333
- cat node_modules/dabke/llms.txt
334
- ```
187
+ ---
335
188
 
336
189
  ## Development
337
190
 
338
- ### Running tests
339
-
340
- Unit tests have no external dependencies:
341
-
342
- ```bash
343
- npm run test:unit
344
- ```
345
-
346
- Integration tests require Docker to run the solver container:
191
+ Unit tests (no dependencies): `npm run test:unit`
347
192
 
348
- ```bash
349
- # Ensure Docker is running, then:
350
- npm run test:integration
351
- ```
193
+ Integration tests (requires Docker): `npm run test:integration`
352
194
 
353
- The integration test harness (`startSolverContainer`) builds and starts a Docker container from `solver/Dockerfile` automatically. It binds to port 18080 by default — make sure no other container is using that port.
354
-
355
- To run both unit and integration tests:
356
-
357
- ```bash
358
- npm test # runs typecheck + unit tests only
359
- npm run test:integration # solver integration tests (requires Docker)
360
- ```
361
-
362
- ### Test utilities
363
-
364
- dabke exports test helpers for writing your own integration tests:
195
+ The test harness builds and starts a solver container from `solver/Dockerfile` automatically.
365
196
 
366
197
  ```typescript
367
198
  import { startSolverContainer } from "dabke/testing";
368
-
369
199
  const solver = await startSolverContainer();
370
- const response = await solver.client.solve(request);
371
- solver.stop();
372
200
  ```
373
201
 
374
- This builds the solver Docker image, starts a container, waits for the health check, and returns a pre-configured `HttpSolverClient`.
375
-
376
- ## Contributing
377
-
378
- See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, how to add rules, and contribution guidelines.
202
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for how to add rules and contribute.
379
203
 
380
204
  ## License
381
205
 
package/dist/client.d.ts CHANGED
@@ -1,14 +1,32 @@
1
- import { type FetcherLike, type SolverClient, type SolverRequest, type SolverResponse } from "./client.types.js";
1
+ import { type FetcherLike, type SolverClient, type SolverRequest } from "./client.types.js";
2
2
  export type { SolverClient, SolverRequest, SolverResponse, SolverVariable, SolverConstraint, SolverTerm, SolverObjective, FetcherLike, } from "./client.types.js";
3
3
  /**
4
4
  * Generic HTTP client for the solver service.
5
+ *
6
+ * @category Solver
5
7
  */
6
8
  export declare class HttpSolverClient implements SolverClient {
7
9
  #private;
8
10
  constructor(fetcher: FetcherLike, baseUrl?: string);
9
11
  solve(request: SolverRequest, options?: {
10
12
  signal?: AbortSignal;
11
- }): Promise<SolverResponse>;
13
+ }): Promise<{
14
+ status: "OPTIMAL" | "FEASIBLE" | "INFEASIBLE" | "TIMEOUT" | "ERROR";
15
+ values?: Record<string, number> | undefined;
16
+ statistics?: {
17
+ solveTimeMs?: number | undefined;
18
+ conflicts?: number | undefined;
19
+ branches?: number | undefined;
20
+ } | undefined;
21
+ error?: string | undefined;
22
+ solutionInfo?: string | undefined;
23
+ softViolations?: {
24
+ constraintId: string;
25
+ violationAmount: number;
26
+ targetValue: number;
27
+ actualValue: number;
28
+ }[] | undefined;
29
+ }>;
12
30
  health(): Promise<void>;
13
31
  }
14
32
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAE3B,YAAY,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAS3B;;GAEG;AACH,qBAAa,gBAAiB,YAAW,YAAY;;gBAIvC,OAAO,EAAE,WAAW,EAAE,OAAO,GAAE,MAAgC;IAKrE,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAqB1F,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ9B"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAG5F,YAAY,EACV,YAAY,EACZ,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,WAAW,GACZ,MAAM,mBAAmB,CAAC;AAS3B;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,YAAY;;gBAIvC,OAAO,EAAE,WAAW,EAAE,OAAO,GAAE,MAAgC;IAKrE,KAAK,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE;;;;;;;;;;;;;;;;;IAqBhE,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAQ9B"}
package/dist/client.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { SolverResponseSchema } from "./client.schemas.js";
1
2
  const normalizeFetch = (fetcher) => {
2
3
  if (typeof fetcher === "function")
3
4
  return fetcher;
@@ -5,6 +6,8 @@ const normalizeFetch = (fetcher) => {
5
6
  };
6
7
  /**
7
8
  * Generic HTTP client for the solver service.
9
+ *
10
+ * @category Solver
8
11
  */
9
12
  export class HttpSolverClient {
10
13
  #fetch;
@@ -28,7 +31,7 @@ export class HttpSolverClient {
28
31
  if (!bodyText) {
29
32
  throw new Error("Solver returned an empty response");
30
33
  }
31
- return JSON.parse(bodyText);
34
+ return SolverResponseSchema.parse(JSON.parse(bodyText));
32
35
  }
33
36
  async health() {
34
37
  const res = await this.#fetch(`${this.#baseUrl}/health`);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAkBA,MAAM,cAAc,GAAG,CACrB,OAAoB,EAC8C,EAAE;IACpE,IAAI,OAAO,OAAO,KAAK,UAAU;QAAE,OAAO,OAAO,CAAC;IAClD,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAC3B,MAAM,CAAiE;IACvE,QAAQ,CAAS;IAEjB,YAAY,OAAoB,EAAE,UAAkB,uBAAuB;QACzE,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAsB,EAAE,OAAkC;QACpE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,QAAQ,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAmB,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,MAAM;QACV,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAa3D,MAAM,cAAc,GAAG,CACrB,OAAoB,EAC8C,EAAE;IACpE,IAAI,OAAO,OAAO,KAAK,UAAU;QAAE,OAAO,OAAO,CAAC;IAClD,OAAO,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IAC3B,MAAM,CAAiE;IACvE,QAAQ,CAAS;IAEjB,YAAY,OAAoB,EAAE,UAAkB,uBAAuB;QACzE,IAAI,CAAC,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAsB,EAAE,OAAkC;QACpE,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,QAAQ,EAAE;YACtD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,oBAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,MAAM;QACV,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,SAAS,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,mCAAmC,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;CACF"}
@@ -64,6 +64,8 @@ export type SolverResponse = z.infer<typeof SolverResponseSchema>;
64
64
  * Solver outcome status.
65
65
  *
66
66
  * One of `"OPTIMAL"`, `"FEASIBLE"`, `"INFEASIBLE"`, `"TIMEOUT"`, or `"ERROR"`.
67
+ *
68
+ * @category Solver
67
69
  */
68
70
  export type SolverStatus = z.infer<typeof SolverStatusSchema>;
69
71
  /**
@@ -73,6 +75,7 @@ export type SolverStatus = z.infer<typeof SolverStatusSchema>;
73
75
  * - `violationAmount` (required): magnitude of the violation
74
76
  */
75
77
  export type SoftConstraintViolation = z.infer<typeof SoftConstraintViolationSchema>;
78
+ /** Convenience constants for {@link SolverStatus} values. */
76
79
  export declare const SOLVER_STATUS: {
77
80
  readonly OPTIMAL: "OPTIMAL";
78
81
  readonly FEASIBLE: "FEASIBLE";
@@ -80,9 +83,15 @@ export declare const SOLVER_STATUS: {
80
83
  readonly TIMEOUT: "TIMEOUT";
81
84
  readonly ERROR: "ERROR";
82
85
  };
86
+ /** A `fetch` function or an object with a `fetch` method. */
83
87
  export type FetcherLike = typeof fetch | {
84
88
  fetch: typeof fetch;
85
89
  };
90
+ /**
91
+ * Interface for sending solver requests and receiving responses.
92
+ *
93
+ * @category Solver
94
+ */
86
95
  export interface SolverClient {
87
96
  solve(request: SolverRequest, options?: {
88
97
  signal?: AbortSignal;