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.
- package/CHANGELOG.md +41 -0
- package/README.md +126 -302
- package/dist/client.d.ts +20 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -1
- package/dist/client.js.map +1 -1
- package/dist/client.types.d.ts +9 -0
- package/dist/client.types.d.ts.map +1 -1
- package/dist/client.types.js +1 -0
- package/dist/client.types.js.map +1 -1
- package/dist/cpsat/model-builder.d.ts +9 -0
- package/dist/cpsat/model-builder.d.ts.map +1 -1
- package/dist/cpsat/model-builder.js +36 -34
- package/dist/cpsat/model-builder.js.map +1 -1
- package/dist/cpsat/response.d.ts +13 -1
- package/dist/cpsat/response.d.ts.map +1 -1
- package/dist/cpsat/response.js +4 -0
- package/dist/cpsat/response.js.map +1 -1
- package/dist/cpsat/rules/cost-utils.d.ts +11 -0
- package/dist/cpsat/rules/cost-utils.d.ts.map +1 -0
- package/dist/cpsat/rules/cost-utils.js +24 -0
- package/dist/cpsat/rules/cost-utils.js.map +1 -0
- package/dist/cpsat/rules/day-cost-multiplier.d.ts.map +1 -1
- package/dist/cpsat/rules/day-cost-multiplier.js +3 -14
- package/dist/cpsat/rules/day-cost-multiplier.js.map +1 -1
- package/dist/cpsat/rules/day-cost-surcharge.d.ts.map +1 -1
- package/dist/cpsat/rules/day-cost-surcharge.js +3 -7
- package/dist/cpsat/rules/day-cost-surcharge.js.map +1 -1
- package/dist/cpsat/rules/max-consecutive-days.d.ts.map +1 -1
- package/dist/cpsat/rules/max-consecutive-days.js +16 -2
- package/dist/cpsat/rules/max-consecutive-days.js.map +1 -1
- package/dist/cpsat/rules/max-hours-day.d.ts.map +1 -1
- package/dist/cpsat/rules/max-hours-day.js +15 -2
- package/dist/cpsat/rules/max-hours-day.js.map +1 -1
- package/dist/cpsat/rules/max-hours-week.d.ts.map +1 -1
- package/dist/cpsat/rules/max-hours-week.js +16 -2
- package/dist/cpsat/rules/max-hours-week.js.map +1 -1
- package/dist/cpsat/rules/max-shifts-day.d.ts.map +1 -1
- package/dist/cpsat/rules/max-shifts-day.js +15 -2
- package/dist/cpsat/rules/max-shifts-day.js.map +1 -1
- package/dist/cpsat/rules/min-consecutive-days.d.ts.map +1 -1
- package/dist/cpsat/rules/min-consecutive-days.js +15 -2
- package/dist/cpsat/rules/min-consecutive-days.js.map +1 -1
- package/dist/cpsat/rules/min-hours-day.d.ts.map +1 -1
- package/dist/cpsat/rules/min-hours-day.js +15 -2
- package/dist/cpsat/rules/min-hours-day.js.map +1 -1
- package/dist/cpsat/rules/min-hours-week.d.ts.map +1 -1
- package/dist/cpsat/rules/min-hours-week.js +16 -2
- package/dist/cpsat/rules/min-hours-week.js.map +1 -1
- package/dist/cpsat/rules/min-rest-between-shifts.d.ts.map +1 -1
- package/dist/cpsat/rules/min-rest-between-shifts.js +72 -2
- package/dist/cpsat/rules/min-rest-between-shifts.js.map +1 -1
- package/dist/cpsat/rules/minimize-cost.d.ts.map +1 -1
- package/dist/cpsat/rules/minimize-cost.js +2 -23
- package/dist/cpsat/rules/minimize-cost.js.map +1 -1
- package/dist/cpsat/rules/overtime-daily-multiplier.d.ts.map +1 -1
- package/dist/cpsat/rules/overtime-daily-multiplier.js +1 -12
- package/dist/cpsat/rules/overtime-daily-multiplier.js.map +1 -1
- package/dist/cpsat/rules/overtime-daily-surcharge.d.ts.map +1 -1
- package/dist/cpsat/rules/overtime-daily-surcharge.js +1 -5
- package/dist/cpsat/rules/overtime-daily-surcharge.js.map +1 -1
- package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts +5 -1
- package/dist/cpsat/rules/overtime-tiered-multiplier.d.ts.map +1 -1
- package/dist/cpsat/rules/overtime-tiered-multiplier.js +1 -12
- package/dist/cpsat/rules/overtime-tiered-multiplier.js.map +1 -1
- package/dist/cpsat/rules/overtime-weekly-multiplier.d.ts.map +1 -1
- package/dist/cpsat/rules/overtime-weekly-multiplier.js +1 -12
- package/dist/cpsat/rules/overtime-weekly-multiplier.js.map +1 -1
- package/dist/cpsat/rules/overtime-weekly-surcharge.d.ts.map +1 -1
- package/dist/cpsat/rules/overtime-weekly-surcharge.js +1 -5
- package/dist/cpsat/rules/overtime-weekly-surcharge.js.map +1 -1
- package/dist/cpsat/rules/registry.d.ts +25 -2
- package/dist/cpsat/rules/registry.d.ts.map +1 -1
- package/dist/cpsat/rules/registry.js.map +1 -1
- package/dist/cpsat/rules/resolver.js +2 -2
- package/dist/cpsat/rules/resolver.js.map +1 -1
- package/dist/cpsat/rules/scope.types.d.ts +18 -1
- package/dist/cpsat/rules/scope.types.d.ts.map +1 -1
- package/dist/cpsat/rules/scope.types.js +59 -16
- package/dist/cpsat/rules/scope.types.js.map +1 -1
- package/dist/cpsat/rules/time-cost-surcharge.d.ts.map +1 -1
- package/dist/cpsat/rules/time-cost-surcharge.js +2 -1
- package/dist/cpsat/rules/time-cost-surcharge.js.map +1 -1
- package/dist/cpsat/rules/time-off.d.ts.map +1 -1
- package/dist/cpsat/rules/time-off.js +6 -3
- package/dist/cpsat/rules/time-off.js.map +1 -1
- package/dist/cpsat/semantic-time.d.ts +44 -42
- package/dist/cpsat/semantic-time.d.ts.map +1 -1
- package/dist/cpsat/semantic-time.js +64 -46
- package/dist/cpsat/semantic-time.js.map +1 -1
- package/dist/cpsat/types.d.ts +37 -27
- package/dist/cpsat/types.d.ts.map +1 -1
- package/dist/cpsat/utils.d.ts.map +1 -1
- package/dist/cpsat/utils.js +7 -12
- package/dist/cpsat/utils.js.map +1 -1
- package/dist/cpsat/validation-reporter.d.ts +10 -7
- package/dist/cpsat/validation-reporter.d.ts.map +1 -1
- package/dist/cpsat/validation-reporter.js +44 -72
- package/dist/cpsat/validation-reporter.js.map +1 -1
- package/dist/cpsat/validation.types.d.ts +54 -44
- package/dist/cpsat/validation.types.d.ts.map +1 -1
- package/dist/cpsat/validation.types.js +15 -10
- package/dist/cpsat/validation.types.js.map +1 -1
- package/dist/datetime.utils.d.ts +3 -203
- package/dist/datetime.utils.d.ts.map +1 -1
- package/dist/datetime.utils.js +1 -288
- package/dist/datetime.utils.js.map +1 -1
- package/dist/index.d.ts +15 -86
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -86
- package/dist/index.js.map +1 -1
- package/dist/llms.d.ts +1 -1
- package/dist/llms.d.ts.map +1 -1
- package/dist/llms.js +1 -1
- package/dist/llms.js.map +1 -1
- package/dist/schedule.d.ts +437 -244
- package/dist/schedule.d.ts.map +1 -1
- package/dist/schedule.js +729 -305
- package/dist/schedule.js.map +1 -1
- package/dist/types.d.ts +14 -78
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/llms.txt +346 -513
- package/package.json +1 -1
- package/solver/src/solver/app.py +1 -1
- package/solver/src/solver/solver.py +7 -4
- package/src/client.ts +6 -8
- package/src/client.types.ts +9 -0
- package/src/cpsat/model-builder.ts +44 -35
- package/src/cpsat/response.ts +13 -1
- package/src/cpsat/rules/cost-utils.ts +25 -0
- package/src/cpsat/rules/day-cost-multiplier.ts +3 -14
- package/src/cpsat/rules/day-cost-surcharge.ts +3 -8
- package/src/cpsat/rules/max-consecutive-days.ts +17 -0
- package/src/cpsat/rules/max-hours-day.ts +21 -1
- package/src/cpsat/rules/max-hours-week.ts +22 -1
- package/src/cpsat/rules/max-shifts-day.ts +21 -1
- package/src/cpsat/rules/min-consecutive-days.ts +16 -1
- package/src/cpsat/rules/min-hours-day.ts +16 -1
- package/src/cpsat/rules/min-hours-week.ts +17 -1
- package/src/cpsat/rules/min-rest-between-shifts.ts +92 -2
- package/src/cpsat/rules/minimize-cost.ts +2 -29
- package/src/cpsat/rules/overtime-daily-multiplier.ts +1 -12
- package/src/cpsat/rules/overtime-daily-surcharge.ts +1 -6
- package/src/cpsat/rules/overtime-tiered-multiplier.ts +6 -13
- package/src/cpsat/rules/overtime-weekly-multiplier.ts +1 -12
- package/src/cpsat/rules/overtime-weekly-surcharge.ts +1 -6
- package/src/cpsat/rules/registry.ts +2 -2
- package/src/cpsat/rules/resolver.ts +2 -2
- package/src/cpsat/rules/scope.types.ts +73 -20
- package/src/cpsat/rules/time-cost-surcharge.ts +2 -1
- package/src/cpsat/rules/time-off.ts +6 -2
- package/src/cpsat/semantic-time.ts +115 -91
- package/src/cpsat/types.ts +37 -27
- package/src/cpsat/utils.ts +8 -12
- package/src/cpsat/validation-reporter.ts +51 -82
- package/src/cpsat/validation.types.ts +72 -47
- package/src/datetime.utils.ts +3 -334
- package/src/index.ts +31 -108
- package/src/llms.ts +1 -1
- package/src/schedule.ts +1008 -467
- package/src/types.ts +14 -88
- package/dist/errors.d.ts +0 -12
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -17
- package/dist/errors.js.map +0 -1
- package/dist/validation.d.ts +0 -105
- package/dist/validation.d.ts.map +0 -1
- package/dist/validation.js +0 -130
- package/dist/validation.js.map +0 -1
- package/src/errors.ts +0 -17
- 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)
|
|
5
5
|
[](https://github.com/christianklotz/dabke/actions/workflows/ci.yml)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
TypeScript scheduling library powered by constraint programming.
|
|
8
8
|
|
|
9
|
-
Define
|
|
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 {
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
113
|
+
---
|
|
204
114
|
|
|
205
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
253
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
-
|
|
278
|
-
reporter.analyzeSolution(response);
|
|
279
|
-
const results = reporter.getValidation();
|
|
280
|
-
const summaries = summarizeValidation(results);
|
|
142
|
+
---
|
|
281
143
|
|
|
282
|
-
|
|
283
|
-
console.log(
|
|
284
|
-
`${s.description}: ${s.status} (${s.passedCount}/${s.passedCount + s.violatedCount})`,
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
```
|
|
144
|
+
## Rules
|
|
288
145
|
|
|
289
|
-
|
|
146
|
+
### Scheduling
|
|
290
147
|
|
|
291
|
-
|
|
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
|
-
|
|
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
|
-
|
|
314
|
-
|
|
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
|
-
|
|
177
|
+
---
|
|
319
178
|
|
|
320
179
|
## LLM Integration
|
|
321
180
|
|
|
322
|
-
dabke ships an `llms.txt`
|
|
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
|
-
|
|
331
|
-
|
|
332
|
-
```bash
|
|
333
|
-
cat node_modules/dabke/llms.txt
|
|
334
|
-
```
|
|
187
|
+
---
|
|
335
188
|
|
|
336
189
|
## Development
|
|
337
190
|
|
|
338
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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<
|
|
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
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`);
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/client.types.d.ts
CHANGED
|
@@ -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;
|