@plurnk/plurnk-schedule 1.19.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.
@@ -0,0 +1,14 @@
1
+ import { type RepresentationPreparationRequest, type RepresentationPreparationResult, type SchemeCtx } from "@plurnk/plurnk-schemes";
2
+ type RuleList = (workspaceId: number) => Promise<readonly {
3
+ alias: string;
4
+ state: string;
5
+ [key: string]: unknown;
6
+ }[]>;
7
+ export default class ScheduleResources {
8
+ #private;
9
+ constructor(list: RuleList);
10
+ claims(pathname: string): boolean;
11
+ prepareRepresentation(request: RepresentationPreparationRequest, ctx: SchemeCtx): Promise<RepresentationPreparationResult>;
12
+ }
13
+ export {};
14
+ //# sourceMappingURL=ScheduleResources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScheduleResources.d.ts","sourceRoot":"","sources":["../src/ScheduleResources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,gCAAgC,EAAE,KAAK,+BAA+B,EAAE,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAE9I,KAAK,QAAQ,GAAG,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAAE,CAAC,CAAC;AAGtH,MAAM,CAAC,OAAO,OAAO,iBAAiB;;IAGlC,YAAY,IAAI,EAAE,QAAQ,EAEzB;IAED,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEhC;IAEK,qBAAqB,CAAC,OAAO,EAAE,gCAAgC,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,+BAA+B,CAAC,CAO/H;CACJ"}
@@ -0,0 +1,22 @@
1
+ import { Results } from "@plurnk/plurnk-schemes";
2
+ // The readable rule resources, `schedule:///rules/<alias>`; an occurrence is a message, never a wait.
3
+ export default class ScheduleResources {
4
+ #list;
5
+ constructor(list) {
6
+ this.#list = list;
7
+ }
8
+ claims(pathname) {
9
+ return /^\/rules(?:\/|$)/u.test(pathname);
10
+ }
11
+ async prepareRepresentation(request, ctx) {
12
+ if (request.authority !== "")
13
+ return Results.failure("schedule:resource", "authority-invalid", 400, "Schedule resources use an empty authority.");
14
+ const { pathname } = request;
15
+ const content = (await this.#list(ctx.workspaceId)).find((rule) => pathname === `/rules/${encodeURIComponent(rule.alias)}`);
16
+ if (content === undefined)
17
+ return Results.failure("schedule:resource", "not-found", 404, "The schedule resource does not exist.");
18
+ const result = await ctx.entries.write(pathname, { channels: { results: { content: JSON.stringify(content, null, 2), mimetype: "application/json" } } });
19
+ return result.status >= 400 ? { status: result.status, problem: result.problem } : { status: 200 };
20
+ }
21
+ }
22
+ //# sourceMappingURL=ScheduleResources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ScheduleResources.js","sourceRoot":"","sources":["../src/ScheduleResources.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA+F,MAAM,wBAAwB,CAAC;AAI9I,sGAAsG;AACtG,MAAM,CAAC,OAAO,OAAO,iBAAiB;IACzB,KAAK,CAAW;IAEzB,YAAY,IAAc;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,MAAM,CAAC,QAAgB;QACnB,OAAO,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,OAAyC,EAAE,GAAc;QACjF,IAAI,OAAO,CAAC,SAAS,KAAK,EAAE;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,GAAG,EAAE,4CAA4C,CAAC,CAAC;QAClJ,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;QAC7B,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,KAAK,UAAU,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC5H,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,WAAW,EAAE,GAAG,EAAE,uCAAuC,CAAC,CAAC;QAClI,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,kBAAkB,EAAE,EAAE,EAAE,CAAC,CAAC;QACzJ,OAAO,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvG,CAAC;CACJ"}
@@ -0,0 +1,51 @@
1
+ import { type LoopPolicyRequest, type ProblemDetails } from "@plurnk/plurnk-contracts";
2
+ import { type ScheduleDefinition } from "./definition.ts";
3
+ import { type ParsedRule } from "./rules.ts";
4
+ export interface ScheduledRule {
5
+ readonly alias: string;
6
+ readonly definition: ScheduleDefinition;
7
+ readonly parsed: ParsedRule;
8
+ }
9
+ export interface DeliveryPort {
10
+ listWorkers(workspaceId: number): Promise<readonly {
11
+ readonly id: number;
12
+ readonly name: string;
13
+ }[]>;
14
+ runLoop(args: {
15
+ readonly workspaceId: number;
16
+ readonly workerId: number;
17
+ readonly prompt: string;
18
+ readonly source: string;
19
+ readonly policy?: LoopPolicyRequest;
20
+ }): Promise<unknown>;
21
+ }
22
+ export interface SchedulerTimers {
23
+ set(callback: () => void, delayMs: number): unknown;
24
+ clear(handle: unknown): void;
25
+ }
26
+ export interface SchedulerOptions {
27
+ readonly clock?: () => number;
28
+ readonly timers?: SchedulerTimers;
29
+ readonly report?: (message: string, cause: unknown) => void;
30
+ readonly settled?: (workspaceId: number, alias: string) => void;
31
+ }
32
+ export interface ScheduleFailure {
33
+ readonly text: string;
34
+ readonly problem: ProblemDetails;
35
+ }
36
+ export declare class ScheduleDeliveryError extends Error {
37
+ readonly problem: ProblemDetails;
38
+ constructor(problem: ProblemDetails, cause?: unknown);
39
+ }
40
+ export default class Scheduler {
41
+ #private;
42
+ constructor(options?: SchedulerOptions);
43
+ now(): number;
44
+ start(port: DeliveryPort): void;
45
+ close(): Promise<void>;
46
+ sync(workspaceId: number, rules: ReadonlyMap<string, ScheduledRule>): Promise<void>;
47
+ failure(workspaceId: number, alias: string): ScheduleFailure | undefined;
48
+ forgive(workspaceId: number, alias: string): void;
49
+ armed(workspaceId: number): readonly string[];
50
+ }
51
+ //# sourceMappingURL=Scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scheduler.d.ts","sourceRoot":"","sources":["../src/Scheduler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAY,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAGjG,OAAO,EAAoB,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC5E,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7D,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IACzB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC,CAAC;IACrG,OAAO,CAAC,IAAI,EAAE;QACV,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;QAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;KACvC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,GAAG,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;IACpD,KAAK,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAE5D,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnE;AAED,MAAM,WAAW,eAAe;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;CACpC;AAWD,qBAAa,qBAAsB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;IAEjC,YAAY,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE,OAAO,EAInD;CACJ;AAoBD,MAAM,CAAC,OAAO,OAAO,SAAS;;IAa1B,YAAY,OAAO,GAAE,gBAAqB,EAKzC;IAED,GAAG,IAAI,MAAM,CAEZ;IAED,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,CAI9B;IAQK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ3B;IAID,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBlF;IAED,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEvE;IAED,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEhD;IAED,KAAK,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE5C;CAqFJ"}
@@ -0,0 +1,205 @@
1
+ // {§schedule-delivery} — the timers. One armed occurrence per (workspace, alias); at its instant
2
+ // the message is delivered to the target worker through the application port as an arrival with
3
+ // the source `schedule://<alias>`, joining the worker's live loop or starting one. Then the next
4
+ // occurrence arms from now: a late fire delivers once and skips what it missed, never a backlog.
5
+ // A delivery failure disarms the rule and holds its Problem for the outcome; `enable` retries.
6
+ import { Problems } from "@plurnk/plurnk-contracts";
7
+ import { createHash } from "node:crypto";
8
+ import { targetWorkerName } from "./definition.js";
9
+ import { nextOccurrence } from "./rules.js";
10
+ export class ScheduleDeliveryError extends Error {
11
+ problem;
12
+ constructor(problem, cause) {
13
+ super(problem.detail, cause === undefined ? undefined : { cause });
14
+ this.name = "ScheduleDeliveryError";
15
+ this.problem = problem;
16
+ }
17
+ }
18
+ // setTimeout's ceiling; a farther occurrence arms in hops.
19
+ const MAX_DELAY_MS = 2_147_483_647;
20
+ const DIAGNOSTIC_LIMIT = 512;
21
+ const key = (workspaceId, alias) => `${workspaceId}:${alias}`;
22
+ const SYSTEM_TIMERS = Object.freeze({
23
+ set: (callback, delayMs) => setTimeout(callback, delayMs).unref(),
24
+ clear: (handle) => { clearTimeout(handle); },
25
+ });
26
+ const problem = (code, status, detail, extensions = {}) => Problems.create("schedule:delivery", code, status, detail, { stage: "schedule-delivery", ...extensions });
27
+ const problemOf = (alias, cause) => Problems.fromError(cause) ?? problem("delivery-failed", 502, `Delivering the scheduled message '${alias}' failed.`, { alias, diagnostic: (cause instanceof Error ? cause.message : String(cause)).slice(0, DIAGNOSTIC_LIMIT), retryable: true });
28
+ export default class Scheduler {
29
+ #clock;
30
+ #timers;
31
+ #report;
32
+ #settled;
33
+ #armed = new Map();
34
+ #failures = new Map();
35
+ #pending = new Set();
36
+ #port = null;
37
+ #serial = Promise.resolve();
38
+ #closing = false;
39
+ #settlementErrors = [];
40
+ constructor(options = {}) {
41
+ this.#clock = options.clock ?? Date.now;
42
+ this.#timers = options.timers ?? SYSTEM_TIMERS;
43
+ this.#report = options.report ?? ((message, cause) => { console.error(`${message}:`, cause); });
44
+ this.#settled = options.settled ?? (() => { });
45
+ }
46
+ now() {
47
+ return this.#clock();
48
+ }
49
+ start(port) {
50
+ if (this.#port !== null)
51
+ throw new Error("schedule Scheduler already started");
52
+ this.#port = port;
53
+ this.#closing = false;
54
+ }
55
+ #exclusive(run) {
56
+ const result = this.#serial.then(run);
57
+ this.#serial = result.then(() => { }, () => { });
58
+ return result;
59
+ }
60
+ async close() {
61
+ this.#closing = true;
62
+ await this.#serial;
63
+ for (const { handle } of this.#armed.values())
64
+ if (handle !== null)
65
+ this.#timers.clear(handle);
66
+ this.#armed.clear();
67
+ await Promise.all(this.#pending);
68
+ this.#port = null;
69
+ if (this.#settlementErrors.length > 0)
70
+ throw new AggregateError(this.#settlementErrors, "Scheduled occurrence settlement failed.");
71
+ }
72
+ // {§schedule-residency} — a workspace's rule set as published: aliases absent from it disarm,
73
+ // unchanged occurrences retain identity. A held failure clears when its rule leaves the set or changes.
74
+ sync(workspaceId, rules) {
75
+ return this.#exclusive(async () => {
76
+ for (const [entryKey, armed] of this.#armed) {
77
+ if (armed.workspaceId !== workspaceId)
78
+ continue;
79
+ const replacement = rules.get(armed.rule.alias);
80
+ if (replacement !== undefined && JSON.stringify(replacement.definition) === JSON.stringify(armed.rule.definition))
81
+ continue;
82
+ if (armed.handle !== null)
83
+ this.#timers.clear(armed.handle);
84
+ this.#armed.delete(entryKey);
85
+ }
86
+ for (const [entryKey, failed] of this.#failures) {
87
+ if (!entryKey.startsWith(`${workspaceId}:`))
88
+ continue;
89
+ const rule = rules.get(entryKey.slice(entryKey.indexOf(":") + 1));
90
+ if (rule === undefined || rule.parsed.text !== failed.text)
91
+ this.#failures.delete(entryKey);
92
+ }
93
+ for (const rule of rules.values()) {
94
+ if (this.#failures.has(key(workspaceId, rule.alias)))
95
+ continue;
96
+ if (this.#armed.has(key(workspaceId, rule.alias)))
97
+ continue;
98
+ this.#arm(workspaceId, rule);
99
+ }
100
+ });
101
+ }
102
+ failure(workspaceId, alias) {
103
+ return this.#failures.get(key(workspaceId, alias));
104
+ }
105
+ forgive(workspaceId, alias) {
106
+ this.#failures.delete(key(workspaceId, alias));
107
+ }
108
+ armed(workspaceId) {
109
+ return [...this.#armed.values()].filter((armed) => armed.workspaceId === workspaceId).map((armed) => armed.rule.alias).toSorted();
110
+ }
111
+ #arm(workspaceId, rule) {
112
+ if (this.#closing)
113
+ return;
114
+ const entryKey = key(workspaceId, rule.alias);
115
+ const existing = this.#armed.get(entryKey);
116
+ if (existing !== undefined) {
117
+ if (existing.handle !== null)
118
+ this.#timers.clear(existing.handle);
119
+ this.#armed.delete(entryKey);
120
+ }
121
+ const now = this.#clock();
122
+ const due = nextOccurrence(rule.parsed, now);
123
+ if (due === null)
124
+ return;
125
+ const dueMs = due.epochMilliseconds;
126
+ const fingerprint = createHash("sha256").update(JSON.stringify(rule.definition)).digest("hex");
127
+ const armed = { workspaceId, rule, dueMs, event: `${rule.alias}/${fingerprint}/${dueMs}`, handle: null, delivering: false };
128
+ this.#armed.set(entryKey, armed);
129
+ this.#setTimer(armed);
130
+ }
131
+ #setTimer(armed) {
132
+ armed.handle = this.#timers.set(() => { this.#fire(armed); }, Math.max(0, Math.min(armed.dueMs - this.#clock(), MAX_DELAY_MS)));
133
+ }
134
+ #fire(armed) {
135
+ const { workspaceId, rule } = armed;
136
+ const entryKey = key(workspaceId, rule.alias);
137
+ const delivery = (async () => {
138
+ const admitted = await this.#exclusive(async () => {
139
+ if (this.#closing || this.#armed.get(entryKey) !== armed || armed.delivering)
140
+ return false;
141
+ if (this.#clock() < armed.dueMs) {
142
+ this.#setTimer(armed);
143
+ return false;
144
+ }
145
+ armed.handle = null;
146
+ armed.delivering = true;
147
+ return true;
148
+ });
149
+ if (!admitted)
150
+ return;
151
+ // Admission may demand workspace capabilities. Never hold the producer's
152
+ // mutation queue across that exterior call ({§schedule-delivery}).
153
+ let result;
154
+ try {
155
+ await this.#deliver(workspaceId, rule);
156
+ result = { status: 200 };
157
+ }
158
+ catch (cause) {
159
+ const failed = problemOf(rule.alias, cause);
160
+ result = { status: failed.status, problem: failed };
161
+ this.#report(`scheduled message '${rule.alias}' was not delivered in workspace ${workspaceId}`, cause);
162
+ }
163
+ await this.#exclusive(async () => {
164
+ if (this.#armed.get(entryKey) !== armed)
165
+ return;
166
+ this.#armed.delete(entryKey);
167
+ if (result.status >= 400)
168
+ this.#failures.set(entryKey, { text: rule.parsed.text, problem: result.problem });
169
+ else
170
+ this.#arm(workspaceId, rule);
171
+ });
172
+ })()
173
+ .catch((cause) => {
174
+ this.#settlementErrors.push(cause);
175
+ this.#report(`scheduled occurrence '${rule.alias}' could not settle in workspace ${workspaceId}`, cause);
176
+ })
177
+ .finally(() => {
178
+ this.#pending.delete(delivery);
179
+ this.#settled(workspaceId, rule.alias);
180
+ });
181
+ this.#pending.add(delivery);
182
+ }
183
+ async #deliver(workspaceId, rule) {
184
+ const port = this.#port;
185
+ if (port === null)
186
+ throw new Error("schedule Scheduler is not started");
187
+ const name = targetWorkerName(rule.definition.target);
188
+ const worker = (await port.listWorkers(workspaceId)).find((candidate) => candidate.name === name);
189
+ if (worker === undefined) {
190
+ throw new ScheduleDeliveryError(problem("target-missing", 404, `No worker named '${name}' exists in this workspace.`, {
191
+ alias: rule.alias,
192
+ target: rule.definition.target,
193
+ retryable: true,
194
+ }));
195
+ }
196
+ await port.runLoop({
197
+ workspaceId,
198
+ workerId: worker.id,
199
+ prompt: rule.definition.prompt,
200
+ source: `schedule://${encodeURIComponent(rule.alias)}`,
201
+ ...(rule.definition.policy === undefined ? {} : { policy: rule.definition.policy }),
202
+ });
203
+ }
204
+ }
205
+ //# sourceMappingURL=Scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Scheduler.js","sourceRoot":"","sources":["../src/Scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { type ScheduleDefinition } from "./definition.ts";
2
+ export declare const ENABLED = "PLURNK_SCHEDULE_ENABLED";
3
+ export declare const PREVIEW_OCCURRENCES = "PLURNK_SCHEDULE_PREVIEW_OCCURRENCES";
4
+ export declare const previewOccurrences: (env: NodeJS.ProcessEnv) => number;
5
+ export declare const serviceEnabled: (env: NodeJS.ProcessEnv) => ReadonlySet<string>;
6
+ export declare const serviceDefinitions: (env: NodeJS.ProcessEnv) => ReadonlyMap<string, ScheduleDefinition>;
7
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmC,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG3F,eAAO,MAAM,OAAO,4BAAqB,CAAC;AAC1C,eAAO,MAAM,mBAAmB,wCAAiC,CAAC;AA2BlE,eAAO,MAAM,kBAAkB,QAAS,MAAM,CAAC,UAAU,KAAG,MAO3D,CAAC;AAEF,eAAO,MAAM,cAAc,QAAS,MAAM,CAAC,UAAU,KAAG,WAAW,CAAC,MAAM,CASzE,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,MAAM,CAAC,UAAU,KAAG,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAejG,CAAC"}
package/dist/config.js ADDED
@@ -0,0 +1,73 @@
1
+ // {§schedule-environment} — the service's own rules: `PLURNK_SCHEDULE_<ALIAS>` holds one
2
+ // definition as JSON, the alias case-folded to the family grammar; `PLURNK_SCHEDULE_ENABLED`
3
+ // names the aliases a workspace starts with. Service rules may be unbounded ({§schedule-bound}).
4
+ import { readDefinition, DefinitionError } from "./definition.js";
5
+ const PREFIX = "PLURNK_SCHEDULE_";
6
+ export const ENABLED = `${PREFIX}ENABLED`;
7
+ export const PREVIEW_OCCURRENCES = `${PREFIX}PREVIEW_OCCURRENCES`;
8
+ // The family's own knobs; every other key under the prefix declares a rule.
9
+ const CONTROLS = new Set([ENABLED, PREVIEW_OCCURRENCES]);
10
+ const ALIAS = /^[a-z][a-z0-9-]*$/u;
11
+ const parseEnvironment = (env) => {
12
+ const definitions = new Map();
13
+ for (const [key, value] of Object.entries(env)) {
14
+ if (value === undefined || !key.startsWith(PREFIX) || CONTROLS.has(key))
15
+ continue;
16
+ const alias = key.slice(PREFIX.length).toLowerCase();
17
+ if (!ALIAS.test(alias))
18
+ throw new Error(`${key} derives the alias '${alias}', which must match [a-z][a-z0-9-]*.`);
19
+ const existing = definitions.get(alias);
20
+ if (existing !== undefined)
21
+ throw new Error(`${existing.key} and ${key} both derive the schedule alias '${alias}'.`);
22
+ definitions.set(alias, { key, value });
23
+ }
24
+ return definitions;
25
+ };
26
+ const parseJson = (key, value) => {
27
+ try {
28
+ return JSON.parse(value);
29
+ }
30
+ catch (cause) {
31
+ throw new Error(`${key} is not JSON.`, { cause });
32
+ }
33
+ };
34
+ // {§schedule-discovery-preview} — how many upcoming occurrences a reading of rule text shows.
35
+ export const previewOccurrences = (env) => {
36
+ const raw = env[PREVIEW_OCCURRENCES];
37
+ const value = Number(raw);
38
+ if (raw === undefined || raw.trim().length === 0 || !Number.isSafeInteger(value) || value < 1) {
39
+ throw new Error(`${PREVIEW_OCCURRENCES} must be a positive integer; got ${JSON.stringify(raw)}.`);
40
+ }
41
+ return value;
42
+ };
43
+ export const serviceEnabled = (env) => {
44
+ const raw = env[ENABLED];
45
+ if (raw === undefined)
46
+ throw new Error(`${ENABLED} is missing from the assembled environment floor.`);
47
+ const parsed = parseJson(ENABLED, raw);
48
+ if (!Array.isArray(parsed) || !parsed.every((entry) => typeof entry === "string")) {
49
+ throw new Error(`${ENABLED} must be a JSON array of aliases.`);
50
+ }
51
+ const definitions = parseEnvironment(env);
52
+ return new Set(parsed.filter((alias) => definitions.get(alias)?.value !== ""));
53
+ };
54
+ export const serviceDefinitions = (env) => {
55
+ const definitions = new Map();
56
+ for (const [alias, { key, value }] of parseEnvironment(env)) {
57
+ if (value === "")
58
+ continue;
59
+ let definition;
60
+ try {
61
+ definition = readDefinition(parseJson(key, value));
62
+ }
63
+ catch (cause) {
64
+ if (!(cause instanceof DefinitionError))
65
+ throw cause;
66
+ throw new Error(`${key} must be a schedule definition: {"rule", "target", "prompt", "policy"?}.`, { cause });
67
+ }
68
+ definitions.set(alias, definition);
69
+ }
70
+ return new Map([...definitions]
71
+ .toSorted(([left], [right]) => left.localeCompare(right)));
72
+ };
73
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import { type LoopPolicyRequest } from "@plurnk/plurnk-contracts";
2
+ export interface ScheduleDefinition {
3
+ readonly rule: string;
4
+ readonly target: string;
5
+ readonly prompt: string;
6
+ readonly policy?: LoopPolicyRequest;
7
+ }
8
+ export declare const TARGET: RegExp;
9
+ export declare const DEFINITION_SCHEMA: Readonly<{
10
+ type: "object";
11
+ additionalProperties: false;
12
+ required: string[];
13
+ properties: {
14
+ rule: {
15
+ type: string;
16
+ minLength: number;
17
+ description: string;
18
+ };
19
+ target: {
20
+ type: string;
21
+ pattern: string;
22
+ description: string;
23
+ };
24
+ prompt: {
25
+ type: string;
26
+ minLength: number;
27
+ description: string;
28
+ };
29
+ policy: {
30
+ $ref: string;
31
+ description: string;
32
+ };
33
+ };
34
+ }>;
35
+ export declare class DefinitionError extends TypeError {
36
+ readonly errors: readonly unknown[];
37
+ constructor(errors: readonly unknown[]);
38
+ }
39
+ export declare const readDefinition: (value: unknown) => ScheduleDefinition;
40
+ export declare const targetWorkerName: (target: string) => string;
41
+ //# sourceMappingURL=definition.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAGA,OAAO,EAA2C,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE3G,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAED,eAAO,MAAM,MAAM,QAAqE,CAAC;AAEzF,eAAO,MAAM,iBAAiB;;;;;QAKtB,IAAI;YACA,IAAI;YACJ,SAAS;YACT,WAAW;;QAEf,MAAM;YACF,IAAI;YACJ,OAAO;YACP,WAAW;;QAEf,MAAM;YACF,IAAI;YACJ,SAAS;YACT,WAAW;;QAEf,MAAM;YACF,IAAI;YACJ,WAAW;;;EAGA,CAAC;AAExB,qBAAa,eAAgB,SAAQ,SAAS;IAC1C,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;IAEpC,YAAY,MAAM,EAAE,SAAS,OAAO,EAAE,EAIrC;CACJ;AAED,eAAO,MAAM,cAAc,UAAW,OAAO,KAAG,kBAI/C,CAAC;AAEF,eAAO,MAAM,gBAAgB,WAAY,MAAM,KAAG,MAIjD,CAAC"}
@@ -0,0 +1,52 @@
1
+ // {§schedule-family} — the one definition `add` accepts and the coordinator persists: the rule
2
+ // text ({§schedule-rule}), the worker the message is delivered to, the message, and optionally
3
+ // what the delivery states about the policy of a loop it starts ({§schedule-delivery}).
4
+ import { Validator, WORKER_NAME } from "@plurnk/plurnk-contracts";
5
+ export const TARGET = new RegExp(`^worker://(${WORKER_NAME.source.slice(1, -1)})$`, "u");
6
+ export const DEFINITION_SCHEMA = Object.freeze({
7
+ type: "object",
8
+ additionalProperties: false,
9
+ required: ["rule", "target", "prompt"],
10
+ properties: {
11
+ rule: {
12
+ type: "string",
13
+ minLength: 1,
14
+ description: "RFC 5545 text: an optional DTSTART line and one RRULE line, or bare FREQ=… parts. A workspace rule ends: COUNT or UNTIL.",
15
+ },
16
+ target: {
17
+ type: "string",
18
+ pattern: TARGET.source,
19
+ description: "The worker the message is delivered to.",
20
+ },
21
+ prompt: {
22
+ type: "string",
23
+ minLength: 1,
24
+ description: "The message delivered at each occurrence.",
25
+ },
26
+ policy: {
27
+ $ref: "https://schemas.plurnk.xyz/v0/LoopPolicyRequest.json",
28
+ description: "What the delivery states about the policy of a loop it starts; every field left out is the daemon's to supply.",
29
+ },
30
+ },
31
+ });
32
+ export class DefinitionError extends TypeError {
33
+ errors;
34
+ constructor(errors) {
35
+ super("The schedule definition does not match its schema.");
36
+ this.name = "DefinitionError";
37
+ this.errors = errors;
38
+ }
39
+ }
40
+ export const readDefinition = (value) => {
41
+ const validation = Validator.validateJsonSchemaInstance(DEFINITION_SCHEMA, value);
42
+ if (!validation.valid)
43
+ throw new DefinitionError(validation.errors);
44
+ return structuredClone(value);
45
+ };
46
+ export const targetWorkerName = (target) => {
47
+ const match = TARGET.exec(target);
48
+ if (match === null)
49
+ throw new TypeError(`'${target}' is not a worker:// target.`);
50
+ return match[1];
51
+ };
52
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../src/definition.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,+FAA+F;AAC/F,wFAAwF;AACxF,OAAO,EAAE,SAAS,EAAE,WAAW,EAA2C,MAAM,0BAA0B,CAAC;AAS3G,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,cAAc,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAEzF,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3C,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE,KAAK;IAC3B,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;IACtC,UAAU,EAAE;QACR,IAAI,EAAE;YACF,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,0HAA0H;SAC1I;QACD,MAAM,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,MAAM,CAAC,MAAM;YACtB,WAAW,EAAE,yCAAyC;SACzD;QACD,MAAM,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,SAAS,EAAE,CAAC;YACZ,WAAW,EAAE,2CAA2C;SAC3D;QACD,MAAM,EAAE;YACJ,IAAI,EAAE,sDAAsD;YAC5D,WAAW,EAAE,gHAAgH;SAChI;KACJ;CACJ,CAAsB,CAAC;AAExB,MAAM,OAAO,eAAgB,SAAQ,SAAS;IACjC,MAAM,CAAqB;IAEpC,YAAY,MAA0B;QAClC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;CACJ;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAc,EAAsB,EAAE;IACjE,MAAM,UAAU,GAAG,SAAS,CAAC,0BAA0B,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IAClF,IAAI,CAAC,UAAU,CAAC,KAAK;QAAE,MAAM,IAAI,eAAe,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IACpE,OAAO,eAAe,CAAC,KAA2B,CAAC,CAAC;AACxD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAU,EAAE;IACvD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,IAAI;QAAE,MAAM,IAAI,SAAS,CAAC,IAAI,MAAM,8BAA8B,CAAC,CAAC;IAClF,OAAO,KAAK,CAAC,CAAC,CAAE,CAAC;AACrB,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { default as Module, type ModuleOptions } from "./Module.ts";
2
+ export { default as ScheduleFunctionality, SCHEDULE_FAMILY, SCHEDULE_OWNER, ScheduleFunctionalityError, type FunctionalityFamilyHandle, type ScheduleFunctionalityOptions, } from "./Functionality.ts";
3
+ export { default as Scheduler, ScheduleDeliveryError, type DeliveryPort, type ScheduledRule, type SchedulerOptions, type SchedulerTimers, } from "./Scheduler.ts";
4
+ export { assertZone, describeRule, nextOccurrence, normalizeRule, parseRule, ScheduleRuleError, upcoming, type ParsedRule, type ScheduleRuleCode, } from "./rules.ts";
5
+ export { DEFINITION_SCHEMA, DefinitionError, readDefinition, targetWorkerName, type ScheduleDefinition } from "./definition.ts";
6
+ export { ENABLED, serviceDefinitions, serviceEnabled } from "./config.ts";
7
+ export { isoString, zoned } from "./temporal.ts";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACH,OAAO,IAAI,qBAAqB,EAChC,eAAe,EACf,cAAc,EACd,0BAA0B,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,GACpC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,OAAO,IAAI,SAAS,EACpB,qBAAqB,EACrB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACH,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,QAAQ,EACR,KAAK,UAAU,EACf,KAAK,gBAAgB,GACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAChI,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { default as Module } from "./Module.js";
2
+ export { default as ScheduleFunctionality, SCHEDULE_FAMILY, SCHEDULE_OWNER, ScheduleFunctionalityError, } from "./Functionality.js";
3
+ export { default as Scheduler, ScheduleDeliveryError, } from "./Scheduler.js";
4
+ export { assertZone, describeRule, nextOccurrence, normalizeRule, parseRule, ScheduleRuleError, upcoming, } from "./rules.js";
5
+ export { DEFINITION_SCHEMA, DefinitionError, readDefinition, targetWorkerName } from "./definition.js";
6
+ export { ENABLED, serviceDefinitions, serviceEnabled } from "./config.js";
7
+ export { isoString, zoned } from "./temporal.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAsB,MAAM,aAAa,CAAC;AACpE,OAAO,EACH,OAAO,IAAI,qBAAqB,EAChC,eAAe,EACf,cAAc,EACd,0BAA0B,GAG7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACH,OAAO,IAAI,SAAS,EACpB,qBAAqB,GAKxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACH,UAAU,EACV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,SAAS,EACT,iBAAiB,EACjB,QAAQ,GAGX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAA2B,MAAM,iBAAiB,CAAC;AAChI,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { RRuleTemporal, type TemporalZonedDateTime } from "rrule-temporal";
2
+ export type ScheduleRuleCode = "rule-invalid" | "rule-unbounded" | "zone-unknown";
3
+ export declare class ScheduleRuleError extends Error {
4
+ readonly code: ScheduleRuleCode;
5
+ constructor(code: ScheduleRuleCode, detail: string, cause?: unknown);
6
+ }
7
+ export interface ParsedRule {
8
+ readonly text: string;
9
+ readonly zone: string;
10
+ readonly bounded: boolean;
11
+ readonly rule: RRuleTemporal;
12
+ }
13
+ export declare const assertZone: (zone: string) => void;
14
+ export declare const parseRule: (text: string) => ParsedRule;
15
+ export declare const normalizeRule: (text: string, zone: string, nowMs: number) => ParsedRule;
16
+ export declare const nextOccurrence: (parsed: ParsedRule, afterMs: number) => TemporalZonedDateTime | null;
17
+ export declare const upcoming: (parsed: ParsedRule, afterMs: number, limit: number) => TemporalZonedDateTime[];
18
+ export declare const describeRule: (parsed: ParsedRule) => string;
19
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,KAAK,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAY3E,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAElF,qBAAa,iBAAkB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAEhC,YAAY,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,EAIlE;CACJ;AAED,MAAM,WAAW,UAAU;IAEvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAChC;AAyCD,eAAO,MAAM,UAAU,SAAU,MAAM,KAAG,IAMzC,CAAC;AAcF,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,UAMxC,CAAC;AAKF,eAAO,MAAM,aAAa,SAAU,MAAM,QAAQ,MAAM,SAAS,MAAM,KAAG,UAqBzE,CAAC;AAGF,eAAO,MAAM,cAAc,WAAY,UAAU,WAAW,MAAM,KAAG,qBAAqB,GAAG,IACpC,CAAC;AAE1D,eAAO,MAAM,QAAQ,WAAY,UAAU,WAAW,MAAM,SAAS,MAAM,KAAG,qBAAqB,EAUlG,CAAC;AAGF,eAAO,MAAM,YAAY,WAAY,UAAU,KAAG,MAAyE,CAAC"}