bareloop 0.42.0 → 0.43.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 (43) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/bareloop.context.md +53 -30
  3. package/package.json +1 -1
  4. package/src/authorjob.js +6 -0
  5. package/src/declaredclose.js +2 -2
  6. package/src/interviewrun.js +0 -1
  7. package/src/job.js +38 -11
  8. package/src/panel/authorroutes.js +107 -33
  9. package/src/panel/authorsession.js +59 -27
  10. package/src/panel/index.html +813 -484
  11. package/src/panel/runroutes.js +163 -5
  12. package/src/panel/scheduler.js +156 -0
  13. package/src/panel/schedules.js +667 -0
  14. package/src/panel/schedulestart.js +243 -0
  15. package/src/panel/server.js +451 -48
  16. package/src/planrun.js +39 -7
  17. package/src/providerrows.js +3 -3
  18. package/src/reviewdoor.js +37 -0
  19. package/src/runlist.js +35 -0
  20. package/src/schedulewords.js +296 -0
  21. package/src/trigger.js +48 -0
  22. package/src/triggerclock.js +127 -0
  23. package/src/triggerfiles.js +215 -0
  24. package/src/triggerledger.js +79 -0
  25. package/src/userrun.js +6 -7
  26. package/types/declaredclose.d.ts +1 -1
  27. package/types/job.d.ts +8 -1
  28. package/types/panel/authorroutes.d.ts +34 -1
  29. package/types/panel/authorsession.d.ts +37 -12
  30. package/types/panel/runroutes.d.ts +32 -1
  31. package/types/panel/scheduler.d.ts +17 -0
  32. package/types/panel/schedules.d.ts +412 -0
  33. package/types/panel/schedulestart.d.ts +106 -0
  34. package/types/panel/server.d.ts +143 -14
  35. package/types/planrun.d.ts +2 -0
  36. package/types/providerrows.d.ts +2 -2
  37. package/types/reviewdoor.d.ts +27 -0
  38. package/types/runlist.d.ts +20 -0
  39. package/types/schedulewords.d.ts +135 -0
  40. package/types/trigger.d.ts +37 -0
  41. package/types/triggerclock.d.ts +52 -0
  42. package/types/triggerfiles.d.ts +93 -0
  43. package/types/triggerledger.d.ts +35 -0
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The only way a clock schedule enters the system. Refuses anything else, naming the field.
3
+ * @param {unknown} s
4
+ * @returns {Schedule}
5
+ */
6
+ export function validateSchedule(s: unknown): Schedule;
7
+ /**
8
+ * Is a run due at `now`? Slots missed (panel off) collapse to ONE fire, for the latest slot, marked catch-up.
9
+ * Catch-up = more than one slot was missed, or the latest slot is more than GRACE_MS old.
10
+ * @param {Schedule} schedule
11
+ * @param {ClockRow[]} rows
12
+ * @param {number} now epoch ms
13
+ * @returns {Due}
14
+ */
15
+ export function due(schedule: Schedule, rows: ClockRow[], now: number): Due;
16
+ /**
17
+ * The next slot time strictly after `afterMs` (epoch ms). Words are the caller's (schedulewords.js).
18
+ * @param {Schedule} schedule
19
+ * @param {number} afterMs
20
+ * @returns {number}
21
+ */
22
+ export function nextSlot(schedule: Schedule, afterMs: number): number;
23
+ /** The trigger was set at `now` under signature `sig`: no slot before this ever fires. @param {string} file @param {number} now @param {string} sig */
24
+ export function armTrigger(file: string, now: number, sig: string): void;
25
+ /**
26
+ * Record that the run for this due slot is starting (the consuming row). Write-once per slot.
27
+ * @param {string} file @param {Due} d the result of `due` with fire true @param {number} now @param {string} sig
28
+ */
29
+ export function recordFire(file: string, d: Due, now: number, sig: string): void;
30
+ /** @typedef {{kind:'daily'|'weekdays', hour:number, minute:number} | {kind:'weekly', day:string, hour:number, minute:number}} Schedule */
31
+ /** @typedef {import('./triggerledger.js').LedgerRow} ClockRow */
32
+ /** @typedef {{fire:boolean, catchUp:boolean, missed:number, slot?:number}} Due */
33
+ /** A slot seen MORE than this after its set time is a catch-up. Exactly this late is on time. */
34
+ export const GRACE_MS: 120000;
35
+ export const DAYS: string[];
36
+ export type Schedule = {
37
+ kind: "daily" | "weekdays";
38
+ hour: number;
39
+ minute: number;
40
+ } | {
41
+ kind: "weekly";
42
+ day: string;
43
+ hour: number;
44
+ minute: number;
45
+ };
46
+ export type ClockRow = import("./triggerledger.js").LedgerRow;
47
+ export type Due = {
48
+ fire: boolean;
49
+ catchUp: boolean;
50
+ missed: number;
51
+ slot?: number;
52
+ };
@@ -0,0 +1,93 @@
1
+ /** The file-kind rows of the job's ledger that still count (a released `ran` does not). @param {string} file @returns {SeenRow[]} */
2
+ export function readSeen(file: string): SeenRow[];
3
+ /** Arrived rows are never overwritten: the 2nd arrival of a sha (after a drop) gets its own id. @param {string} ledger @param {ToRun & {name?:string}} item @param {number} at the scheduler's clock, never the file's mtime @param {string} sig */
4
+ export function recordArrived(ledger: string, item: ToRun & {
5
+ name?: string;
6
+ }, at: number, sig: string): boolean;
7
+ /** `of` = the arrived row it cancels (item.id when a queue row is passed). @param {string} ledger @param {{sha:string, path:string, size:number, id?:string}} item @param {string} why a plain reason: deleted, changed, schedule-changed, schedule-cancelled @param {number} at @param {string} sig */
8
+ export function recordDropped(ledger: string, item: {
9
+ sha: string;
10
+ path: string;
11
+ size: number;
12
+ id?: string;
13
+ }, why: string, at: number, sig: string): boolean;
14
+ /**
15
+ * The queue: arrived and neither ran nor dropped, oldest arrival first. Identical arrival times: by name, then by sha (deterministic).
16
+ * @param {SeenRow[]} rows @returns {(SeenRow & {path:string})[]}
17
+ */
18
+ export function queueOf(rows: SeenRow[]): (SeenRow & {
19
+ path: string;
20
+ })[];
21
+ /**
22
+ * At a queued file's turn, look at it again, at use time: lstat (no symlink, a regular file), realpath of its folder, re-hash.
23
+ * @param {{path:string, sha:string}} item
24
+ * @returns {{state:'ok', path:string, sha:string, size:number} | {state:'deleted', say:string} | {state:'changed', sha:string}}
25
+ */
26
+ export function recheck(item: {
27
+ path: string;
28
+ sha: string;
29
+ }): {
30
+ state: "ok";
31
+ path: string;
32
+ sha: string;
33
+ size: number;
34
+ } | {
35
+ state: "deleted";
36
+ say: string;
37
+ } | {
38
+ state: "changed";
39
+ sha: string;
40
+ };
41
+ /**
42
+ * The target is usable NOW, or an Error naming why: a file that is not a symlink and not something else (a file that does not exist yet
43
+ * is allowed: it may arrive), a folder that exists, resolved with realpathSync. The one rule `arm` and a door's set-time check share.
44
+ * @param {'new'|'updated'} mode @param {string} target
45
+ */
46
+ export function checkTarget(mode: "new" | "updated", target: string): void;
47
+ /**
48
+ * @param {{mode:'new'|'updated', target:string, ledger:string, sig:string, now?:() => number}} opts target = folder (new) or file (updated)
49
+ */
50
+ export function createFileTrigger({ mode, target, ledger, sig, now }: {
51
+ mode: "new" | "updated";
52
+ target: string;
53
+ ledger: string;
54
+ sig: string;
55
+ now?: () => number;
56
+ }): {
57
+ arm: () => void;
58
+ poll: () => {
59
+ arrived: ToRun[];
60
+ refused: Refused[];
61
+ };
62
+ };
63
+ /** @typedef {{id:string, kind:'baseline'|'arrived'|'ran'|'dropped', sha:string, name:string, size:number, at:number, sig?:string, path?:string, why?:string, of?:string}} SeenRow */
64
+ /** @typedef {{path:string, sha:string, size:number}} ToRun */
65
+ /** @typedef {{path:string, why:string}} Refused */
66
+ /** Consecutive polls with the same size and mtime before a file is taken. (Two matches in a row = taken on the third sighting.) */
67
+ export const STABLE_POLLS: 2;
68
+ export function recordRan(ledger: string, item: {
69
+ sha: string;
70
+ path: string;
71
+ size: number;
72
+ }, at: number, sig: string): boolean;
73
+ export type SeenRow = {
74
+ id: string;
75
+ kind: "baseline" | "arrived" | "ran" | "dropped";
76
+ sha: string;
77
+ name: string;
78
+ size: number;
79
+ at: number;
80
+ sig?: string;
81
+ path?: string;
82
+ why?: string;
83
+ of?: string;
84
+ };
85
+ export type ToRun = {
86
+ path: string;
87
+ sha: string;
88
+ size: number;
89
+ };
90
+ export type Refused = {
91
+ path: string;
92
+ why: string;
93
+ };
@@ -0,0 +1,35 @@
1
+ /** @typedef {{id?: string, kind: string, sig?: string, at?: number, [k: string]: unknown}} LedgerRow */
2
+ /**
3
+ * Every row that parses, oldest first, and how many lines did not. A missing file is no rows.
4
+ * @param {string} file
5
+ * @returns {{rows: LedgerRow[], skipped: number}}
6
+ */
7
+ export function readLedger(file: string): {
8
+ rows: LedgerRow[];
9
+ skipped: number;
10
+ };
11
+ /**
12
+ * Append one row (dir 0700, file 0600). A torn tail gets a newline first. `once` refuses a row whose `id` is
13
+ * already on disk (write-once ids), by throwing.
14
+ * @param {string} file
15
+ * @param {LedgerRow} row
16
+ * @param {{once?: boolean}} [opts]
17
+ */
18
+ export function appendRow(file: string, row: LedgerRow, opts?: {
19
+ once?: boolean;
20
+ }): void;
21
+ /**
22
+ * Walk the rows in order: a `released` row (`of` = an id) cancels the latest earlier live row with that id, and
23
+ * is itself dropped. A released `fire` or `ran` is not consumed, so its slot or file is retryable (Part 4) and
24
+ * the same id may be written again.
25
+ * @param {LedgerRow[]} rows
26
+ * @returns {LedgerRow[]}
27
+ */
28
+ export function withoutReleased(rows: LedgerRow[]): LedgerRow[];
29
+ export type LedgerRow = {
30
+ id?: string;
31
+ kind: string;
32
+ sig?: string;
33
+ at?: number;
34
+ [k: string]: unknown;
35
+ };