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.
- package/CHANGELOG.md +58 -0
- package/README.md +45 -27
- 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/index.d.ts +3 -0
- package/dist/cpsat/rules/index.d.ts.map +1 -1
- package/dist/cpsat/rules/index.js +3 -0
- package/dist/cpsat/rules/index.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-days-week.d.ts +44 -0
- package/dist/cpsat/rules/max-days-week.d.ts.map +1 -0
- package/dist/cpsat/rules/max-days-week.js +95 -0
- package/dist/cpsat/rules/max-days-week.js.map +1 -0
- 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-days-week.d.ts +34 -0
- package/dist/cpsat/rules/min-days-week.d.ts.map +1 -0
- package/dist/cpsat/rules/min-days-week.js +84 -0
- package/dist/cpsat/rules/min-days-week.js.map +1 -0
- 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/must-assign.d.ts +49 -0
- package/dist/cpsat/rules/must-assign.d.ts.map +1 -0
- package/dist/cpsat/rules/must-assign.js +86 -0
- package/dist/cpsat/rules/must-assign.js.map +1 -0
- 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 +28 -2
- package/dist/cpsat/rules/registry.d.ts.map +1 -1
- package/dist/cpsat/rules/registry.js +4 -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/rules.types.d.ts +3 -0
- package/dist/cpsat/rules/rules.types.d.ts.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 +14 -83
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -83
- package/dist/index.js.map +1 -1
- package/dist/schedule/cost.d.ts +204 -0
- package/dist/schedule/cost.d.ts.map +1 -0
- package/dist/schedule/cost.js +187 -0
- package/dist/schedule/cost.js.map +1 -0
- package/dist/schedule/coverage.d.ts +85 -0
- package/dist/schedule/coverage.d.ts.map +1 -0
- package/dist/schedule/coverage.js +33 -0
- package/dist/schedule/coverage.js.map +1 -0
- package/dist/schedule/definition.d.ts +227 -0
- package/dist/schedule/definition.d.ts.map +1 -0
- package/dist/schedule/definition.js +659 -0
- package/dist/schedule/definition.js.map +1 -0
- package/dist/schedule/index.d.ts +67 -0
- package/dist/schedule/index.d.ts.map +1 -0
- package/dist/schedule/index.js +69 -0
- package/dist/schedule/index.js.map +1 -0
- package/dist/schedule/rules.d.ts +353 -0
- package/dist/schedule/rules.d.ts.map +1 -0
- package/dist/schedule/rules.js +352 -0
- package/dist/schedule/rules.js.map +1 -0
- package/dist/schedule/shift-patterns.d.ts +34 -0
- package/dist/schedule/shift-patterns.d.ts.map +1 -0
- package/dist/schedule/shift-patterns.js +41 -0
- package/dist/schedule/shift-patterns.js.map +1 -0
- package/dist/schedule/time-periods.d.ts +69 -0
- package/dist/schedule/time-periods.d.ts.map +1 -0
- package/dist/schedule/time-periods.js +91 -0
- package/dist/schedule/time-periods.js.map +1 -0
- package/dist/types.d.ts +14 -78
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +4 -9
- 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/index.ts +3 -0
- package/src/cpsat/rules/max-consecutive-days.ts +17 -0
- package/src/cpsat/rules/max-days-week.ts +143 -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-days-week.ts +120 -0
- 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/must-assign.ts +108 -0
- 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 +8 -2
- package/src/cpsat/rules/resolver.ts +2 -2
- package/src/cpsat/rules/rules.types.ts +3 -0
- 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 +35 -107
- package/src/schedule/cost.ts +242 -0
- package/src/schedule/coverage.ts +135 -0
- package/src/schedule/definition.ts +958 -0
- package/src/schedule/index.ts +112 -0
- package/src/schedule/rules.ts +529 -0
- package/src/schedule/shift-patterns.ts +46 -0
- package/src/schedule/time-periods.ts +110 -0
- 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/llms.d.ts +0 -2
- package/dist/llms.d.ts.map +0 -1
- package/dist/llms.js +0 -3
- package/dist/llms.js.map +0 -1
- package/dist/schedule.d.ts +0 -724
- package/dist/schedule.d.ts.map +0 -1
- package/dist/schedule.js +0 -899
- package/dist/schedule.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/llms.txt +0 -925
- package/src/errors.ts +0 -17
- package/src/llms.ts +0 -3
- package/src/schedule.ts +0 -1419
- package/src/validation.ts +0 -188
package/src/errors.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error thrown when Google OR Tools scheduling API requests fail.
|
|
3
|
-
*
|
|
4
|
-
* Contains the HTTP status code and raw response data from the API for debugging.
|
|
5
|
-
* Common causes include infeasible constraints, invalid requests, or API unavailability.
|
|
6
|
-
*/
|
|
7
|
-
export class ORSchedulingError extends Error {
|
|
8
|
-
public readonly status: number;
|
|
9
|
-
public readonly data: unknown;
|
|
10
|
-
|
|
11
|
-
constructor(message: string, status: number, data: unknown) {
|
|
12
|
-
super(message);
|
|
13
|
-
this.name = "ORSchedulingError";
|
|
14
|
-
this.status = status;
|
|
15
|
-
this.data = data;
|
|
16
|
-
}
|
|
17
|
-
}
|
package/src/llms.ts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
// Auto-generated — do not edit manually
|
|
2
|
-
export const apiDocs =
|
|
3
|
-
'# dabke\n\n> Scheduling library powered by constraint programming (CP-SAT)\n\nDefine teams, shifts, coverage, and rules declaratively. dabke compiles\nthem into a constraint model and solves for an optimized schedule.\n\n## Core Concepts\n\n**Schedule Definition**: The primary API. Small, composable functions\n(`time`, `cover`, `shift`, rule functions) produce a\ncomplete scheduling configuration via `defineSchedule`. Each concept\nis a single function call with full type safety.\n\n**Times vs Shift Patterns**: These are two distinct concepts.\n`times` are named time windows used to define and reference recurring\nperiods: service hours, delivery windows, peak periods, weekly events\nlike a fire drill. Times may overlap (e.g., "dinner" 18:00-22:00 and\n"happy_hour" 17:30-18:30). Coverage and rules reference these names.\n`shiftPatterns` define WHEN people CAN work (available time slots).\nThe solver assigns people to shift patterns whose hours overlap with\ntimes to satisfy coverage. Not every shift pattern needs a\ncorresponding time; create times only for periods you need to\nreference.\n\n**Rules**: Business requirements expressed as scheduling constraints.\n- Built-in rules: hours limits, time-off, rest periods, preferences, cost optimization\n- Scoping: apply rules globally, per person, per role, per skill, or per time period\n- Priority: `MANDATORY` (hard constraint) vs `LOW`/`MEDIUM`/`HIGH` (soft preferences)\n\n**Solving**: `ScheduleDefinition.createSchedulerConfig` merges the\nstatic definition with runtime data (members, scheduling period).\n`ModelBuilder` compiles the config into a solver request;\n`HttpSolverClient` sends it to the CP-SAT solver.\n\n**Example:**\nDefine a schedule\n```typescript\nimport {\ndefineSchedule, t, time, cover, shift,\nmaxHoursPerWeek, minRestBetweenShifts, timeOff,\nweekdays, weekend,\n} from "dabke";\n\nconst schedule = defineSchedule({\nroles: ["nurse", "doctor"],\nskills: ["charge_nurse"],\n\ntimes: {\nmorning_round: time({ startTime: t(7), endTime: t(9) }),\nday_ward: time({ startTime: t(7), endTime: t(15) }),\nnight_ward: time({ startTime: t(23), endTime: t(7) }),\n},\n\ncoverage: [\ncover("morning_round", "doctor", 1),\ncover("day_ward", "nurse", 3, { dayOfWeek: weekdays }),\ncover("day_ward", "nurse", 2, { dayOfWeek: weekend }),\ncover("night_ward", "nurse", 2),\ncover("night_ward", "charge_nurse", 1),\n],\n\nshiftPatterns: [\nshift("day", t(7), t(15)),\nshift("night", t(23), t(7)),\n],\n\nrules: [\nmaxHoursPerWeek(40),\nminRestBetweenShifts(11),\ntimeOff({ appliesTo: "alice", dayOfWeek: weekend }),\n],\n});\n```\n\n**Example:**\nSolve a schedule\n```typescript\nimport { ModelBuilder, HttpSolverClient, parseSolverResponse } from "dabke";\n\nconst config = schedule.createSchedulerConfig({\nschedulingPeriod: {\ndateRange: { start: "2026-02-09", end: "2026-02-15" },\n},\nmembers: [\n{ id: "alice", roles: ["nurse"], skills: ["charge_nurse"] },\n{ id: "bob", roles: ["nurse"] },\n{ id: "carol", roles: ["doctor"] },\n],\n});\n\nconst builder = new ModelBuilder(config);\nconst { request, canSolve, validation } = builder.compile();\nif (canSolve) {\nconst client = new HttpSolverClient(fetch, "http://localhost:8080");\nconst response = await client.solve(request);\nconst result = parseSolverResponse(response);\n}\n```\n\n---\n\n## Schedule Definition\n\n### `defineSchedule`\n\nDefines a complete schedule configuration.\n\nValidates the static config at call time (role/skill disjointness, coverage\ntargets, shift pattern roles). Returns a `ScheduleDefinition` whose\n`createSchedulerConfig` method validates runtime data (member IDs,\n`appliesTo` resolution) and produces a `ModelBuilderConfig`.\n\n**Example:**\n```typescript\nimport { defineSchedule, t, time, cover, shift, maxHoursPerDay } from "dabke";\n\nexport default defineSchedule({\n roles: ["agent", "supervisor"],\n times: { peak: time({ startTime: t(9), endTime: t(17) }) },\n coverage: [cover("peak", "agent", 4)],\n shiftPatterns: [shift("day", t(9), t(17))],\n rules: [maxHoursPerDay(8)],\n});\n```\n\n```ts\ndefineSchedule(config: ScheduleConfig<R, S, T>): ScheduleDefinition\n```\n\n### `ScheduleDefinition`\n\nResult of `defineSchedule`.\n\n**Properties:**\n- `createSchedulerConfig: ModelBuilderConfig` — Produce a `ModelBuilderConfig` for the solver.\n- `roles: readonly string[]` — Declared role names.\n- `skills: readonly string[]` — Declared skill names.\n- `timeNames: readonly string[]` — Names of declared semantic times.\n- `shiftPatternIds: readonly string[]` — Shift pattern IDs.\n- `ruleNames: readonly string[]` — Internal rule identifiers in kebab-case (e.g., "max-hours-day", "time-off").\n\n### `RuntimeArgs`\n\nRuntime arguments passed to `ScheduleDefinition.createSchedulerConfig`.\n\nSeparates data known at runtime (team roster, date range, ad-hoc rules)\nfrom the static schedule definition. Runtime rules are merged after the\ndefinition\'s own rules and undergo the same `appliesTo` resolution.\n\n**Properties:**\n- `schedulingPeriod: SchedulingPeriod` — The scheduling period (date range + optional filters).\n- `members: SchedulingMember[]` — Team members available for this scheduling run.\n- `runtimeRules?: RuleEntry[]` — Ad-hoc rules injected at runtime (e.g., vacation, holiday closures).\n\n---\n\n## Time Periods\n\n### `t`\n\nCreates a `TimeOfDay` value.\n\n**Example:**\nHours only\n```ts\nt(9) // { hours: 9, minutes: 0 }\n```\n\n**Example:**\nHours and minutes\n```ts\nt(17, 30) // { hours: 17, minutes: 30 }\n```\n\n**Parameters:**\n- `hours: number` — Hour component (0-23)\n- `minutes: number` — Minute component (0-59)\n\n**Returns:** `TimeOfDay`\n\n### `time`\n\nDefines a named time window.\n\nA semantic time is any recurring period you need to reference:\nservice hours, delivery windows, peak periods, weekly events. Times\nmay overlap (e.g., "dinner" 18:00-22:00 and "happy_hour"\n17:30-18:30, or "lunch" 12:00-14:00 with "peak_lunch"\n13:00-13:30). Coverage and rules reference these names; each\ngenerates independent constraints.\n\nEvery argument is a `SemanticTimeVariant` with `startTime`/`endTime`\nand optional `dayOfWeek`/`dates` scoping. An entry without scoping is the\ndefault (applies when no scoped entry matches). At most one default is\nallowed. If no default, the time only exists on the scoped days.\n\nResolution precedence: `dates` > `dayOfWeek` > default.\n\n**Example:**\nEvery day\n```typescript\nday_shift: time({ startTime: t(7), endTime: t(15) }),\n```\n\n**Example:**\nDefault with weekend variant\n```typescript\npeak_hours: time(\n{ startTime: t(9), endTime: t(17) },\n{ startTime: t(10), endTime: t(15), dayOfWeek: weekend },\n),\n```\n\n**Example:**\nNo default (specific days only)\n```typescript\nhappy_hour: time(\n{ startTime: t(16), endTime: t(18), dayOfWeek: ["monday", "tuesday"] },\n{ startTime: t(17), endTime: t(19), dayOfWeek: ["friday"] },\n),\n```\n\n```ts\ntime(entries: [SemanticTimeVariant, ...SemanticTimeVariant[]]): SemanticTimeEntry\n```\n\n### `weekdays`\n\nMonday through Friday.\n\n```typescript\nreadonly DayOfWeek[]\n```\n\n### `weekend`\n\nSaturday and Sunday.\n\n```typescript\nreadonly DayOfWeek[]\n```\n\n---\n\n## Coverage\n\n### `cover`\n\nDefines a staffing requirement for a semantic time period.\n\nTwo call forms are supported:\n\n**Simple form** `cover(time, target, count, opts?)` creates a single\nconstraint. Use `dayOfWeek`/`dates` in `opts` to restrict which days\nit applies to.\n\n**Variant form** `cover(time, target, ...variants)` accepts one or more\n`CoverageVariant` entries with day-specific counts. For each\nscheduling day, exactly one variant is selected using the same\nprecedence as `time`: `dates` > `dayOfWeek` > default (unscoped).\nAt most one variant may be unscoped (the default). Days with no matching\nvariant produce no coverage. See `CoverageVariant` for the entry\nshape.\n\n**Target resolution.** The `target` parameter is resolved against declared\n`roles` and `skills`:\n\n- Single string: matched against roles first, then skills.\n- Array of strings: OR logic (any of the listed roles).\n- With `skills` option (simple form only): role AND skill(s) filter.\n\n**Example:**\nBasic role coverage\n```ts\ncover("day_shift", "nurse", 3)\n```\n\n**Example:**\nOR logic (any of the listed roles)\n```ts\ncover("day_shift", ["manager", "team_lead"], 1)\n```\n\n**Example:**\nSkill-based coverage\n```ts\ncover("night_shift", "keyholder", 1)\n```\n\n**Example:**\nRole with skill filter (role AND skill)\n```ts\ncover("day_shift", "nurse", 1, { skills: ["charge_nurse"] })\n```\n\n**Example:**\nDay-of-week scoping (simple form)\n```ts\ncover("peak_hours", "cashier", 3, { dayOfWeek: weekdays }),\ncover("peak_hours", "cashier", 5, { dayOfWeek: weekend }),\n```\n\n**Example:**\nDefault with date override (variant form)\n```ts\ncover("peak_hours", "agent",\n{ count: 4 },\n{ count: 2, dates: ["2025-12-24"] },\n)\n```\n\n**Example:**\nWeekday vs weekend with holiday override (variant form)\n```ts\ncover("peak_hours", "agent",\n{ count: 3, dayOfWeek: weekdays },\n{ count: 5, dayOfWeek: weekend },\n{ count: 8, dates: ["2025-12-31"] },\n)\n```\n\n**Parameters:**\n- `timeName: T` — Name of a declared semantic time\n- `target: R | [R, ...R[]]` — Role name, skill name, or array of role names (OR)\n- `count: number` — Number of people needed (simple form)\n- `opts?: CoverageOptions` — See `CoverageOptions` (simple form)\n\n**Returns:** `CoverageEntry<T, R>`\n\n### `CoverageOptions`\n\nOptions for a `cover` call.\n\nDay/date scoping controls which days this coverage entry applies to.\nAn entry without `dayOfWeek` or `dates` applies every day in the\nscheduling period.\n\n**Properties:**\n- `skills?: [string, ...string[]]` — Additional skill filter (AND logic with the target role).\n- `dayOfWeek?: readonly DayOfWeek[]` — Restrict to specific days of the week.\n- `dates?: string[]` — Restrict to specific dates (YYYY-MM-DD).\n- `priority?: Priority` — Defaults to `"MANDATORY"`.\n\n### `CoverageVariant`\n\nA day-specific count within a variant `cover` call.\n\nEach variant specifies a count and optional day/date scope. During\nresolution, the most specific matching variant wins for each day\n(`dates` > `dayOfWeek` > default), mirroring `SemanticTimeVariant`.\nAt most one variant may be unscoped (the default).\n\n**Example:**\n```typescript\n// Default: 4 agents. Christmas Eve: 2.\ncover("peak_hours", "agent",\n { count: 4 },\n { count: 2, dates: ["2025-12-24"] },\n)\n```\n\n**Properties:**\n- `count: number` — Number of people needed.\n- `dayOfWeek?: readonly DayOfWeek[]` — Restrict this variant to specific days of the week.\n- `dates?: string[]` — Restrict this variant to specific dates (YYYY-MM-DD).\n- `priority?: Priority` — Defaults to `"MANDATORY"`.\n\n---\n\n## Shift Patterns\n\n### `shift`\n\nCreates a `ShiftPattern` (time slot template).\n\nShift patterns define when people can work: the concrete time slots\nthe solver may assign members to. Each pattern repeats across all\nscheduling days unless filtered by `dayOfWeek` or `roles`.\n\n**Example:**\n```typescript\nshift("early", t(6), t(14)),\nshift("day", t(9), t(17)),\nshift("night", t(22), t(6), { roles: ["nurse", "doctor"] }),\n```\n\n```ts\nshift(id: string, startTime: TimeOfDay, endTime: TimeOfDay, opts?: Pick<ShiftPattern, "roles" | "dayOfWeek" | "locationId">): ShiftPattern\n```\n\n---\n\n## Rules\n\n### `RuleOptions`\n\nScoping options shared by most rule functions.\n\nEach rule function returns an opaque `RuleEntry` for the `rules`\narray. Most accept a `RuleOptions` parameter for scoping and priority.\n\n**Entity scoping.** `appliesTo` targets a role name, skill name, or\nmember ID. It is resolved against declared roles first, then skills,\nthen runtime member IDs. The namespaces are guaranteed disjoint by\nvalidation. Unscoped rules apply to all members.\n\n**Time scoping.** `dayOfWeek`, `dateRange`, `dates`, and\n`recurringPeriods` narrow when the rule is active. Unscoped rules\napply to every day in the scheduling period.\n\n**Priority.** Defaults to `MANDATORY` (hard constraint the solver\nmust satisfy). Use `LOW`, `MEDIUM`, or `HIGH` for soft preferences\nthe solver may violate when necessary.\n\n**Properties:**\n- `appliesTo?: string | string[]` — Who this rule applies to (role name, skill name, or member ID).\n- `dayOfWeek?: readonly DayOfWeek[]` — Restrict to specific days of the week.\n- `dateRange?: { start: string; end: string }` — Restrict to a date range.\n- `dates?: string[]` — Restrict to specific dates (YYYY-MM-DD).\n- `recurringPeriods?: [RecurringPeriod, ...RecurringPeriod[]]` — Restrict to recurring calendar periods.\n- `priority?: Priority` — Defaults to `"MANDATORY"`.\n\n### `EntityOnlyRuleOptions`\n\nOptions for rules that support entity scoping only (no time scoping).\n\nUsed by rules whose semantics are inherently per-day or per-week\n(e.g., `minHoursPerDay`, `maxConsecutiveDays`) and cannot\nbe meaningfully restricted to a date range or day of week.\n\n**Properties:**\n- `appliesTo?: string | string[]` — Who this rule applies to (role name, skill name, or member ID).\n- `priority?: Priority` — Defaults to `"MANDATORY"`.\n\n### `TimeOffOptions`\n\nOptions for `timeOff`.\n\nAt least one time scoping field is required (`dayOfWeek`, `dateRange`,\n`dates`, or `recurringPeriods`). Use `from`/`until` to block only part\nof a day.\n\n**Properties:**\n- `appliesTo?: string | string[]` — Who this rule applies to (role name, skill name, or member ID).\n- `from?: TimeOfDay` — Off from this time until end of day.\n- `until?: TimeOfDay` — Off from start of day until this time.\n- `dayOfWeek?: readonly DayOfWeek[]` — Restrict to specific days of the week.\n- `dateRange?: { start: string; end: string }` — Restrict to a date range.\n- `dates?: string[]` — Restrict to specific dates (YYYY-MM-DD).\n- `recurringPeriods?: [RecurringPeriod, ...RecurringPeriod[]]` — Restrict to recurring calendar periods.\n- `priority?: Priority` — Defaults to `"MANDATORY"`.\n\n### `CostRuleOptions`\n\nOptions for cost rules.\n\nCost rules are objective terms, not constraints. The `priority` field from\n`RuleOptions` does not apply.\n\n**Properties:**\n- `appliesTo?: string | string[]` — Who this rule applies to (role name, skill name, or member ID).\n- `dayOfWeek?: DayOfWeek[]` — Restrict to specific days of the week.\n- `dateRange?: { start: string; end: string }` — Restrict to a date range.\n- `dates?: string[]` — Restrict to specific dates (YYYY-MM-DD).\n- `recurringPeriods?: [RecurringPeriod, ...RecurringPeriod[]]` — Restrict to recurring calendar periods.\n\n### `maxHoursPerDay`\n\nLimits how many hours a person can work in a single day.\n\n**Example:**\nGlobal limit\n```ts\nmaxHoursPerDay(10)\n```\n\n**Example:**\nScoped to a role\n```ts\nmaxHoursPerDay(6, { appliesTo: "student" })\n```\n\n```ts\nmaxHoursPerDay(hours: number, opts?: RuleOptions): RuleEntry\n```\n\n### `maxHoursPerWeek`\n\nCaps total hours a person can work within each scheduling week.\n\n**Example:**\nGlobal cap\n```ts\nmaxHoursPerWeek(48)\n```\n\n**Example:**\nPart-time cap for a skill group\n```ts\nmaxHoursPerWeek(20, { appliesTo: "part_time" })\n```\n\n```ts\nmaxHoursPerWeek(hours: number, opts?: RuleOptions): RuleEntry\n```\n\n### `minHoursPerDay`\n\nEnsures a person works at least a minimum number of hours per day when assigned.\n\n**Example:**\n```ts\nminHoursPerDay(4)\n```\n\n```ts\nminHoursPerDay(hours: number, opts?: EntityOnlyRuleOptions): RuleEntry\n```\n\n### `minHoursPerWeek`\n\nEnforces a minimum total number of hours per scheduling week.\n\n**Example:**\nGuaranteed minimum for full-time members\n```ts\nminHoursPerWeek(30, { appliesTo: "full_time" })\n```\n\n```ts\nminHoursPerWeek(hours: number, opts?: EntityOnlyRuleOptions): RuleEntry\n```\n\n### `maxShiftsPerDay`\n\nLimits how many shifts a person can work in a single day.\n\n**Example:**\nOne shift per day\n```ts\nmaxShiftsPerDay(1)\n```\n\n```ts\nmaxShiftsPerDay(shifts: number, opts?: RuleOptions): RuleEntry\n```\n\n### `maxConsecutiveDays`\n\nLimits how many consecutive days a person can be assigned.\n\n**Example:**\nFive-day work week limit\n```ts\nmaxConsecutiveDays(5)\n```\n\n```ts\nmaxConsecutiveDays(days: number, opts?: EntityOnlyRuleOptions): RuleEntry\n```\n\n### `minConsecutiveDays`\n\nRequires a minimum stretch of consecutive working days once assigned.\n\n**Example:**\n```ts\nminConsecutiveDays(2)\n```\n\n```ts\nminConsecutiveDays(days: number, opts?: EntityOnlyRuleOptions): RuleEntry\n```\n\n### `minRestBetweenShifts`\n\nEnforces a minimum rest period between any two shifts a person works.\n\n**Example:**\nEU Working Time Directive (11 hours)\n```ts\nminRestBetweenShifts(11)\n```\n\n```ts\nminRestBetweenShifts(hours: number, opts?: EntityOnlyRuleOptions): RuleEntry\n```\n\n### `preference`\n\nAdds objective weight to prefer or avoid assigning team members.\n\n**Example:**\nPrefer assigning full-time staff\n```ts\npreference("high", { appliesTo: "full_time" })\n```\n\n**Example:**\nAvoid assigning a specific member on weekends\n```ts\npreference("low", { appliesTo: "alice", dayOfWeek: weekend })\n```\n\n**Parameters:**\n- `level: "high" | "low"` — `"high"` to prefer assigning, `"low"` to avoid\n- `opts?: Omit<RuleOptions, "priority">` — Entity and time scoping (no priority; preference is the priority mechanism)\n\n**Returns:** `RuleEntry`\n\n### `preferLocation`\n\nPrefers assigning a person to shift patterns at a specific location.\n\n**Example:**\n```ts\npreferLocation("north_wing", { appliesTo: "alice" })\n```\n\n```ts\npreferLocation(locationId: string, opts?: EntityOnlyRuleOptions): RuleEntry\n```\n\n### `timeOff`\n\nBlocks or penalizes assignments during specified time periods.\n\nAt least one time scoping field is required (`dayOfWeek`, `dateRange`,\n`dates`, or `recurringPeriods`).\n\nUse `from` for "off from this time until end of day" and `until` for\n"off from start of day until this time."\n\n**Example:**\n```typescript\ntimeOff({ appliesTo: "mauro", dayOfWeek: weekend }),\ntimeOff({ appliesTo: "student", dayOfWeek: ["wednesday"], from: t(14) }),\ntimeOff({ appliesTo: "alice", dateRange: { start: "2024-02-01", end: "2024-02-05" } }),\n```\n\n```ts\ntimeOff(opts: TimeOffOptions): RuleEntry\n```\n\n### `assignTogether`\n\nEncourages or enforces that team members work the same shifts on a day.\n\n**Example:**\n```typescript\nassignTogether(["alice", "bob"], { priority: "HIGH" }),\n```\n\n```ts\nassignTogether(members: [string, string, ...string[]], opts?: AssignTogetherOptions): RuleEntry\n```\n\n### `minimizeCost`\n\nTells the solver to minimize total labor cost.\n\nWithout this rule, cost modifiers only affect post-solve calculation.\nWhen present, the solver actively prefers cheaper assignments.\n\nFor hourly members, penalizes each assignment proportionally to cost.\nFor salaried members, adds a fixed weekly salary cost when they have\nany assignment that week (zero marginal cost up to contracted hours).\n\n**Example:**\n```ts\nminimizeCost()\n```\n\n```ts\nminimizeCost(opts?: CostRuleOptions): RuleEntry\n```\n\n### `dayMultiplier`\n\nMultiplies the base rate for assignments on specified days.\n\nThe base cost (1x) is already counted by `minimizeCost`;\nthis rule adds only the extra portion above 1x.\n\n**Example:**\nWeekend multiplier\n```typescript\ndayMultiplier(1.5, { dayOfWeek: weekend })\n```\n\n```ts\ndayMultiplier(factor: number, opts?: CostRuleOptions): RuleEntry\n```\n\n### `daySurcharge`\n\nAdds a flat extra amount per hour for assignments on specified days.\n\nThe surcharge is independent of the member\'s base rate.\n\n**Example:**\nWeekend surcharge\n```typescript\ndaySurcharge(500, { dayOfWeek: weekend })\n```\n\n```ts\ndaySurcharge(amountPerHour: number, opts?: CostRuleOptions): RuleEntry\n```\n\n### `timeSurcharge`\n\nAdds a flat surcharge per hour for the portion of a shift that overlaps a time-of-day window.\n\nThe window supports overnight spans (e.g., 22:00-06:00). The surcharge\nis independent of the member\'s base rate.\n\n**Example:**\nNight differential\n```typescript\ntimeSurcharge(200, { from: t(22), until: t(6) })\n```\n\n**Parameters:**\n- `amountPerHour: number` — Flat surcharge per hour in smallest currency unit\n- `window: { from: TimeOfDay; until: TimeOfDay }` — Time-of-day window\n- `opts?: CostRuleOptions` — Entity and time scoping\n\n**Returns:** `RuleEntry`\n\n### `overtimeMultiplier`\n\nApplies a multiplier to hours beyond a weekly threshold.\n\nOnly the extra portion above 1x is added (the base cost is already\ncounted by `minimizeCost`).\n\n**Example:**\n```typescript\novertimeMultiplier({ after: 40, factor: 1.5 })\n```\n\n```ts\novertimeMultiplier(opts: { after: number; factor: number } & CostRuleOptions): RuleEntry\n```\n\n### `overtimeSurcharge`\n\nAdds a flat surcharge per hour beyond a weekly threshold.\n\nThe surcharge is independent of the member\'s base rate.\n\n**Example:**\n```typescript\novertimeSurcharge({ after: 40, amount: 1000 })\n```\n\n```ts\novertimeSurcharge(opts: { after: number; amount: number } & CostRuleOptions): RuleEntry\n```\n\n### `dailyOvertimeMultiplier`\n\nApplies a multiplier to hours beyond a daily threshold.\n\nOnly the extra portion above 1x is added (the base cost is already\ncounted by `minimizeCost`).\n\n**Example:**\n```typescript\ndailyOvertimeMultiplier({ after: 8, factor: 1.5 })\n```\n\n```ts\ndailyOvertimeMultiplier(opts: { after: number; factor: number } & CostRuleOptions): RuleEntry\n```\n\n### `dailyOvertimeSurcharge`\n\nAdds a flat surcharge per hour beyond a daily threshold.\n\nThe surcharge is independent of the member\'s base rate.\n\n**Example:**\n```typescript\ndailyOvertimeSurcharge({ after: 8, amount: 500 })\n```\n\n```ts\ndailyOvertimeSurcharge(opts: { after: number; amount: number } & CostRuleOptions): RuleEntry\n```\n\n### `tieredOvertimeMultiplier`\n\nApplies multiple overtime thresholds with increasing multipliers.\n\nEach tier applies only to the hours between its threshold and the next.\nTiers must be sorted by threshold ascending.\n\n**Example:**\n```typescript\n// Hours 0-40: base rate\n// Hours 40-48: 1.5x\n// Hours 48+: 2.0x\ntieredOvertimeMultiplier([\n { after: 40, factor: 1.5 },\n { after: 48, factor: 2.0 },\n])\n```\n\n```ts\ntieredOvertimeMultiplier(tiers: [OvertimeTier, ...OvertimeTier[]], opts?: CostRuleOptions): RuleEntry\n```\n\n---\n\n## Supporting Types\n\n### `TimeOfDay`\n\nTime of day representation (hours and minutes, with optional seconds/nanos).\n\nUsed for defining shift start/end times and semantic time boundaries.\nHours are in 24-hour format (0-23).\n\n**Example:**\n```typescript\n{ hours: 9, minutes: 0 }\n{ hours: 17, minutes: 30 }\n```\n\n**Properties:**\n- `hours: number`\n- `minutes: number`\n- `seconds?: number`\n- `nanos?: number`\n\n### `DayOfWeek`\n\nDay of the week identifier.\n\n```typescript\n"monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"\n```\n\n### `SchedulingPeriod`\n\nDefines a scheduling period as a date range with optional filters.\n\nThe `dateRange` specifies the overall scheduling window. Use `dayOfWeek`\nand/or `dates` to narrow which days within the range are included.\nFilters compose: a day must pass all specified filters to be included.\n\n**Example:**\nAll days in a week\n```typescript\nconst period: SchedulingPeriod = {\ndateRange: { start: \'2025-02-03\', end: \'2025-02-09\' },\n};\n```\n\n**Example:**\nOnly specific days of the week (closed Mon/Tue)\n```typescript\nconst period: SchedulingPeriod = {\ndateRange: { start: \'2025-02-03\', end: \'2025-02-09\' },\ndayOfWeek: [\'wednesday\', \'thursday\', \'friday\', \'saturday\', \'sunday\'],\n};\n```\n\n**Properties:**\n- `dateRange: { start: string; end: string }` — The overall scheduling window (start and end are inclusive).\nDates should be in YYYY-MM-DD format.\n- `dayOfWeek?: DayOfWeek[]` — Include only these days of the week.\nIf omitted, all days of the week are included.\n- `dates?: string[]` — Include only these specific dates (YYYY-MM-DD) within the range.\nIf omitted, all dates in the range are included (subject to dayOfWeek filter).\n\n### `SchedulingMember`\n\nA team member available for scheduling.\n\nMembers are assigned to shift patterns by the solver based on\ncoverage requirements, rules, and constraints.\n\n**Properties:**\n- `id: string` — Unique identifier for this member. Must not contain colons.\n- `roles: string[]` — Roles this member can fill (e.g. "nurse", "doctor").\n- `skills?: string[]` — Skills this member has (e.g. "charge_nurse", "forklift").\n- `pay?: HourlyPay | SalariedPay` — Base pay. Required when cost rules are used.\n\n### `HourlyPay`\n\nPay per hour in the caller\'s smallest currency unit (e.g., pence, cents).\n\n**Properties:**\n- `hourlyRate: number` — Pay per hour in smallest currency unit.\n\n### `SalariedPay`\n\nAnnual salary with contracted weekly hours.\n\nThe solver treats salaried members as having a fixed weekly cost\n(`annual / 52`) that is incurred once they work any shift in a week.\nAdditional shifts within the same week have zero marginal cost.\n\nNote: overtime multiplier rules apply only to hourly members.\nOvertime surcharge rules apply to all members regardless of pay type.\n\n**Properties:**\n- `annual: number` — Annual salary in smallest currency unit.\n- `hoursPerWeek: number` — Contracted hours per week. Reserved for future overtime support.\n\n### `Priority`\n\nHow strictly the solver enforces a rule.\n\n- `"LOW"`, `"MEDIUM"`, `"HIGH"`: soft constraints with increasing penalty for violations\n- `"MANDATORY"`: hard constraint; the solver will not produce a solution that violates it\n\n```typescript\n"LOW" | "MEDIUM" | "HIGH" | "MANDATORY"\n```\n\n';
|