@procedures/schedule 0.0.0-stage → 0.3.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 (75) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/LICENSE +21 -0
  3. package/README.md +98 -2
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/cron.d.ts +47 -0
  6. package/dist/cron.d.ts.map +1 -0
  7. package/dist/cron.js +197 -0
  8. package/dist/cron.js.map +1 -0
  9. package/dist/errors.d.ts +22 -0
  10. package/dist/errors.d.ts.map +1 -0
  11. package/dist/errors.js +13 -0
  12. package/dist/errors.js.map +1 -0
  13. package/dist/index.d.ts +9 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +11 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/module.d.ts +42 -0
  18. package/dist/module.d.ts.map +1 -0
  19. package/dist/module.js +174 -0
  20. package/dist/module.js.map +1 -0
  21. package/dist/procedures/schedule/add.d.ts +17 -0
  22. package/dist/procedures/schedule/add.d.ts.map +1 -0
  23. package/dist/procedures/schedule/add.js +66 -0
  24. package/dist/procedures/schedule/add.js.map +1 -0
  25. package/dist/procedures/schedule/index.d.ts +5 -0
  26. package/dist/procedures/schedule/index.d.ts.map +1 -0
  27. package/dist/procedures/schedule/index.js +5 -0
  28. package/dist/procedures/schedule/index.js.map +1 -0
  29. package/dist/procedures/schedule/list.d.ts +12 -0
  30. package/dist/procedures/schedule/list.d.ts.map +1 -0
  31. package/dist/procedures/schedule/list.js +18 -0
  32. package/dist/procedures/schedule/list.js.map +1 -0
  33. package/dist/procedures/schedule/next.d.ts +13 -0
  34. package/dist/procedures/schedule/next.d.ts.map +1 -0
  35. package/dist/procedures/schedule/next.js +24 -0
  36. package/dist/procedures/schedule/next.js.map +1 -0
  37. package/dist/procedures/schedule/remove.d.ts +12 -0
  38. package/dist/procedures/schedule/remove.d.ts.map +1 -0
  39. package/dist/procedures/schedule/remove.js +13 -0
  40. package/dist/procedures/schedule/remove.js.map +1 -0
  41. package/dist/programs.d.ts +26 -0
  42. package/dist/programs.d.ts.map +1 -0
  43. package/dist/programs.js +34 -0
  44. package/dist/programs.js.map +1 -0
  45. package/dist/register.d.ts +6 -0
  46. package/dist/register.d.ts.map +1 -0
  47. package/dist/register.js +8 -0
  48. package/dist/register.js.map +1 -0
  49. package/dist/scheduler.d.ts +106 -0
  50. package/dist/scheduler.d.ts.map +1 -0
  51. package/dist/scheduler.js +274 -0
  52. package/dist/scheduler.js.map +1 -0
  53. package/dist/store.d.ts +62 -0
  54. package/dist/store.d.ts.map +1 -0
  55. package/dist/store.js +188 -0
  56. package/dist/store.js.map +1 -0
  57. package/dist/types.d.ts +100 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +8 -0
  60. package/dist/types.js.map +1 -0
  61. package/package.json +78 -3
  62. package/src/cron.ts +230 -0
  63. package/src/errors.ts +27 -0
  64. package/src/index.ts +10 -0
  65. package/src/module.ts +227 -0
  66. package/src/procedures/schedule/add.ts +66 -0
  67. package/src/procedures/schedule/index.ts +4 -0
  68. package/src/procedures/schedule/list.ts +20 -0
  69. package/src/procedures/schedule/next.ts +25 -0
  70. package/src/procedures/schedule/remove.ts +15 -0
  71. package/src/programs.ts +43 -0
  72. package/src/register.ts +10 -0
  73. package/src/scheduler.ts +331 -0
  74. package/src/store.ts +213 -0
  75. package/src/types.ts +122 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,48 @@
