@pristine-ts/local-scheduling 4.0.2
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/LICENSE +201 -0
- package/dist/lib/cjs/builders/builders.js +18 -0
- package/dist/lib/cjs/builders/builders.js.map +1 -0
- package/dist/lib/cjs/builders/cron-expression.builder.js +159 -0
- package/dist/lib/cjs/builders/cron-expression.builder.js.map +1 -0
- package/dist/lib/cjs/enums/day-of-week.enum.js +19 -0
- package/dist/lib/cjs/enums/day-of-week.enum.js.map +1 -0
- package/dist/lib/cjs/enums/enums.js +19 -0
- package/dist/lib/cjs/enums/enums.js.map +1 -0
- package/dist/lib/cjs/enums/month.enum.js +23 -0
- package/dist/lib/cjs/enums/month.enum.js.map +1 -0
- package/dist/lib/cjs/errors/errors.js +20 -0
- package/dist/lib/cjs/errors/errors.js.map +1 -0
- package/dist/lib/cjs/errors/invalid-cron-expression.error.js +30 -0
- package/dist/lib/cjs/errors/invalid-cron-expression.error.js.map +1 -0
- package/dist/lib/cjs/errors/schedule-already-exists.error.js +25 -0
- package/dist/lib/cjs/errors/schedule-already-exists.error.js.map +1 -0
- package/dist/lib/cjs/errors/schedule-not-found.error.js +22 -0
- package/dist/lib/cjs/errors/schedule-not-found.error.js.map +1 -0
- package/dist/lib/cjs/interfaces/interfaces.js +22 -0
- package/dist/lib/cjs/interfaces/interfaces.js.map +1 -0
- package/dist/lib/cjs/interfaces/local-scheduler.interface.js +3 -0
- package/dist/lib/cjs/interfaces/local-scheduler.interface.js.map +1 -0
- package/dist/lib/cjs/interfaces/schedulable.interface.js +3 -0
- package/dist/lib/cjs/interfaces/schedulable.interface.js.map +1 -0
- package/dist/lib/cjs/interfaces/schedule-descriptor.interface.js +3 -0
- package/dist/lib/cjs/interfaces/schedule-descriptor.interface.js.map +1 -0
- package/dist/lib/cjs/interfaces/schedule-options.interface.js +3 -0
- package/dist/lib/cjs/interfaces/schedule-options.interface.js.map +1 -0
- package/dist/lib/cjs/interfaces/schedule-state.interface.js +3 -0
- package/dist/lib/cjs/interfaces/schedule-state.interface.js.map +1 -0
- package/dist/lib/cjs/interfaces/schedule.interface.js +3 -0
- package/dist/lib/cjs/interfaces/schedule.interface.js.map +1 -0
- package/dist/lib/cjs/local-scheduling.module.js +85 -0
- package/dist/lib/cjs/local-scheduling.module.js.map +1 -0
- package/dist/lib/cjs/local-scheduling.module.keyname.js +5 -0
- package/dist/lib/cjs/local-scheduling.module.keyname.js.map +1 -0
- package/dist/lib/cjs/managers/local-scheduler.manager.js +361 -0
- package/dist/lib/cjs/managers/local-scheduler.manager.js.map +1 -0
- package/dist/lib/cjs/managers/managers.js +18 -0
- package/dist/lib/cjs/managers/managers.js.map +1 -0
- package/dist/lib/cjs/models/cron-expression.model.js +304 -0
- package/dist/lib/cjs/models/cron-expression.model.js.map +1 -0
- package/dist/lib/cjs/models/models.js +18 -0
- package/dist/lib/cjs/models/models.js.map +1 -0
- package/dist/lib/cjs/schedules/cron.schedule.js +34 -0
- package/dist/lib/cjs/schedules/cron.schedule.js.map +1 -0
- package/dist/lib/cjs/schedules/date.schedule.js +27 -0
- package/dist/lib/cjs/schedules/date.schedule.js.map +1 -0
- package/dist/lib/cjs/schedules/schedules.js +19 -0
- package/dist/lib/cjs/schedules/schedules.js.map +1 -0
- package/dist/lib/cjs/servers/local-scheduler.runtime-server.js +69 -0
- package/dist/lib/cjs/servers/local-scheduler.runtime-server.js.map +1 -0
- package/dist/lib/cjs/servers/servers.js +18 -0
- package/dist/lib/cjs/servers/servers.js.map +1 -0
- package/dist/lib/cjs/types/scheduled-task-function.type.js +3 -0
- package/dist/lib/cjs/types/scheduled-task-function.type.js.map +1 -0
- package/dist/lib/cjs/types/types.js +18 -0
- package/dist/lib/cjs/types/types.js.map +1 -0
- package/dist/lib/esm/builders/builders.js +2 -0
- package/dist/lib/esm/builders/builders.js.map +1 -0
- package/dist/lib/esm/builders/cron-expression.builder.js +155 -0
- package/dist/lib/esm/builders/cron-expression.builder.js.map +1 -0
- package/dist/lib/esm/enums/day-of-week.enum.js +16 -0
- package/dist/lib/esm/enums/day-of-week.enum.js.map +1 -0
- package/dist/lib/esm/enums/enums.js +3 -0
- package/dist/lib/esm/enums/enums.js.map +1 -0
- package/dist/lib/esm/enums/month.enum.js +20 -0
- package/dist/lib/esm/enums/month.enum.js.map +1 -0
- package/dist/lib/esm/errors/errors.js +4 -0
- package/dist/lib/esm/errors/errors.js.map +1 -0
- package/dist/lib/esm/errors/invalid-cron-expression.error.js +26 -0
- package/dist/lib/esm/errors/invalid-cron-expression.error.js.map +1 -0
- package/dist/lib/esm/errors/schedule-already-exists.error.js +21 -0
- package/dist/lib/esm/errors/schedule-already-exists.error.js.map +1 -0
- package/dist/lib/esm/errors/schedule-not-found.error.js +18 -0
- package/dist/lib/esm/errors/schedule-not-found.error.js.map +1 -0
- package/dist/lib/esm/interfaces/interfaces.js +6 -0
- package/dist/lib/esm/interfaces/interfaces.js.map +1 -0
- package/dist/lib/esm/interfaces/local-scheduler.interface.js +2 -0
- package/dist/lib/esm/interfaces/local-scheduler.interface.js.map +1 -0
- package/dist/lib/esm/interfaces/schedulable.interface.js +2 -0
- package/dist/lib/esm/interfaces/schedulable.interface.js.map +1 -0
- package/dist/lib/esm/interfaces/schedule-descriptor.interface.js +2 -0
- package/dist/lib/esm/interfaces/schedule-descriptor.interface.js.map +1 -0
- package/dist/lib/esm/interfaces/schedule-options.interface.js +2 -0
- package/dist/lib/esm/interfaces/schedule-options.interface.js.map +1 -0
- package/dist/lib/esm/interfaces/schedule-state.interface.js +2 -0
- package/dist/lib/esm/interfaces/schedule-state.interface.js.map +1 -0
- package/dist/lib/esm/interfaces/schedule.interface.js +2 -0
- package/dist/lib/esm/interfaces/schedule.interface.js.map +1 -0
- package/dist/lib/esm/local-scheduling.module.js +68 -0
- package/dist/lib/esm/local-scheduling.module.js.map +1 -0
- package/dist/lib/esm/local-scheduling.module.keyname.js +2 -0
- package/dist/lib/esm/local-scheduling.module.keyname.js.map +1 -0
- package/dist/lib/esm/managers/local-scheduler.manager.js +358 -0
- package/dist/lib/esm/managers/local-scheduler.manager.js.map +1 -0
- package/dist/lib/esm/managers/managers.js +2 -0
- package/dist/lib/esm/managers/managers.js.map +1 -0
- package/dist/lib/esm/models/cron-expression.model.js +300 -0
- package/dist/lib/esm/models/cron-expression.model.js.map +1 -0
- package/dist/lib/esm/models/models.js +2 -0
- package/dist/lib/esm/models/models.js.map +1 -0
- package/dist/lib/esm/schedules/cron.schedule.js +30 -0
- package/dist/lib/esm/schedules/cron.schedule.js.map +1 -0
- package/dist/lib/esm/schedules/date.schedule.js +23 -0
- package/dist/lib/esm/schedules/date.schedule.js.map +1 -0
- package/dist/lib/esm/schedules/schedules.js +3 -0
- package/dist/lib/esm/schedules/schedules.js.map +1 -0
- package/dist/lib/esm/servers/local-scheduler.runtime-server.js +66 -0
- package/dist/lib/esm/servers/local-scheduler.runtime-server.js.map +1 -0
- package/dist/lib/esm/servers/servers.js +2 -0
- package/dist/lib/esm/servers/servers.js.map +1 -0
- package/dist/lib/esm/types/scheduled-task-function.type.js +2 -0
- package/dist/lib/esm/types/scheduled-task-function.type.js.map +1 -0
- package/dist/lib/esm/types/types.js +2 -0
- package/dist/lib/esm/types/types.js.map +1 -0
- package/dist/lib/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/lib/tsconfig.tsbuildinfo +1 -0
- package/dist/types/builders/builders.d.ts +1 -0
- package/dist/types/builders/cron-expression.builder.d.ts +69 -0
- package/dist/types/enums/day-of-week.enum.d.ts +14 -0
- package/dist/types/enums/enums.d.ts +2 -0
- package/dist/types/enums/month.enum.d.ts +18 -0
- package/dist/types/errors/errors.d.ts +3 -0
- package/dist/types/errors/invalid-cron-expression.error.d.ts +20 -0
- package/dist/types/errors/schedule-already-exists.error.d.ts +15 -0
- package/dist/types/errors/schedule-not-found.error.d.ts +12 -0
- package/dist/types/interfaces/interfaces.d.ts +5 -0
- package/dist/types/interfaces/local-scheduler.interface.d.ts +57 -0
- package/dist/types/interfaces/schedulable.interface.d.ts +43 -0
- package/dist/types/interfaces/schedule-descriptor.interface.d.ts +22 -0
- package/dist/types/interfaces/schedule-options.interface.d.ts +37 -0
- package/dist/types/interfaces/schedule-state.interface.d.ts +24 -0
- package/dist/types/interfaces/schedule.interface.d.ts +20 -0
- package/dist/types/local-scheduling.module.d.ts +30 -0
- package/dist/types/local-scheduling.module.keyname.d.ts +1 -0
- package/dist/types/managers/local-scheduler.manager.d.ts +110 -0
- package/dist/types/managers/managers.d.ts +1 -0
- package/dist/types/models/cron-expression.model.d.ts +120 -0
- package/dist/types/models/models.d.ts +1 -0
- package/dist/types/schedules/cron.schedule.d.ts +22 -0
- package/dist/types/schedules/date.schedule.d.ts +17 -0
- package/dist/types/schedules/schedules.d.ts +2 -0
- package/dist/types/servers/local-scheduler.runtime-server.d.ts +24 -0
- package/dist/types/servers/servers.d.ts +1 -0
- package/dist/types/types/scheduled-task-function.type.d.ts +10 -0
- package/dist/types/types/types.d.ts +1 -0
- package/package.json +68 -0
- package/readme.md +307 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { InvalidCronExpressionError } from "../errors/invalid-cron-expression.error";
|
|
2
|
+
/**
|
|
3
|
+
* A parsed, validated standard cron expression, and the engine that computes its upcoming
|
|
4
|
+
* execution dates.
|
|
5
|
+
*
|
|
6
|
+
* **Supported syntax** (standard 5-field cron, plus an optional leading seconds field):
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* ┌───────────── second (0-59) (optional 6th field; omit for classic 5-field cron)
|
|
10
|
+
* │ ┌─────────── minute (0-59)
|
|
11
|
+
* │ │ ┌───────── hour (0-23)
|
|
12
|
+
* │ │ │ ┌─────── day-of-month (1-31)
|
|
13
|
+
* │ │ │ │ ┌───── month (1-12 or JAN-DEC)
|
|
14
|
+
* │ │ │ │ │ ┌─── day-of-week (0-7 or SUN-SAT; 0 and 7 are both Sunday)
|
|
15
|
+
* │ │ │ │ │ │
|
|
16
|
+
* * * * * * *
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* Each field accepts `*`, single values, ranges (`a-b`), lists (`a,b,c`), and steps
|
|
20
|
+
* (`* / n`, `a-b/n`, `a/n` meaning "from a to the maximum, every n"). Month and day-of-week
|
|
21
|
+
* values may be given as case-insensitive names. Ranges must be ascending; wrap-around
|
|
22
|
+
* ranges such as `FRI-SUN` are not supported — express them as a list (`FRI,SAT,SUN`).
|
|
23
|
+
*
|
|
24
|
+
* **Day-of-month / day-of-week OR rule:** when *both* the day-of-month and day-of-week
|
|
25
|
+
* fields are restricted (neither is `*`), the expression matches when *either* field
|
|
26
|
+
* matches — the classic Vixie-cron behaviour. For example `30 4 1,15 * 5` runs at 04:30 on
|
|
27
|
+
* the 1st and 15th of the month **and** every Friday. When at least one of the two is `*`,
|
|
28
|
+
* the fields combine with AND (the `*` one matching everything). A field is considered
|
|
29
|
+
* "restricted" whenever its text is not exactly `*` — so a starred field carrying a step
|
|
30
|
+
* (every-N) still counts as restricted.
|
|
31
|
+
*
|
|
32
|
+
* **Time semantics:** all computations use the host's **system local time** (via the
|
|
33
|
+
* standard `Date`). Across a spring-forward DST transition, a local time that does not
|
|
34
|
+
* exist is skipped; across a fall-back transition, a repeated local time fires once. A
|
|
35
|
+
* future revision may accept an IANA timezone without changing this class's method
|
|
36
|
+
* signatures (a timezone would be supplied as an additional, optional constructor option).
|
|
37
|
+
*/
|
|
38
|
+
export class CronExpression {
|
|
39
|
+
/**
|
|
40
|
+
* Parses and validates the expression.
|
|
41
|
+
* @param expression A 5-field (or 6-field, seconds-leading) standard cron expression.
|
|
42
|
+
* @throws {InvalidCronExpressionError} if the expression is malformed or out of range.
|
|
43
|
+
* The error carries an HTTP 400 status and a precise message.
|
|
44
|
+
*/
|
|
45
|
+
constructor(expression) {
|
|
46
|
+
if (typeof expression !== "string") {
|
|
47
|
+
throw new InvalidCronExpressionError("A cron expression must be a string.", String(expression));
|
|
48
|
+
}
|
|
49
|
+
const normalized = expression.trim().replace(/\s+/g, " ");
|
|
50
|
+
if (normalized.length === 0) {
|
|
51
|
+
throw new InvalidCronExpressionError("A cron expression cannot be empty.", expression);
|
|
52
|
+
}
|
|
53
|
+
const fields = normalized.split(" ");
|
|
54
|
+
if (fields.length !== 5 && fields.length !== 6) {
|
|
55
|
+
throw new InvalidCronExpressionError(`A cron expression must have 5 fields (minute hour day-of-month month day-of-week), ` +
|
|
56
|
+
`or 6 fields with a leading seconds field, but ${fields.length} were provided.`, expression);
|
|
57
|
+
}
|
|
58
|
+
this.hasSecondsField = fields.length === 6;
|
|
59
|
+
let index = 0;
|
|
60
|
+
this.seconds = this.hasSecondsField
|
|
61
|
+
? this.parseField(fields[index++], 0, 59, "second", undefined, expression)
|
|
62
|
+
: new Set([0]);
|
|
63
|
+
this.minutes = this.parseField(fields[index++], 0, 59, "minute", undefined, expression);
|
|
64
|
+
this.hours = this.parseField(fields[index++], 0, 23, "hour", undefined, expression);
|
|
65
|
+
const dayOfMonthField = fields[index++];
|
|
66
|
+
this.daysOfMonth = this.parseField(dayOfMonthField, 1, 31, "day-of-month", undefined, expression);
|
|
67
|
+
this.months = this.parseField(fields[index++], 1, 12, "month", CronExpression.MONTH_NAMES, expression);
|
|
68
|
+
const dayOfWeekField = fields[index++];
|
|
69
|
+
this.daysOfWeek = this.parseDayOfWeek(dayOfWeekField, expression);
|
|
70
|
+
this.dayOfMonthRestricted = dayOfMonthField !== "*";
|
|
71
|
+
this.dayOfWeekRestricted = dayOfWeekField !== "*";
|
|
72
|
+
this.expression = normalized;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns whether an expression is valid without throwing — convenient for create-time
|
|
76
|
+
* validation of user input where a boolean is more ergonomic than a try/catch.
|
|
77
|
+
*/
|
|
78
|
+
static isValid(expression) {
|
|
79
|
+
try {
|
|
80
|
+
new CronExpression(expression);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error instanceof InvalidCronExpressionError) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Computes the next execution strictly after `from`.
|
|
92
|
+
* @param from The reference instant. Defaults to now.
|
|
93
|
+
* @returns The next matching `Date`, or `undefined` if the expression has no occurrence
|
|
94
|
+
* within the {@link CronExpression.MAX_SCAN_YEARS} scan window (i.e. it never matches,
|
|
95
|
+
* such as `0 0 30 2 *`).
|
|
96
|
+
*/
|
|
97
|
+
getNextExecutionDate(from = new Date()) {
|
|
98
|
+
if (!(from instanceof Date) || Number.isNaN(from.getTime())) {
|
|
99
|
+
throw new TypeError("CronExpression.getNextExecutionDate expects a valid Date.");
|
|
100
|
+
}
|
|
101
|
+
// Round strictly up to the next unit boundary. Epoch arithmetic is used here (rather
|
|
102
|
+
// than local-field arithmetic) so the rounding itself is immune to DST offsets; the
|
|
103
|
+
// subsequent field-walk is done with local-time constructors so it is DST-aware.
|
|
104
|
+
const unitMs = this.hasSecondsField ? 1000 : 60000;
|
|
105
|
+
let candidate = new Date(Math.floor(from.getTime() / unitMs) * unitMs + unitMs);
|
|
106
|
+
const maxYear = from.getFullYear() + CronExpression.MAX_SCAN_YEARS;
|
|
107
|
+
for (let iterations = 0; iterations < CronExpression.MAX_SCAN_ITERATIONS; iterations++) {
|
|
108
|
+
const year = candidate.getFullYear();
|
|
109
|
+
if (year > maxYear) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
// Each check that fails advances the smallest possible amount and resets every
|
|
113
|
+
// lower-order field to its minimum, then restarts the loop. This converges in a
|
|
114
|
+
// handful of iterations rather than scanning minute-by-minute.
|
|
115
|
+
if (!this.months.has(candidate.getMonth() + 1)) {
|
|
116
|
+
candidate = new Date(year, candidate.getMonth() + 1, 1, 0, 0, 0, 0);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (!this.matchesDay(candidate)) {
|
|
120
|
+
candidate = new Date(year, candidate.getMonth(), candidate.getDate() + 1, 0, 0, 0, 0);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (!this.hours.has(candidate.getHours())) {
|
|
124
|
+
candidate = new Date(year, candidate.getMonth(), candidate.getDate(), candidate.getHours() + 1, 0, 0, 0);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!this.minutes.has(candidate.getMinutes())) {
|
|
128
|
+
candidate = new Date(year, candidate.getMonth(), candidate.getDate(), candidate.getHours(), candidate.getMinutes() + 1, 0, 0);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (this.hasSecondsField && !this.seconds.has(candidate.getSeconds())) {
|
|
132
|
+
candidate = new Date(year, candidate.getMonth(), candidate.getDate(), candidate.getHours(), candidate.getMinutes(), candidate.getSeconds() + 1, 0);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
return candidate;
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Computes up to `count` successive execution dates starting strictly after `from`.
|
|
141
|
+
* Returns fewer than `count` (possibly zero) entries only if the expression stops
|
|
142
|
+
* matching within the scan window.
|
|
143
|
+
*/
|
|
144
|
+
getNextExecutionDates(from, count) {
|
|
145
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
146
|
+
throw new TypeError("CronExpression.getNextExecutionDates expects a non-negative integer count.");
|
|
147
|
+
}
|
|
148
|
+
const dates = [];
|
|
149
|
+
let cursor = from;
|
|
150
|
+
for (let i = 0; i < count; i++) {
|
|
151
|
+
const next = this.getNextExecutionDate(cursor);
|
|
152
|
+
if (next === undefined) {
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
dates.push(next);
|
|
156
|
+
cursor = next;
|
|
157
|
+
}
|
|
158
|
+
return dates;
|
|
159
|
+
}
|
|
160
|
+
/** Returns the normalized expression. */
|
|
161
|
+
toString() {
|
|
162
|
+
return this.expression;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Applies the day-of-month / day-of-week OR rule for a candidate date.
|
|
166
|
+
*/
|
|
167
|
+
matchesDay(date) {
|
|
168
|
+
const dayOfMonthMatches = this.daysOfMonth.has(date.getDate());
|
|
169
|
+
const dayOfWeekMatches = this.daysOfWeek.has(date.getDay());
|
|
170
|
+
if (this.dayOfMonthRestricted && this.dayOfWeekRestricted) {
|
|
171
|
+
return dayOfMonthMatches || dayOfWeekMatches;
|
|
172
|
+
}
|
|
173
|
+
return dayOfMonthMatches && dayOfWeekMatches;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Parses the day-of-week field, which is special-cased for the `0-7` range where both
|
|
177
|
+
* `0` and `7` mean Sunday. Values are parsed against `0-7` and then `7` is normalized to
|
|
178
|
+
* `0` so the resulting set aligns with `Date.getDay()`.
|
|
179
|
+
*/
|
|
180
|
+
parseDayOfWeek(field, original) {
|
|
181
|
+
const raw = this.parseField(field, 0, 7, "day-of-week", CronExpression.DAY_OF_WEEK_NAMES, original);
|
|
182
|
+
const normalized = new Set();
|
|
183
|
+
for (const value of raw) {
|
|
184
|
+
normalized.add(value === 7 ? 0 : value);
|
|
185
|
+
}
|
|
186
|
+
return normalized;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Parses a single cron field into the set of numeric values it allows.
|
|
190
|
+
*/
|
|
191
|
+
parseField(field, min, max, label, names, original) {
|
|
192
|
+
const values = new Set();
|
|
193
|
+
for (const segment of field.split(",")) {
|
|
194
|
+
if (segment.length === 0) {
|
|
195
|
+
throw new InvalidCronExpressionError(`The ${label} field '${field}' contains an empty list element.`, original, label);
|
|
196
|
+
}
|
|
197
|
+
// Split off an optional step (`.../n`).
|
|
198
|
+
let rangePart = segment;
|
|
199
|
+
let step = 1;
|
|
200
|
+
const slashIndex = segment.indexOf("/");
|
|
201
|
+
if (slashIndex !== -1) {
|
|
202
|
+
rangePart = segment.slice(0, slashIndex);
|
|
203
|
+
const stepPart = segment.slice(slashIndex + 1);
|
|
204
|
+
if (stepPart.indexOf("/") !== -1) {
|
|
205
|
+
throw new InvalidCronExpressionError(`The ${label} field element '${segment}' has more than one step.`, original, label);
|
|
206
|
+
}
|
|
207
|
+
if (!/^\d+$/.test(stepPart)) {
|
|
208
|
+
throw new InvalidCronExpressionError(`The ${label} field element '${segment}' has an invalid step '${stepPart}'.`, original, label);
|
|
209
|
+
}
|
|
210
|
+
step = parseInt(stepPart, 10);
|
|
211
|
+
if (step === 0) {
|
|
212
|
+
throw new InvalidCronExpressionError(`The ${label} field element '${segment}' has a step of 0; the step must be greater than 0.`, original, label);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Resolve the low/high bounds of this segment.
|
|
216
|
+
let low;
|
|
217
|
+
let high;
|
|
218
|
+
if (rangePart === "*") {
|
|
219
|
+
low = min;
|
|
220
|
+
high = max;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
const dashIndex = rangePart.indexOf("-");
|
|
224
|
+
if (dashIndex > 0) {
|
|
225
|
+
low = this.parseValue(rangePart.slice(0, dashIndex), min, max, label, names, original);
|
|
226
|
+
high = this.parseValue(rangePart.slice(dashIndex + 1), min, max, label, names, original);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
low = this.parseValue(rangePart, min, max, label, names, original);
|
|
230
|
+
// `a/n` (a single value with a step) means "from a up to the maximum, every n".
|
|
231
|
+
// A bare single value (`a`) is just that value.
|
|
232
|
+
high = slashIndex !== -1 ? max : low;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (low > high) {
|
|
236
|
+
throw new InvalidCronExpressionError(`The ${label} field element '${segment}' is a descending range (${low} > ${high}); ranges must be ascending.`, original, label);
|
|
237
|
+
}
|
|
238
|
+
for (let value = low; value <= high; value += step) {
|
|
239
|
+
values.add(value);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return values;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Parses one atomic token (a number or a name) and validates it is within range.
|
|
246
|
+
*/
|
|
247
|
+
parseValue(token, min, max, label, names, original) {
|
|
248
|
+
if (token.length === 0) {
|
|
249
|
+
throw new InvalidCronExpressionError(`The ${label} field has a malformed, empty value.`, original, label);
|
|
250
|
+
}
|
|
251
|
+
let value;
|
|
252
|
+
if (names !== undefined && /[a-zA-Z]/.test(token)) {
|
|
253
|
+
const resolved = names[token.toUpperCase()];
|
|
254
|
+
if (resolved === undefined) {
|
|
255
|
+
throw new InvalidCronExpressionError(`The ${label} field has an unknown name '${token}'.`, original, label);
|
|
256
|
+
}
|
|
257
|
+
value = resolved;
|
|
258
|
+
}
|
|
259
|
+
else if (/^\d+$/.test(token)) {
|
|
260
|
+
value = parseInt(token, 10);
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
throw new InvalidCronExpressionError(`The ${label} field has an invalid value '${token}'.`, original, label);
|
|
264
|
+
}
|
|
265
|
+
if (value < min || value > max) {
|
|
266
|
+
throw new InvalidCronExpressionError(`The ${label} field value '${token}' is out of range (${min}-${max}).`, original, label);
|
|
267
|
+
}
|
|
268
|
+
return value;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Case-insensitive month names accepted in the month field, mapped to their `1-12` value.
|
|
273
|
+
*/
|
|
274
|
+
CronExpression.MONTH_NAMES = {
|
|
275
|
+
JAN: 1, FEB: 2, MAR: 3, APR: 4, MAY: 5, JUN: 6,
|
|
276
|
+
JUL: 7, AUG: 8, SEP: 9, OCT: 10, NOV: 11, DEC: 12,
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* Case-insensitive day-of-week names accepted in the day-of-week field, mapped to their
|
|
280
|
+
* `0-6` value where `0` is Sunday (the classic cron convention).
|
|
281
|
+
*/
|
|
282
|
+
CronExpression.DAY_OF_WEEK_NAMES = {
|
|
283
|
+
SUN: 0, MON: 1, TUE: 2, WED: 3, THU: 4, FRI: 5, SAT: 6,
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* The upper bound (in years past the `from` date) of the forward scan performed when
|
|
287
|
+
* computing the next execution. Eight years is the largest gap between two consecutive
|
|
288
|
+
* occurrences of Feb 29 (e.g. 2096 → 2104, because 2100 is not a leap year), so any
|
|
289
|
+
* expression that ever matches is guaranteed to match within this window. An expression
|
|
290
|
+
* that does not match within it is treated as never-matching (e.g. `0 0 30 2 *`).
|
|
291
|
+
*/
|
|
292
|
+
CronExpression.MAX_SCAN_YEARS = 8;
|
|
293
|
+
/**
|
|
294
|
+
* A hard iteration ceiling on the forward scan, as a defensive backstop against an
|
|
295
|
+
* unforeseen non-advancing state. The scan advances by at least one calendar field per
|
|
296
|
+
* iteration and is really bounded by {@link CronExpression.MAX_SCAN_YEARS}; this ceiling
|
|
297
|
+
* only ever trips on a bug, never on legitimate input.
|
|
298
|
+
*/
|
|
299
|
+
CronExpression.MAX_SCAN_ITERATIONS = 1000000;
|
|
300
|
+
//# sourceMappingURL=cron-expression.model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-expression.model.js","sourceRoot":"","sources":["../../../../src/models/cron-expression.model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../../../../src/models/models.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { CronExpression } from "../models/cron-expression.model";
|
|
2
|
+
/**
|
|
3
|
+
* A recurring {@link ScheduleInterface} backed by a standard cron expression. Construct it
|
|
4
|
+
* from a cron string (parsed and validated immediately, throwing an
|
|
5
|
+
* {@link InvalidCronExpressionError} on bad input) or from an already-built
|
|
6
|
+
* {@link CronExpression}.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* new CronSchedule("0 3 * * *"); // 03:00 every day
|
|
10
|
+
* new CronSchedule("0/15 9-17 * * 1-5"); // every 15 minutes, 09:00-17:00, Mon-Fri
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export class CronSchedule {
|
|
14
|
+
constructor(cronExpression) {
|
|
15
|
+
// A string is parsed (and thereby validated) here, propagating an
|
|
16
|
+
// InvalidCronExpressionError (HTTP 400) for malformed input.
|
|
17
|
+
this.cronExpression = typeof cronExpression === "string" ? new CronExpression(cronExpression) : cronExpression;
|
|
18
|
+
}
|
|
19
|
+
getNextExecutionDate(from) {
|
|
20
|
+
return this.cronExpression.getNextExecutionDate(from);
|
|
21
|
+
}
|
|
22
|
+
/** Up to `count` successive occurrences after `from`. */
|
|
23
|
+
getNextExecutionDates(from, count) {
|
|
24
|
+
return this.cronExpression.getNextExecutionDates(from, count);
|
|
25
|
+
}
|
|
26
|
+
toString() {
|
|
27
|
+
return this.cronExpression.expression;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=cron.schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.schedule.js","sourceRoot":"","sources":["../../../../src/schedules/cron.schedule.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,iCAAiC,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,MAAM,OAAO,YAAY;IAIvB,YAAY,cAAuC;QACjD,kEAAkE;QAClE,6DAA6D;QAC7D,IAAI,CAAC,cAAc,GAAG,OAAO,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,cAAc,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;IACjH,CAAC;IAEM,oBAAoB,CAAC,IAAU;QACpC,OAAO,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IAED,yDAAyD;IAClD,qBAAqB,CAAC,IAAU,EAAE,KAAa;QACpD,OAAO,IAAI,CAAC,cAAc,CAAC,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;IAEM,QAAQ;QACb,OAAO,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC;IACxC,CAAC;CACF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A one-shot {@link ScheduleInterface} that fires a single time at a fixed instant. Once that
|
|
3
|
+
* instant has passed, {@link getNextExecutionDate} returns `undefined`, so the scheduler
|
|
4
|
+
* fires it once and then leaves it unarmed — it remains listed, with no next execution date.
|
|
5
|
+
*
|
|
6
|
+
* ```ts
|
|
7
|
+
* new DateSchedule(new Date("2026-12-31T23:59:00"));
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export class DateSchedule {
|
|
11
|
+
constructor(date) {
|
|
12
|
+
this.date = date;
|
|
13
|
+
}
|
|
14
|
+
getNextExecutionDate(from) {
|
|
15
|
+
// Strictly after `from`, mirroring cron semantics; a copy is returned so callers cannot
|
|
16
|
+
// mutate the schedule's own instant.
|
|
17
|
+
return this.date.getTime() > from.getTime() ? new Date(this.date.getTime()) : undefined;
|
|
18
|
+
}
|
|
19
|
+
toString() {
|
|
20
|
+
return this.date.toISOString();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=date.schedule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date.schedule.js","sourceRoot":"","sources":["../../../../src/schedules/date.schedule.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,OAAO,YAAY;IAIvB,YAAY,IAAU;QACpB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAEM,oBAAoB,CAAC,IAAU;QACpC,wFAAwF;QACxF,qCAAqC;QACrC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1F,CAAC;IAEM,QAAQ;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedules.js","sourceRoot":"","sources":["../../../../src/schedules/schedules.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
import { inject, injectable } from "tsyringe";
|
|
23
|
+
import { moduleScoped, ServiceDefinitionTagEnum, tag } from "@pristine-ts/common";
|
|
24
|
+
import { LocalSchedulingModuleKeyname } from "../local-scheduling.module.keyname";
|
|
25
|
+
/**
|
|
26
|
+
* Adapts {@link LocalSchedulerManager} to the `pristine start` lifecycle so tagged tasks run
|
|
27
|
+
* with no manual bootstrap.
|
|
28
|
+
*
|
|
29
|
+
* It is tagged {@link ServiceDefinitionTagEnum.RuntimeServer}, so `pristine start` resolves it
|
|
30
|
+
* alongside the HTTP/gRPC servers and calls `start()` — which registers every tagged
|
|
31
|
+
* {@link SchedulableInterface} and arms its timers. Graceful shutdown is wired via the
|
|
32
|
+
* module's `onShutdown`, which calls `stop()` to cancel timers and drain in-flight tasks.
|
|
33
|
+
*
|
|
34
|
+
* A scheduler has no socket, so the `--port` / `--address` overrides `pristine start`
|
|
35
|
+
* propagates are ignored.
|
|
36
|
+
*/
|
|
37
|
+
let LocalSchedulerRuntimeServer = class LocalSchedulerRuntimeServer {
|
|
38
|
+
constructor(scheduler, logHandler) {
|
|
39
|
+
this.scheduler = scheduler;
|
|
40
|
+
this.logHandler = logHandler;
|
|
41
|
+
/** Stable label for `pristine start` log lines and diagnostics. */
|
|
42
|
+
this.name = "local-scheduler";
|
|
43
|
+
}
|
|
44
|
+
start() {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
this.logHandler.info("LocalSchedulerRuntimeServer: starting the local scheduler.");
|
|
47
|
+
this.scheduler.start();
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
stop() {
|
|
51
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
this.logHandler.info("LocalSchedulerRuntimeServer: stopping the local scheduler.");
|
|
53
|
+
yield this.scheduler.stop();
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
LocalSchedulerRuntimeServer = __decorate([
|
|
58
|
+
tag(ServiceDefinitionTagEnum.RuntimeServer),
|
|
59
|
+
moduleScoped(LocalSchedulingModuleKeyname),
|
|
60
|
+
injectable(),
|
|
61
|
+
__param(0, inject("LocalSchedulerInterface")),
|
|
62
|
+
__param(1, inject("LogHandlerInterface")),
|
|
63
|
+
__metadata("design:paramtypes", [Object, Object])
|
|
64
|
+
], LocalSchedulerRuntimeServer);
|
|
65
|
+
export { LocalSchedulerRuntimeServer };
|
|
66
|
+
//# sourceMappingURL=local-scheduler.runtime-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-scheduler.runtime-server.js","sourceRoot":"","sources":["../../../../src/servers/local-scheduler.runtime-server.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAC,MAAM,EAAE,UAAU,EAAC,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAC,YAAY,EAAE,wBAAwB,EAAE,GAAG,EAAC,MAAM,qBAAqB,CAAC;AAGhF,OAAO,EAAC,4BAA4B,EAAC,MAAM,oCAAoC,CAAC;AAGhF;;;;;;;;;;;GAWG;AAII,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IAItC,YAA+C,SAAmD,EACvD,UAAgD;QAD3B,cAAS,GAAT,SAAS,CAAyB;QACtC,eAAU,GAAV,UAAU,CAAqB;QAJ3F,mEAAmE;QACnD,SAAI,GAAW,iBAAiB,CAAC;IAIjD,CAAC;IAEY,KAAK;;YAChB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YACnF,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QACzB,CAAC;KAAA;IAEY,IAAI;;YACf,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YACnF,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QAC9B,CAAC;KAAA;CACF,CAAA;AAjBY,2BAA2B;IAHvC,GAAG,CAAC,wBAAwB,CAAC,aAAa,CAAC;IAC3C,YAAY,CAAC,4BAA4B,CAAC;IAC1C,UAAU,EAAE;IAKE,WAAA,MAAM,CAAC,yBAAyB,CAAC,CAAA;IACjC,WAAA,MAAM,CAAC,qBAAqB,CAAC,CAAA;;GAL/B,2BAA2B,CAiBvC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"servers.js","sourceRoot":"","sources":["../../../../src/servers/servers.ts"],"names":[],"mappings":"AAAA,cAAc,kCAAkC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduled-task-function.type.js","sourceRoot":"","sources":["../../../../src/types/scheduled-task-function.type.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/types/types.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAC"}
|