1
+ # @procedures/schedule
2
+
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c56dce3: The new package `@procedures/schedule` (roadmap R46) is a cron for stored programs. It has four procedures: `schedule.add` (a cron expression, the key of a stored program and its input), `schedule.list`, `schedule.remove` and `schedule.next` (the next times of an expression, with no store). A schedule starts only a stored program: a procedure of `procedure.define`, or a program of the program store of the registry.
8
+
9
+ A host starts a `Scheduler` with its registry, its store and its policy. At each minute, the scheduler starts each schedule whose time came, through the registry, with the capability of the host narrowed by the capability of the caller that added the schedule. A schedule has at most one run at a time: a time during a run counts as skipped. The store records the last run and its outcome. A run that passes `runTimeoutMs` gets an abort and the outcome `TIMEOUT`. The scheduler does not start the times that it missed while it was stopped. The timers use an injectable `Clock`.
10
+
11
+ The package parses cron itself: 5 fields, ranges, steps, lists, the names of the months and of the days, `@daily` and the other names, in UTC or in local time. The schedules persist in a `ScheduleStore`: `MemoryScheduleStore` (the default) or `FileScheduleStore`.
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies [ddea529]
16
+ - Updated dependencies [b2a3e3a]
17
+ - Updated dependencies [a8c47f1]
18
+ - Updated dependencies [381ce3a]
19
+ - Updated dependencies [0c627f8]
20
+ - Updated dependencies [ae7f05f]
21
+ - Updated dependencies [7873940]
22
+ - Updated dependencies [a70d445]
23
+ - Updated dependencies [bc70357]
24
+ - Updated dependencies [07cc998]
25
+ - Updated dependencies [a6b01a9]
26
+ - Updated dependencies [c799cdd]
27
+ - Updated dependencies [540f8d9]
28
+ - Updated dependencies [b6daaec]
29
+ - Updated dependencies [5b9264e]
30
+ - Updated dependencies [956e88b]
31
+ - Updated dependencies [ff62281]
32
+ - Updated dependencies [d81d0ed]
33
+ - Updated dependencies [aa67cc7]
34
+ - Updated dependencies [061fa22]
35
+ - Updated dependencies [cfb9d69]
36
+ - Updated dependencies [43f7de5]
37
+ - Updated dependencies [b07bb50]
38
+ - Updated dependencies [4ef0d44]
39
+ - Updated dependencies [4a3bfa1]
40
+ - Updated dependencies [bd0b626]
41
+ - Updated dependencies [a6be873]
42
+ - Updated dependencies [fb30718]
43
+ - Updated dependencies [c5528e4]
44
+ - Updated dependencies [fee5d9c]
45
+ - Updated dependencies [21f7743]
46
+ - Updated dependencies [31a0b46]
47
+ - @procedures/client@0.3.0
48
+ - @procedures/store@0.3.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 Mark Russell
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,99 @@
1
- # Temporary Holding Version
1
+ # @procedures/schedule
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm](https://img.shields.io/npm/v/@procedures/schedule?color=2346c4&label=npm)](https://www.npmjs.com/package/@procedures/schedule)
4
+
5
+ ```sh
6
+ npm install @procedures/schedule
7
+ ```
8
+
9
+ A cron for stored programs. The procedures add, list and remove schedules. A `Scheduler` that the host starts gives each stored program its runs.
10
+
11
+ ## The procedures
12
+
13
+ | Procedure | What it does | Effects |
14
+ |---|---|---|
15
+ | `schedule.add` | It adds a schedule: a cron expression, the key of a stored program, and the input of the program. | reads `fs`, `programs`, `registry`, `schedules`, writes `fs`, `schedules` |
16
+ | `schedule.list` | It gives the schedules, sorted, with the next time, the last run and the counts of each. | reads `fs`, `schedules` |
17
+ | `schedule.remove` | It removes a schedule. | reads and writes `fs`, `schedules` |
18
+ | `schedule.next` | It gives the next times of a cron expression. | none |
19
+
20
+ - `schedule.add` examines the expression and the program. The program is a procedure that `procedure.define` made, or a program of the program store of the registry. A procedure of code is not a program, so a schedule cannot start `shell.run` directly.
21
+ - The name of a schedule (`id`) is the key of the program by default. A second schedule of a name is an error, unless the input has `replace: true`.
22
+ - `schedule.next` reads no store. Its output comes from its input and the time.
23
+ - A store can be a file, so the procedures that read or write the schedules declare `fs` too.
24
+
25
+ ```ts
26
+ await client.call(["schedule", "add"], { cron: "0 9 * * mon-fri", program: "reports.daily", input: { team: "core" } });
27
+ await client.call(["schedule", "next"], { cron: "*/15 * * * *", count: 3 });
28
+ ```
29
+
30
+ ## The scheduler
31
+
32
+ A host makes one store, gives it to the module of the procedures and to its `Scheduler`, and starts the scheduler:
33
+
34
+ ```ts
35
+ import { createRegistry, hostPolicy } from "@procedures/client";
36
+ import { storeModule } from "@procedures/store";
37
+ import { createScheduleModule, FileScheduleStore, Scheduler } from "@procedures/schedule";
38
+
39
+ const store = new FileScheduleStore("schedules.json");
40
+ const registry = createRegistry(createScheduleModule({ store }), storeModule);
41
+ const scheduler = new Scheduler({ registry, store, policy: hostPolicy({ capability, expose: ["reports.*", "http.*"] }) });
42
+ await scheduler.start();
43
+ ```
44
+
45
+ - The scheduler wakes at each minute, reads the schedules, and starts each schedule whose time came. A schedule that a procedure adds or removes counts at the next minute.
46
+ - A run goes through the registry with the capability of the host. The scheduler narrows it with the capability of the caller that added the schedule, so a caller cannot start more than it can do.
47
+ - The expose rule, the call rule, the interceptors, the clearance order and the resources of the policy apply to the calls of the program.
48
+ - When the registry does not have the program, the scheduler loads it from the program store of the registry with `procedure.load`, then starts it.
49
+ - A schedule has at most one run at a time. A time that comes during a run starts no second run, and the store counts it in `skipped`.
50
+ - The store records the last run of each schedule: its start, its time, its outcome and its error. It also counts the runs and the failures.
51
+ - A run that passes `runTimeoutMs` (default 10 minutes) gets the abort of its signal and the outcome `TIMEOUT`. The schedule stays busy until the handler ends.
52
+ - The scheduler does not start the times that it missed while it was stopped. A late or blocked minute gives one run, not one run for each time that passed.
53
+ - `stop()` stops the timer, aborts the runs and gives the end of the runs. `runNow(id)` starts one run at once. `settled()` gives the end of the examination and of the runs.
54
+
55
+ | Option | Meaning |
56
+ |---|---|
57
+ | `registry` | The registry of the programs. The default is the global registry. |
58
+ | `store` | The store of the schedules. The default is `defaultScheduleStore`, in memory. |
59
+ | `capability` | The capability of the host for each run. The default is the capability of `policy`. |
60
+ | `policy` | The policy of the host, from `hostPolicy()`. |
61
+ | `clock` | The clock of the timers and of the durations. The default is `realClock`. |
62
+ | `now` | The wall time in milliseconds. The default is `Date.now`. |
63
+ | `runTimeoutMs` | The time limit of a run. 0 sets no limit. |
64
+ | `onRun`, `onError` | Functions that get each run and each error of the scheduler. |
65
+
66
+ A test gives `fakeClock` of `@mark1russell7/service/testing`, and a wall time from it: `now: () => start + clock.now()`. It gives the same `now` to `createScheduleModule()`.
67
+
68
+ ## The stores
69
+
70
+ - `MemoryScheduleStore` keeps the schedules while the process runs. The default module uses `defaultScheduleStore`, one store in memory for the process.
71
+ - `FileScheduleStore` keeps them in a JSON file. A write goes through a temporary file and a rename. The store is for one process.
72
+ - `update()` changes one schedule in one step. The record of a run thus does not lose a change of `schedule.add`, and it does not touch a schedule that replaced the old one.
73
+
74
+ ## Cron expressions
75
+
76
+ This package parses cron itself. The format is small, and a cron library brings a time zone database or another format that this package does not need.
77
+
78
+ | Field | Values |
79
+ |---|---|
80
+ | Minute | 0-59 |
81
+ | Hour | 0-23 |
82
+ | Day of the month | 1-31 |
83
+ | Month | 1-12, or `jan` to `dec` |
84
+ | Day of the week | 0-7 (0 and 7 are Sunday), or `sun` to `sat` |
85
+
86
+ - Each field takes `*`, a number, a range `a-b`, a step after `/` (`*/15`, `a-b/n`, `a/n`), and lists of these with commas.
87
+ - The names `@yearly`, `@annually`, `@monthly`, `@weekly`, `@daily`, `@midnight` and `@hourly` replace the 5 fields.
88
+ - When the two day fields have a limit, a day matches when one of the two matches, as in Vixie cron. A field that starts with `*` has no limit.
89
+ - The time zone is `local` (the time of the host) by default, or `utc`.
90
+ - In local time, a time that the change to summer time skips gives no run. A time that the change back repeats can give two runs.
91
+ - An expression without a time in the next 9 years is an error of `schedule.add`.
92
+
93
+ ## MCP
94
+
95
+ `schedule.next` and `schedule.list` change nothing, and they are good tools. `schedule.add` makes the host start a program later, at each time, so a host gives it to Claude only on purpose. `schedule.remove` stops the runs that the owner wants.
96
+
97
+ ## Tests
98
+
99
+ `pnpm --filter @procedures/schedule test` examines the procedures, the stores and the cron expressions. The tests of the scheduler use `fakeClock`, so each time is exact and no test waits.