@queuebase/core 1.3.0 → 1.5.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/dist/index.js CHANGED
@@ -8,13 +8,659 @@ function createJobRouter(jobs) {
8
8
  return jobs;
9
9
  }
10
10
 
11
- // ../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.js
12
- import { webcrypto as crypto } from "crypto";
13
-
14
- // ../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/url-alphabet/index.js
15
- var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
11
+ // ../../node_modules/.pnpm/croner@10.0.1/node_modules/croner/dist/croner.js
12
+ function T(s2) {
13
+ return Date.UTC(s2.y, s2.m - 1, s2.d, s2.h, s2.i, s2.s);
14
+ }
15
+ function D(s2, e) {
16
+ return s2.y === e.y && s2.m === e.m && s2.d === e.d && s2.h === e.h && s2.i === e.i && s2.s === e.s;
17
+ }
18
+ function A(s2, e) {
19
+ let t = new Date(Date.parse(s2));
20
+ if (isNaN(t)) throw new Error("Invalid ISO8601 passed to timezone parser.");
21
+ let r = s2.substring(9);
22
+ return r.includes("Z") || r.includes("+") || r.includes("-") ? b(t.getUTCFullYear(), t.getUTCMonth() + 1, t.getUTCDate(), t.getUTCHours(), t.getUTCMinutes(), t.getUTCSeconds(), "Etc/UTC") : b(t.getFullYear(), t.getMonth() + 1, t.getDate(), t.getHours(), t.getMinutes(), t.getSeconds(), e);
23
+ }
24
+ function v(s2, e, t) {
25
+ return k(A(s2, e), t);
26
+ }
27
+ function k(s2, e) {
28
+ let t = new Date(T(s2)), r = g(t, s2.tz), n = T(s2), i = T(r), a = n - i, o = new Date(t.getTime() + a), h = g(o, s2.tz);
29
+ if (D(h, s2)) {
30
+ let u = new Date(o.getTime() - 36e5), d = g(u, s2.tz);
31
+ return D(d, s2) ? u : o;
32
+ }
33
+ let l = new Date(o.getTime() + T(s2) - T(h)), y = g(l, s2.tz);
34
+ if (D(y, s2)) return l;
35
+ if (e) throw new Error("Invalid date passed to fromTZ()");
36
+ return o.getTime() > l.getTime() ? o : l;
37
+ }
38
+ function g(s2, e) {
39
+ let t, r;
40
+ try {
41
+ t = new Intl.DateTimeFormat("en-US", { timeZone: e, year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: "numeric", hour12: false }), r = t.formatToParts(s2);
42
+ } catch (i) {
43
+ let a = i instanceof Error ? i.message : String(i);
44
+ throw new RangeError(`toTZ: Invalid timezone '${e}' or date. Please provide a valid IANA timezone (e.g., 'America/New_York', 'Europe/Stockholm'). Original error: ${a}`);
45
+ }
46
+ let n = { year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0 };
47
+ for (let i of r) (i.type === "year" || i.type === "month" || i.type === "day" || i.type === "hour" || i.type === "minute" || i.type === "second") && (n[i.type] = parseInt(i.value, 10));
48
+ if (isNaN(n.year) || isNaN(n.month) || isNaN(n.day) || isNaN(n.hour) || isNaN(n.minute) || isNaN(n.second)) throw new Error(`toTZ: Failed to parse all date components from timezone '${e}'. This may indicate an invalid date or timezone configuration. Parsed components: ${JSON.stringify(n)}`);
49
+ return n.hour === 24 && (n.hour = 0), { y: n.year, m: n.month, d: n.day, h: n.hour, i: n.minute, s: n.second, tz: e };
50
+ }
51
+ function b(s2, e, t, r, n, i, a) {
52
+ return { y: s2, m: e, d: t, h: r, i: n, s: i, tz: a };
53
+ }
54
+ var O = [1, 2, 4, 8, 16];
55
+ var C = class {
56
+ pattern;
57
+ timezone;
58
+ mode;
59
+ alternativeWeekdays;
60
+ sloppyRanges;
61
+ second;
62
+ minute;
63
+ hour;
64
+ day;
65
+ month;
66
+ dayOfWeek;
67
+ year;
68
+ lastDayOfMonth;
69
+ lastWeekday;
70
+ nearestWeekdays;
71
+ starDOM;
72
+ starDOW;
73
+ starYear;
74
+ useAndLogic;
75
+ constructor(e, t, r) {
76
+ this.pattern = e, this.timezone = t, this.mode = r?.mode ?? "auto", this.alternativeWeekdays = r?.alternativeWeekdays ?? false, this.sloppyRanges = r?.sloppyRanges ?? false, this.second = Array(60).fill(0), this.minute = Array(60).fill(0), this.hour = Array(24).fill(0), this.day = Array(31).fill(0), this.month = Array(12).fill(0), this.dayOfWeek = Array(7).fill(0), this.year = Array(1e4).fill(0), this.lastDayOfMonth = false, this.lastWeekday = false, this.nearestWeekdays = Array(31).fill(0), this.starDOM = false, this.starDOW = false, this.starYear = false, this.useAndLogic = false, this.parse();
77
+ }
78
+ parse() {
79
+ if (!(typeof this.pattern == "string" || this.pattern instanceof String)) throw new TypeError("CronPattern: Pattern has to be of type string.");
80
+ this.pattern.indexOf("@") >= 0 && (this.pattern = this.handleNicknames(this.pattern).trim());
81
+ let e = this.pattern.match(/\S+/g) || [""], t = e.length;
82
+ if (e.length < 5 || e.length > 7) throw new TypeError("CronPattern: invalid configuration format ('" + this.pattern + "'), exactly five, six, or seven space separated parts are required.");
83
+ if (this.mode !== "auto") {
84
+ let n;
85
+ switch (this.mode) {
86
+ case "5-part":
87
+ n = 5;
88
+ break;
89
+ case "6-part":
90
+ n = 6;
91
+ break;
92
+ case "7-part":
93
+ n = 7;
94
+ break;
95
+ case "5-or-6-parts":
96
+ n = [5, 6];
97
+ break;
98
+ case "6-or-7-parts":
99
+ n = [6, 7];
100
+ break;
101
+ default:
102
+ n = 0;
103
+ }
104
+ if (!(Array.isArray(n) ? n.includes(t) : t === n)) {
105
+ let a = Array.isArray(n) ? n.join(" or ") : n.toString();
106
+ throw new TypeError(`CronPattern: mode '${this.mode}' requires exactly ${a} parts, but pattern '${this.pattern}' has ${t} parts.`);
107
+ }
108
+ }
109
+ if (e.length === 5 && e.unshift("0"), e.length === 6 && e.push("*"), e[3].toUpperCase() === "LW" ? (this.lastWeekday = true, e[3] = "") : e[3].toUpperCase().indexOf("L") >= 0 && (e[3] = e[3].replace(/L/gi, ""), this.lastDayOfMonth = true), e[3] == "*" && (this.starDOM = true), e[6] == "*" && (this.starYear = true), e[4].length >= 3 && (e[4] = this.replaceAlphaMonths(e[4])), e[5].length >= 3 && (e[5] = this.alternativeWeekdays ? this.replaceAlphaDaysQuartz(e[5]) : this.replaceAlphaDays(e[5])), e[5].startsWith("+") && (this.useAndLogic = true, e[5] = e[5].substring(1), e[5] === "")) throw new TypeError("CronPattern: Day-of-week field cannot be empty after '+' modifier.");
110
+ switch (e[5] == "*" && (this.starDOW = true), this.pattern.indexOf("?") >= 0 && (e[0] = e[0].replace(/\?/g, "*"), e[1] = e[1].replace(/\?/g, "*"), e[2] = e[2].replace(/\?/g, "*"), e[3] = e[3].replace(/\?/g, "*"), e[4] = e[4].replace(/\?/g, "*"), e[5] = e[5].replace(/\?/g, "*"), e[6] && (e[6] = e[6].replace(/\?/g, "*"))), this.mode) {
111
+ case "5-part":
112
+ e[0] = "0", e[6] = "*";
113
+ break;
114
+ case "6-part":
115
+ e[6] = "*";
116
+ break;
117
+ case "5-or-6-parts":
118
+ e[6] = "*";
119
+ break;
120
+ case "6-or-7-parts":
121
+ break;
122
+ case "7-part":
123
+ case "auto":
124
+ break;
125
+ }
126
+ this.throwAtIllegalCharacters(e), this.partToArray("second", e[0], 0, 1), this.partToArray("minute", e[1], 0, 1), this.partToArray("hour", e[2], 0, 1), this.partToArray("day", e[3], -1, 1), this.partToArray("month", e[4], -1, 1);
127
+ let r = this.alternativeWeekdays ? -1 : 0;
128
+ this.partToArray("dayOfWeek", e[5], r, 63), this.partToArray("year", e[6], 0, 1), !this.alternativeWeekdays && this.dayOfWeek[7] && (this.dayOfWeek[0] = this.dayOfWeek[7]);
129
+ }
130
+ partToArray(e, t, r, n) {
131
+ let i = this[e], a = e === "day" && this.lastDayOfMonth, o = e === "day" && this.lastWeekday;
132
+ if (t === "" && !a && !o) throw new TypeError("CronPattern: configuration entry " + e + " (" + t + ") is empty, check for trailing spaces.");
133
+ if (t === "*") return i.fill(n);
134
+ let h = t.split(",");
135
+ if (h.length > 1) for (let l = 0; l < h.length; l++) this.partToArray(e, h[l], r, n);
136
+ else t.indexOf("-") !== -1 && t.indexOf("/") !== -1 ? this.handleRangeWithStepping(t, e, r, n) : t.indexOf("-") !== -1 ? this.handleRange(t, e, r, n) : t.indexOf("/") !== -1 ? this.handleStepping(t, e, r, n) : t !== "" && this.handleNumber(t, e, r, n);
137
+ }
138
+ throwAtIllegalCharacters(e) {
139
+ for (let t = 0; t < e.length; t++) if ((t === 3 ? /[^/*0-9,\-WwLl]+/ : t === 5 ? /[^/*0-9,\-#Ll]+/ : /[^/*0-9,\-]+/).test(e[t])) throw new TypeError("CronPattern: configuration entry " + t + " (" + e[t] + ") contains illegal characters.");
140
+ }
141
+ handleNumber(e, t, r, n) {
142
+ let i = this.extractNth(e, t), a = e.toUpperCase().includes("W");
143
+ if (t !== "day" && a) throw new TypeError("CronPattern: Nearest weekday modifier (W) only allowed in day-of-month.");
144
+ a && (t = "nearestWeekdays");
145
+ let o = parseInt(i[0], 10) + r;
146
+ if (isNaN(o)) throw new TypeError("CronPattern: " + t + " is not a number: '" + e + "'");
147
+ this.setPart(t, o, i[1] || n);
148
+ }
149
+ setPart(e, t, r) {
150
+ if (!Object.prototype.hasOwnProperty.call(this, e)) throw new TypeError("CronPattern: Invalid part specified: " + e);
151
+ if (e === "dayOfWeek") {
152
+ if (t === 7 && (t = 0), t < 0 || t > 6) throw new RangeError("CronPattern: Invalid value for dayOfWeek: " + t);
153
+ this.setNthWeekdayOfMonth(t, r);
154
+ return;
155
+ }
156
+ if (e === "second" || e === "minute") {
157
+ if (t < 0 || t >= 60) throw new RangeError("CronPattern: Invalid value for " + e + ": " + t);
158
+ } else if (e === "hour") {
159
+ if (t < 0 || t >= 24) throw new RangeError("CronPattern: Invalid value for " + e + ": " + t);
160
+ } else if (e === "day" || e === "nearestWeekdays") {
161
+ if (t < 0 || t >= 31) throw new RangeError("CronPattern: Invalid value for " + e + ": " + t);
162
+ } else if (e === "month") {
163
+ if (t < 0 || t >= 12) throw new RangeError("CronPattern: Invalid value for " + e + ": " + t);
164
+ } else if (e === "year" && (t < 1 || t >= 1e4)) throw new RangeError("CronPattern: Invalid value for " + e + ": " + t + " (supported range: 1-9999)");
165
+ this[e][t] = r;
166
+ }
167
+ validateNotNaN(e, t) {
168
+ if (isNaN(e)) throw new TypeError(t);
169
+ }
170
+ validateRange(e, t, r, n, i) {
171
+ if (e > t) throw new TypeError("CronPattern: From value is larger than to value: '" + i + "'");
172
+ if (r !== void 0) {
173
+ if (r === 0) throw new TypeError("CronPattern: Syntax error, illegal stepping: 0");
174
+ if (r > this[n].length) throw new TypeError("CronPattern: Syntax error, steps cannot be greater than maximum value of part (" + this[n].length + ")");
175
+ }
176
+ }
177
+ handleRangeWithStepping(e, t, r, n) {
178
+ if (e.toUpperCase().includes("W")) throw new TypeError("CronPattern: Syntax error, W is not allowed in ranges with stepping.");
179
+ let i = this.extractNth(e, t), a = i[0].match(/^(\d+)-(\d+)\/(\d+)$/);
180
+ if (a === null) throw new TypeError("CronPattern: Syntax error, illegal range with stepping: '" + e + "'");
181
+ let [, o, h, l] = a, y = parseInt(o, 10) + r, u = parseInt(h, 10) + r, d = parseInt(l, 10);
182
+ this.validateNotNaN(y, "CronPattern: Syntax error, illegal lower range (NaN)"), this.validateNotNaN(u, "CronPattern: Syntax error, illegal upper range (NaN)"), this.validateNotNaN(d, "CronPattern: Syntax error, illegal stepping: (NaN)"), this.validateRange(y, u, d, t, e);
183
+ for (let c = y; c <= u; c += d) this.setPart(t, c, i[1] || n);
184
+ }
185
+ extractNth(e, t) {
186
+ let r = e, n;
187
+ if (r.includes("#")) {
188
+ if (t !== "dayOfWeek") throw new Error("CronPattern: nth (#) only allowed in day-of-week field");
189
+ n = r.split("#")[1], r = r.split("#")[0];
190
+ } else if (r.toUpperCase().endsWith("L")) {
191
+ if (t !== "dayOfWeek") throw new Error("CronPattern: L modifier only allowed in day-of-week field (use L alone for day-of-month)");
192
+ n = "L", r = r.slice(0, -1);
193
+ }
194
+ return [r, n];
195
+ }
196
+ handleRange(e, t, r, n) {
197
+ if (e.toUpperCase().includes("W")) throw new TypeError("CronPattern: Syntax error, W is not allowed in a range.");
198
+ let i = this.extractNth(e, t), a = i[0].split("-");
199
+ if (a.length !== 2) throw new TypeError("CronPattern: Syntax error, illegal range: '" + e + "'");
200
+ let o = parseInt(a[0], 10) + r, h = parseInt(a[1], 10) + r;
201
+ this.validateNotNaN(o, "CronPattern: Syntax error, illegal lower range (NaN)"), this.validateNotNaN(h, "CronPattern: Syntax error, illegal upper range (NaN)"), this.validateRange(o, h, void 0, t, e);
202
+ for (let l = o; l <= h; l++) this.setPart(t, l, i[1] || n);
203
+ }
204
+ handleStepping(e, t, r, n) {
205
+ if (e.toUpperCase().includes("W")) throw new TypeError("CronPattern: Syntax error, W is not allowed in parts with stepping.");
206
+ let i = this.extractNth(e, t), a = i[0].split("/");
207
+ if (a.length !== 2) throw new TypeError("CronPattern: Syntax error, illegal stepping: '" + e + "'");
208
+ if (this.sloppyRanges) a[0] === "" && (a[0] = "*");
209
+ else {
210
+ if (a[0] === "") throw new TypeError("CronPattern: Syntax error, stepping with missing prefix ('" + e + "') is not allowed. Use wildcard (*/step) or range (min-max/step) instead.");
211
+ if (a[0] !== "*") throw new TypeError("CronPattern: Syntax error, stepping with numeric prefix ('" + e + "') is not allowed. Use wildcard (*/step) or range (min-max/step) instead.");
212
+ }
213
+ let o = 0;
214
+ a[0] !== "*" && (o = parseInt(a[0], 10) + r);
215
+ let h = parseInt(a[1], 10);
216
+ this.validateNotNaN(h, "CronPattern: Syntax error, illegal stepping: (NaN)"), this.validateRange(0, this[t].length - 1, h, t, e);
217
+ for (let l = o; l < this[t].length; l += h) this.setPart(t, l, i[1] || n);
218
+ }
219
+ replaceAlphaDays(e) {
220
+ return e.replace(/-sun/gi, "-7").replace(/sun/gi, "0").replace(/mon/gi, "1").replace(/tue/gi, "2").replace(/wed/gi, "3").replace(/thu/gi, "4").replace(/fri/gi, "5").replace(/sat/gi, "6");
221
+ }
222
+ replaceAlphaDaysQuartz(e) {
223
+ return e.replace(/sun/gi, "1").replace(/mon/gi, "2").replace(/tue/gi, "3").replace(/wed/gi, "4").replace(/thu/gi, "5").replace(/fri/gi, "6").replace(/sat/gi, "7");
224
+ }
225
+ replaceAlphaMonths(e) {
226
+ return e.replace(/jan/gi, "1").replace(/feb/gi, "2").replace(/mar/gi, "3").replace(/apr/gi, "4").replace(/may/gi, "5").replace(/jun/gi, "6").replace(/jul/gi, "7").replace(/aug/gi, "8").replace(/sep/gi, "9").replace(/oct/gi, "10").replace(/nov/gi, "11").replace(/dec/gi, "12");
227
+ }
228
+ handleNicknames(e) {
229
+ let t = e.trim().toLowerCase();
230
+ if (t === "@yearly" || t === "@annually") return "0 0 1 1 *";
231
+ if (t === "@monthly") return "0 0 1 * *";
232
+ if (t === "@weekly") return "0 0 * * 0";
233
+ if (t === "@daily" || t === "@midnight") return "0 0 * * *";
234
+ if (t === "@hourly") return "0 * * * *";
235
+ if (t === "@reboot") throw new TypeError("CronPattern: @reboot is not supported in this environment. This is an event-based trigger that requires system startup detection.");
236
+ return e;
237
+ }
238
+ setNthWeekdayOfMonth(e, t) {
239
+ if (typeof t != "number" && t.toUpperCase() === "L") this.dayOfWeek[e] = this.dayOfWeek[e] | 32;
240
+ else if (t === 63) this.dayOfWeek[e] = 63;
241
+ else if (t < 6 && t > 0) this.dayOfWeek[e] = this.dayOfWeek[e] | O[t - 1];
242
+ else throw new TypeError(`CronPattern: nth weekday out of range, should be 1-5 or L. Value: ${t}, Type: ${typeof t}`);
243
+ }
244
+ };
245
+ var P = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
246
+ var f = [["month", "year", 0], ["day", "month", -1], ["hour", "day", 0], ["minute", "hour", 0], ["second", "minute", 0]];
247
+ var m = class s {
248
+ tz;
249
+ ms;
250
+ second;
251
+ minute;
252
+ hour;
253
+ day;
254
+ month;
255
+ year;
256
+ constructor(e, t) {
257
+ if (this.tz = t, e && e instanceof Date) if (!isNaN(e)) this.fromDate(e);
258
+ else throw new TypeError("CronDate: Invalid date passed to CronDate constructor");
259
+ else if (e == null) this.fromDate(/* @__PURE__ */ new Date());
260
+ else if (e && typeof e == "string") this.fromString(e);
261
+ else if (e instanceof s) this.fromCronDate(e);
262
+ else throw new TypeError("CronDate: Invalid type (" + typeof e + ") passed to CronDate constructor");
263
+ }
264
+ getLastDayOfMonth(e, t) {
265
+ return t !== 1 ? P[t] : new Date(Date.UTC(e, t + 1, 0)).getUTCDate();
266
+ }
267
+ getLastWeekday(e, t) {
268
+ let r = this.getLastDayOfMonth(e, t), i = new Date(Date.UTC(e, t, r)).getUTCDay();
269
+ return i === 0 ? r - 2 : i === 6 ? r - 1 : r;
270
+ }
271
+ getNearestWeekday(e, t, r) {
272
+ let n = this.getLastDayOfMonth(e, t);
273
+ if (r > n) return -1;
274
+ let a = new Date(Date.UTC(e, t, r)).getUTCDay();
275
+ return a === 0 ? r === n ? r - 2 : r + 1 : a === 6 ? r === 1 ? r + 2 : r - 1 : r;
276
+ }
277
+ isNthWeekdayOfMonth(e, t, r, n) {
278
+ let a = new Date(Date.UTC(e, t, r)).getUTCDay(), o = 0;
279
+ for (let h = 1; h <= r; h++) new Date(Date.UTC(e, t, h)).getUTCDay() === a && o++;
280
+ if (n & 63 && O[o - 1] & n) return true;
281
+ if (n & 32) {
282
+ let h = this.getLastDayOfMonth(e, t);
283
+ for (let l = r + 1; l <= h; l++) if (new Date(Date.UTC(e, t, l)).getUTCDay() === a) return false;
284
+ return true;
285
+ }
286
+ return false;
287
+ }
288
+ fromDate(e) {
289
+ if (this.tz !== void 0) if (typeof this.tz == "number") this.ms = e.getUTCMilliseconds(), this.second = e.getUTCSeconds(), this.minute = e.getUTCMinutes() + this.tz, this.hour = e.getUTCHours(), this.day = e.getUTCDate(), this.month = e.getUTCMonth(), this.year = e.getUTCFullYear(), this.apply();
290
+ else try {
291
+ let t = g(e, this.tz);
292
+ this.ms = e.getMilliseconds(), this.second = t.s, this.minute = t.i, this.hour = t.h, this.day = t.d, this.month = t.m - 1, this.year = t.y;
293
+ } catch (t) {
294
+ let r = t instanceof Error ? t.message : String(t);
295
+ throw new TypeError(`CronDate: Failed to convert date to timezone '${this.tz}'. This may happen with invalid timezone names or dates. Original error: ${r}`);
296
+ }
297
+ else this.ms = e.getMilliseconds(), this.second = e.getSeconds(), this.minute = e.getMinutes(), this.hour = e.getHours(), this.day = e.getDate(), this.month = e.getMonth(), this.year = e.getFullYear();
298
+ }
299
+ fromCronDate(e) {
300
+ this.tz = e.tz, this.year = e.year, this.month = e.month, this.day = e.day, this.hour = e.hour, this.minute = e.minute, this.second = e.second, this.ms = e.ms;
301
+ }
302
+ apply() {
303
+ if (this.month > 11 || this.month < 0 || this.day > P[this.month] || this.day < 1 || this.hour > 59 || this.minute > 59 || this.second > 59 || this.hour < 0 || this.minute < 0 || this.second < 0) {
304
+ let e = new Date(Date.UTC(this.year, this.month, this.day, this.hour, this.minute, this.second, this.ms));
305
+ return this.ms = e.getUTCMilliseconds(), this.second = e.getUTCSeconds(), this.minute = e.getUTCMinutes(), this.hour = e.getUTCHours(), this.day = e.getUTCDate(), this.month = e.getUTCMonth(), this.year = e.getUTCFullYear(), true;
306
+ } else return false;
307
+ }
308
+ fromString(e) {
309
+ if (typeof this.tz == "number") {
310
+ let t = v(e);
311
+ this.ms = t.getUTCMilliseconds(), this.second = t.getUTCSeconds(), this.minute = t.getUTCMinutes(), this.hour = t.getUTCHours(), this.day = t.getUTCDate(), this.month = t.getUTCMonth(), this.year = t.getUTCFullYear(), this.apply();
312
+ } else return this.fromDate(v(e, this.tz));
313
+ }
314
+ findNext(e, t, r, n) {
315
+ return this._findMatch(e, t, r, n, 1);
316
+ }
317
+ _findMatch(e, t, r, n, i) {
318
+ let a = this[t], o;
319
+ r.lastDayOfMonth && (o = this.getLastDayOfMonth(this.year, this.month));
320
+ let h = !r.starDOW && t == "day" ? new Date(Date.UTC(this.year, this.month, 1, 0, 0, 0, 0)).getUTCDay() : void 0, l = this[t] + n, y = i === 1 ? (u) => u < r[t].length : (u) => u >= 0;
321
+ for (let u = l; y(u); u += i) {
322
+ let d = r[t][u];
323
+ if (t === "day" && !d) {
324
+ for (let c = 0; c < r.nearestWeekdays.length; c++) if (r.nearestWeekdays[c]) {
325
+ let M = this.getNearestWeekday(this.year, this.month, c - n);
326
+ if (M === -1) continue;
327
+ if (M === u - n) {
328
+ d = 1;
329
+ break;
330
+ }
331
+ }
332
+ }
333
+ if (t === "day" && r.lastWeekday) {
334
+ let c = this.getLastWeekday(this.year, this.month);
335
+ u - n === c && (d = 1);
336
+ }
337
+ if (t === "day" && r.lastDayOfMonth && u - n == o && (d = 1), t === "day" && !r.starDOW) {
338
+ let c = r.dayOfWeek[(h + (u - n - 1)) % 7];
339
+ if (c && c & 63) c = this.isNthWeekdayOfMonth(this.year, this.month, u - n, c) ? 1 : 0;
340
+ else if (c) throw new Error(`CronDate: Invalid value for dayOfWeek encountered. ${c}`);
341
+ r.useAndLogic ? d = d && c : !e.domAndDow && !r.starDOM ? d = d || c : d = d && c;
342
+ }
343
+ if (d) return this[t] = u - n, a !== this[t] ? 2 : 1;
344
+ }
345
+ return 3;
346
+ }
347
+ recurse(e, t, r) {
348
+ if (r === 0 && !e.starYear) {
349
+ if (this.year >= 0 && this.year < e.year.length && e.year[this.year] === 0) {
350
+ let i = -1;
351
+ for (let a = this.year + 1; a < e.year.length && a < 1e4; a++) if (e.year[a] === 1) {
352
+ i = a;
353
+ break;
354
+ }
355
+ if (i === -1) return null;
356
+ this.year = i, this.month = 0, this.day = 1, this.hour = 0, this.minute = 0, this.second = 0, this.ms = 0;
357
+ }
358
+ if (this.year >= 1e4) return null;
359
+ }
360
+ let n = this.findNext(t, f[r][0], e, f[r][2]);
361
+ if (n > 1) {
362
+ let i = r + 1;
363
+ for (; i < f.length; ) this[f[i][0]] = -f[i][2], i++;
364
+ if (n === 3) {
365
+ if (this[f[r][1]]++, this[f[r][0]] = -f[r][2], this.apply(), r === 0 && !e.starYear) {
366
+ for (; this.year >= 0 && this.year < e.year.length && e.year[this.year] === 0 && this.year < 1e4; ) this.year++;
367
+ if (this.year >= 1e4 || this.year >= e.year.length) return null;
368
+ }
369
+ return this.recurse(e, t, 0);
370
+ } else if (this.apply()) return this.recurse(e, t, r - 1);
371
+ }
372
+ return r += 1, r >= f.length ? this : (e.starYear ? this.year >= 3e3 : this.year >= 1e4) ? null : this.recurse(e, t, r);
373
+ }
374
+ increment(e, t, r) {
375
+ return this.second += t.interval !== void 0 && t.interval > 1 && r ? t.interval : 1, this.ms = 0, this.apply(), this.recurse(e, t, 0);
376
+ }
377
+ decrement(e, t) {
378
+ return this.second -= t.interval !== void 0 && t.interval > 1 ? t.interval : 1, this.ms = 0, this.apply(), this.recurseBackward(e, t, 0, 0);
379
+ }
380
+ recurseBackward(e, t, r, n = 0) {
381
+ if (n > 1e4) return null;
382
+ if (r === 0 && !e.starYear) {
383
+ if (this.year >= 0 && this.year < e.year.length && e.year[this.year] === 0) {
384
+ let a = -1;
385
+ for (let o = this.year - 1; o >= 0; o--) if (e.year[o] === 1) {
386
+ a = o;
387
+ break;
388
+ }
389
+ if (a === -1) return null;
390
+ this.year = a, this.month = 11, this.day = 31, this.hour = 23, this.minute = 59, this.second = 59, this.ms = 0;
391
+ }
392
+ if (this.year < 0) return null;
393
+ }
394
+ let i = this.findPrevious(t, f[r][0], e, f[r][2]);
395
+ if (i > 1) {
396
+ let a = r + 1;
397
+ for (; a < f.length; ) {
398
+ let o = f[a][0], h = f[a][2], l = this.getMaxPatternValue(o, e, h);
399
+ this[o] = l, a++;
400
+ }
401
+ if (i === 3) {
402
+ if (this[f[r][1]]--, r === 0) {
403
+ let y = this.getLastDayOfMonth(this.year, this.month);
404
+ this.day > y && (this.day = y);
405
+ }
406
+ if (r === 1) if (this.day <= 0) this.day = 1;
407
+ else {
408
+ let y = this.year, u = this.month;
409
+ for (; u < 0; ) u += 12, y--;
410
+ for (; u > 11; ) u -= 12, y++;
411
+ let d = u !== 1 ? P[u] : new Date(Date.UTC(y, u + 1, 0)).getUTCDate();
412
+ this.day > d && (this.day = d);
413
+ }
414
+ this.apply();
415
+ let o = f[r][0], h = f[r][2], l = this.getMaxPatternValue(o, e, h);
416
+ if (o === "day") {
417
+ let y = this.getLastDayOfMonth(this.year, this.month);
418
+ this[o] = Math.min(l, y);
419
+ } else this[o] = l;
420
+ if (this.apply(), r === 0) {
421
+ let y = f[1][2], u = this.getMaxPatternValue("day", e, y), d = this.getLastDayOfMonth(this.year, this.month), c = Math.min(u, d);
422
+ c !== this.day && (this.day = c, this.hour = this.getMaxPatternValue("hour", e, f[2][2]), this.minute = this.getMaxPatternValue("minute", e, f[3][2]), this.second = this.getMaxPatternValue("second", e, f[4][2]));
423
+ }
424
+ if (r === 0 && !e.starYear) {
425
+ for (; this.year >= 0 && this.year < e.year.length && e.year[this.year] === 0; ) this.year--;
426
+ if (this.year < 0) return null;
427
+ }
428
+ return this.recurseBackward(e, t, 0, n + 1);
429
+ } else if (this.apply()) return this.recurseBackward(e, t, r - 1, n + 1);
430
+ }
431
+ return r += 1, r >= f.length ? this : this.year < 0 ? null : this.recurseBackward(e, t, r, n + 1);
432
+ }
433
+ getMaxPatternValue(e, t, r) {
434
+ if (e === "day" && t.lastDayOfMonth) return this.getLastDayOfMonth(this.year, this.month);
435
+ if (e === "day" && !t.starDOW) return this.getLastDayOfMonth(this.year, this.month);
436
+ for (let n = t[e].length - 1; n >= 0; n--) if (t[e][n]) return n - r;
437
+ return t[e].length - 1 - r;
438
+ }
439
+ findPrevious(e, t, r, n) {
440
+ return this._findMatch(e, t, r, n, -1);
441
+ }
442
+ getDate(e) {
443
+ return e || this.tz === void 0 ? new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.ms) : typeof this.tz == "number" ? new Date(Date.UTC(this.year, this.month, this.day, this.hour, this.minute - this.tz, this.second, this.ms)) : k(b(this.year, this.month + 1, this.day, this.hour, this.minute, this.second, this.tz), false);
444
+ }
445
+ getTime() {
446
+ return this.getDate(false).getTime();
447
+ }
448
+ match(e, t) {
449
+ if (!e.starYear && (this.year < 0 || this.year >= e.year.length || e.year[this.year] === 0)) return false;
450
+ for (let r = 0; r < f.length; r++) {
451
+ let n = f[r][0], i = f[r][2], a = this[n];
452
+ if (a + i < 0 || a + i >= e[n].length) return false;
453
+ let o = e[n][a + i];
454
+ if (n === "day") {
455
+ if (!o) {
456
+ for (let h = 0; h < e.nearestWeekdays.length; h++) if (e.nearestWeekdays[h]) {
457
+ let l = this.getNearestWeekday(this.year, this.month, h - i);
458
+ if (l !== -1 && l === a) {
459
+ o = 1;
460
+ break;
461
+ }
462
+ }
463
+ }
464
+ if (e.lastWeekday) {
465
+ let h = this.getLastWeekday(this.year, this.month);
466
+ a === h && (o = 1);
467
+ }
468
+ if (e.lastDayOfMonth) {
469
+ let h = this.getLastDayOfMonth(this.year, this.month);
470
+ a === h && (o = 1);
471
+ }
472
+ if (!e.starDOW) {
473
+ let h = new Date(Date.UTC(this.year, this.month, 1, 0, 0, 0, 0)).getUTCDay(), l = e.dayOfWeek[(h + (a - 1)) % 7];
474
+ l && l & 63 && (l = this.isNthWeekdayOfMonth(this.year, this.month, a, l) ? 1 : 0), e.useAndLogic ? o = o && l : !t.domAndDow && !e.starDOM ? o = o || l : o = o && l;
475
+ }
476
+ }
477
+ if (!o) return false;
478
+ }
479
+ return true;
480
+ }
481
+ };
482
+ function R(s2) {
483
+ if (s2 === void 0 && (s2 = {}), delete s2.name, s2.legacyMode !== void 0 && s2.domAndDow === void 0 ? s2.domAndDow = !s2.legacyMode : s2.domAndDow === void 0 && (s2.domAndDow = false), s2.legacyMode = !s2.domAndDow, s2.paused = s2.paused === void 0 ? false : s2.paused, s2.maxRuns = s2.maxRuns === void 0 ? 1 / 0 : s2.maxRuns, s2.catch = s2.catch === void 0 ? false : s2.catch, s2.interval = s2.interval === void 0 ? 0 : parseInt(s2.interval.toString(), 10), s2.utcOffset = s2.utcOffset === void 0 ? void 0 : parseInt(s2.utcOffset.toString(), 10), s2.dayOffset = s2.dayOffset === void 0 ? 0 : parseInt(s2.dayOffset.toString(), 10), s2.unref = s2.unref === void 0 ? false : s2.unref, s2.mode = s2.mode === void 0 ? "auto" : s2.mode, s2.alternativeWeekdays = s2.alternativeWeekdays === void 0 ? false : s2.alternativeWeekdays, s2.sloppyRanges = s2.sloppyRanges === void 0 ? false : s2.sloppyRanges, !["auto", "5-part", "6-part", "7-part", "5-or-6-parts", "6-or-7-parts"].includes(s2.mode)) throw new Error("CronOptions: mode must be one of 'auto', '5-part', '6-part', '7-part', '5-or-6-parts', or '6-or-7-parts'.");
484
+ if (s2.startAt && (s2.startAt = new m(s2.startAt, s2.timezone)), s2.stopAt && (s2.stopAt = new m(s2.stopAt, s2.timezone)), s2.interval !== null) {
485
+ if (isNaN(s2.interval)) throw new Error("CronOptions: Supplied value for interval is not a number");
486
+ if (s2.interval < 0) throw new Error("CronOptions: Supplied value for interval can not be negative");
487
+ }
488
+ if (s2.utcOffset !== void 0) {
489
+ if (isNaN(s2.utcOffset)) throw new Error("CronOptions: Invalid value passed for utcOffset, should be number representing minutes offset from UTC.");
490
+ if (s2.utcOffset < -870 || s2.utcOffset > 870) throw new Error("CronOptions: utcOffset out of bounds.");
491
+ if (s2.utcOffset !== void 0 && s2.timezone) throw new Error("CronOptions: Combining 'utcOffset' with 'timezone' is not allowed.");
492
+ }
493
+ if (s2.unref !== true && s2.unref !== false) throw new Error("CronOptions: Unref should be either true, false or undefined(false).");
494
+ if (s2.dayOffset !== void 0 && s2.dayOffset !== 0 && isNaN(s2.dayOffset)) throw new Error("CronOptions: Invalid value passed for dayOffset, should be a number representing days to offset.");
495
+ return s2;
496
+ }
497
+ function p(s2) {
498
+ return Object.prototype.toString.call(s2) === "[object Function]" || typeof s2 == "function" || s2 instanceof Function;
499
+ }
500
+ function _(s2) {
501
+ return p(s2);
502
+ }
503
+ function x(s2) {
504
+ typeof Deno < "u" && typeof Deno.unrefTimer < "u" ? Deno.unrefTimer(s2) : s2 && typeof s2.unref < "u" && s2.unref();
505
+ }
506
+ var W = 30 * 1e3;
507
+ var w = [];
508
+ var E = class {
509
+ name;
510
+ options;
511
+ _states;
512
+ fn;
513
+ getTz() {
514
+ return this.options.timezone || this.options.utcOffset;
515
+ }
516
+ applyDayOffset(e) {
517
+ if (this.options.dayOffset !== void 0 && this.options.dayOffset !== 0) {
518
+ let t = this.options.dayOffset * 24 * 60 * 60 * 1e3;
519
+ return new Date(e.getTime() + t);
520
+ }
521
+ return e;
522
+ }
523
+ constructor(e, t, r) {
524
+ let n, i;
525
+ if (p(t)) i = t;
526
+ else if (typeof t == "object") n = t;
527
+ else if (t !== void 0) throw new Error("Cron: Invalid argument passed for optionsIn. Should be one of function, or object (options).");
528
+ if (p(r)) i = r;
529
+ else if (typeof r == "object") n = r;
530
+ else if (r !== void 0) throw new Error("Cron: Invalid argument passed for funcIn. Should be one of function, or object (options).");
531
+ if (this.name = n?.name, this.options = R(n), this._states = { kill: false, blocking: false, previousRun: void 0, currentRun: void 0, once: void 0, currentTimeout: void 0, maxRuns: n ? n.maxRuns : void 0, paused: n ? n.paused : false, pattern: new C("* * * * *", void 0, { mode: "auto" }) }, e && (e instanceof Date || typeof e == "string" && e.indexOf(":") > 0) ? this._states.once = new m(e, this.getTz()) : this._states.pattern = new C(e, this.options.timezone, { mode: this.options.mode, alternativeWeekdays: this.options.alternativeWeekdays, sloppyRanges: this.options.sloppyRanges }), this.name) {
532
+ if (w.find((o) => o.name === this.name)) throw new Error("Cron: Tried to initialize new named job '" + this.name + "', but name already taken.");
533
+ w.push(this);
534
+ }
535
+ return i !== void 0 && _(i) && (this.fn = i, this.schedule()), this;
536
+ }
537
+ nextRun(e) {
538
+ let t = this._next(e);
539
+ return t ? this.applyDayOffset(t.getDate(false)) : null;
540
+ }
541
+ nextRuns(e, t) {
542
+ this._states.maxRuns !== void 0 && e > this._states.maxRuns && (e = this._states.maxRuns);
543
+ let r = t || this._states.currentRun || void 0;
544
+ return this._enumerateRuns(e, r, "next");
545
+ }
546
+ previousRuns(e, t) {
547
+ return this._enumerateRuns(e, t || void 0, "previous");
548
+ }
549
+ _enumerateRuns(e, t, r) {
550
+ let n = [], i = t ? new m(t, this.getTz()) : null, a = r === "next" ? this._next : this._previous;
551
+ for (; e--; ) {
552
+ let o = a.call(this, i);
553
+ if (!o) break;
554
+ let h = o.getDate(false);
555
+ n.push(this.applyDayOffset(h)), i = o;
556
+ }
557
+ return n;
558
+ }
559
+ match(e) {
560
+ if (this._states.once) {
561
+ let r = new m(e, this.getTz());
562
+ r.ms = 0;
563
+ let n = new m(this._states.once, this.getTz());
564
+ return n.ms = 0, r.getTime() === n.getTime();
565
+ }
566
+ let t = new m(e, this.getTz());
567
+ return t.ms = 0, t.match(this._states.pattern, this.options);
568
+ }
569
+ getPattern() {
570
+ if (!this._states.once) return this._states.pattern ? this._states.pattern.pattern : void 0;
571
+ }
572
+ getOnce() {
573
+ return this._states.once ? this._states.once.getDate() : null;
574
+ }
575
+ isRunning() {
576
+ let e = this.nextRun(this._states.currentRun), t = !this._states.paused, r = this.fn !== void 0, n = !this._states.kill;
577
+ return t && r && n && e !== null;
578
+ }
579
+ isStopped() {
580
+ return this._states.kill;
581
+ }
582
+ isBusy() {
583
+ return this._states.blocking;
584
+ }
585
+ currentRun() {
586
+ return this._states.currentRun ? this._states.currentRun.getDate() : null;
587
+ }
588
+ previousRun() {
589
+ return this._states.previousRun ? this._states.previousRun.getDate() : null;
590
+ }
591
+ msToNext(e) {
592
+ let t = this._next(e);
593
+ return t ? e instanceof m || e instanceof Date ? t.getTime() - e.getTime() : t.getTime() - new m(e).getTime() : null;
594
+ }
595
+ stop() {
596
+ this._states.kill = true, this._states.currentTimeout && clearTimeout(this._states.currentTimeout);
597
+ let e = w.indexOf(this);
598
+ e >= 0 && w.splice(e, 1);
599
+ }
600
+ pause() {
601
+ return this._states.paused = true, !this._states.kill;
602
+ }
603
+ resume() {
604
+ return this._states.paused = false, !this._states.kill;
605
+ }
606
+ schedule(e) {
607
+ if (e && this.fn) throw new Error("Cron: It is not allowed to schedule two functions using the same Croner instance.");
608
+ e && (this.fn = e);
609
+ let t = this.msToNext(), r = this.nextRun(this._states.currentRun);
610
+ return t == null || isNaN(t) || r === null ? this : (t > W && (t = W), this._states.currentTimeout = setTimeout(() => this._checkTrigger(r), t), this._states.currentTimeout && this.options.unref && x(this._states.currentTimeout), this);
611
+ }
612
+ async _trigger(e) {
613
+ this._states.blocking = true, this._states.currentRun = new m(void 0, this.getTz());
614
+ try {
615
+ if (this.options.catch) try {
616
+ this.fn !== void 0 && await this.fn(this, this.options.context);
617
+ } catch (t) {
618
+ if (p(this.options.catch)) try {
619
+ this.options.catch(t, this);
620
+ } catch {
621
+ }
622
+ }
623
+ else this.fn !== void 0 && await this.fn(this, this.options.context);
624
+ } finally {
625
+ this._states.previousRun = new m(e, this.getTz()), this._states.blocking = false;
626
+ }
627
+ }
628
+ async trigger() {
629
+ await this._trigger();
630
+ }
631
+ runsLeft() {
632
+ return this._states.maxRuns;
633
+ }
634
+ _checkTrigger(e) {
635
+ let t = /* @__PURE__ */ new Date(), r = !this._states.paused && t.getTime() >= e.getTime(), n = this._states.blocking && this.options.protect;
636
+ r && !n ? (this._states.maxRuns !== void 0 && this._states.maxRuns--, this._trigger()) : r && n && p(this.options.protect) && setTimeout(() => this.options.protect(this), 0), this.schedule();
637
+ }
638
+ _next(e) {
639
+ let t = !!(e || this._states.currentRun), r = false;
640
+ !e && this.options.startAt && this.options.interval && ([e, t] = this._calculatePreviousRun(e, t), r = !e), e = new m(e, this.getTz()), this.options.startAt && e && e.getTime() < this.options.startAt.getTime() && (e = this.options.startAt);
641
+ let n = this._states.once || new m(e, this.getTz());
642
+ return !r && n !== this._states.once && (n = n.increment(this._states.pattern, this.options, t)), this._states.once && this._states.once.getTime() <= e.getTime() || n === null || this._states.maxRuns !== void 0 && this._states.maxRuns <= 0 || this._states.kill || this.options.stopAt && n.getTime() >= this.options.stopAt.getTime() ? null : n;
643
+ }
644
+ _previous(e) {
645
+ let t = new m(e, this.getTz());
646
+ this.options.stopAt && t.getTime() > this.options.stopAt.getTime() && (t = this.options.stopAt);
647
+ let r = new m(t, this.getTz());
648
+ return this._states.once ? this._states.once.getTime() < t.getTime() ? this._states.once : null : (r = r.decrement(this._states.pattern, this.options), r === null || this.options.startAt && r.getTime() < this.options.startAt.getTime() ? null : r);
649
+ }
650
+ _calculatePreviousRun(e, t) {
651
+ let r = new m(void 0, this.getTz()), n = e;
652
+ if (this.options.startAt.getTime() <= r.getTime()) {
653
+ n = this.options.startAt;
654
+ let i = n.getTime() + this.options.interval * 1e3;
655
+ for (; i <= r.getTime(); ) n = new m(n, this.getTz()).increment(this._states.pattern, this.options, true), i = n.getTime() + this.options.interval * 1e3;
656
+ t = true;
657
+ }
658
+ return n === null && (n = void 0), [n, t];
659
+ }
660
+ };
16
661
 
17
662
  // ../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.js
663
+ import { webcrypto as crypto } from "crypto";
18
664
  var POOL_SIZE_MULTIPLIER = 128;
19
665
  var pool;
20
666
  var poolOffset;
@@ -29,16 +675,34 @@ function fillPool(bytes) {
29
675
  }
30
676
  poolOffset += bytes;
31
677
  }
32
- function nanoid(size = 21) {
33
- fillPool(size |= 0);
34
- let id = "";
35
- for (let i = poolOffset - size; i < poolOffset; i++) {
36
- id += urlAlphabet[pool[i] & 63];
37
- }
38
- return id;
678
+ function random(bytes) {
679
+ fillPool(bytes |= 0);
680
+ return pool.subarray(poolOffset - bytes, poolOffset);
681
+ }
682
+ function customRandom(alphabet, defaultSize, getRandom) {
683
+ let mask = (2 << 31 - Math.clz32(alphabet.length - 1 | 1)) - 1;
684
+ let step = Math.ceil(1.6 * mask * defaultSize / alphabet.length);
685
+ return (size = defaultSize) => {
686
+ if (!size) return "";
687
+ let id = "";
688
+ while (true) {
689
+ let bytes = getRandom(step);
690
+ let i = step;
691
+ while (i--) {
692
+ id += alphabet[bytes[i] & mask] || "";
693
+ if (id.length >= size) return id;
694
+ }
695
+ }
696
+ };
697
+ }
698
+ function customAlphabet(alphabet, size = 21) {
699
+ return customRandom(alphabet, size, random);
39
700
  }
40
701
 
41
702
  // src/utils.ts
703
+ var nanoid = customAlphabet(
704
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
705
+ );
42
706
  function parseDelay(delay) {
43
707
  if (typeof delay === "number") {
44
708
  return delay;
@@ -78,13 +742,153 @@ function calculateBackoff(attempt, strategy, baseDelay) {
78
742
  }
79
743
  function generateJobId() {
80
744
  const timestamp = Date.now().toString(36);
81
- const random = Math.random().toString(36).substring(2, 10);
82
- return `job_${timestamp}_${random}`;
745
+ const random2 = Math.random().toString(36).substring(2, 10);
746
+ return `job_${timestamp}_${random2}`;
83
747
  }
84
748
  function generatePublicId(prefix = "job") {
85
749
  return `${prefix}_${nanoid(21)}`;
86
750
  }
87
751
 
752
+ // src/schedule.ts
753
+ var PLAIN_ENGLISH_PATTERNS = [
754
+ // "every 5 minutes", "every 30 minutes"
755
+ {
756
+ regex: /^every (\d+) minutes?$/i,
757
+ toCron: (minutes) => `*/${minutes} * * * *`
758
+ },
759
+ // "every minute"
760
+ {
761
+ regex: /^every minute$/i,
762
+ toCron: () => "* * * * *"
763
+ },
764
+ // "every 2 hours", "every hour"
765
+ {
766
+ regex: /^every (\d+) hours?$/i,
767
+ toCron: (hours) => `0 */${hours} * * *`
768
+ },
769
+ {
770
+ regex: /^every hour$/i,
771
+ toCron: () => "0 * * * *"
772
+ },
773
+ // "every day at 9am", "every day at 2pm", "every day at 14:30"
774
+ {
775
+ regex: /^every day at (\d{1,2})(:\d{2})?\s*(am|pm)?$/i,
776
+ toCron: (hour, minutes, ampm) => {
777
+ const { h, m: m2 } = parseTime(hour, minutes, ampm);
778
+ return `${m2} ${h} * * *`;
779
+ }
780
+ },
781
+ // "every weekday at 9am"
782
+ {
783
+ regex: /^every weekday at (\d{1,2})(:\d{2})?\s*(am|pm)?$/i,
784
+ toCron: (hour, minutes, ampm) => {
785
+ const { h, m: m2 } = parseTime(hour, minutes, ampm);
786
+ return `${m2} ${h} * * 1-5`;
787
+ }
788
+ },
789
+ // "every monday at 9am", "every friday at 2pm"
790
+ {
791
+ regex: /^every (monday|tuesday|wednesday|thursday|friday|saturday|sunday) at (\d{1,2})(:\d{2})?\s*(am|pm)?$/i,
792
+ toCron: (day, hour, minutes, ampm) => {
793
+ const { h, m: m2 } = parseTime(hour, minutes, ampm);
794
+ return `${m2} ${h} * * ${dayToNumber(day)}`;
795
+ }
796
+ }
797
+ ];
798
+ var DAY_MAP = {
799
+ sunday: 0,
800
+ monday: 1,
801
+ tuesday: 2,
802
+ wednesday: 3,
803
+ thursday: 4,
804
+ friday: 5,
805
+ saturday: 6
806
+ };
807
+ function dayToNumber(day) {
808
+ const num = DAY_MAP[day.toLowerCase()];
809
+ if (num === void 0) {
810
+ throw new Error(`Unknown day: ${day}`);
811
+ }
812
+ return num;
813
+ }
814
+ function parseTime(hourStr, minutesStr, ampm) {
815
+ let h = Number.parseInt(hourStr, 10);
816
+ const m2 = minutesStr ? Number.parseInt(minutesStr.slice(1), 10) : 0;
817
+ if (ampm) {
818
+ const period = ampm.toLowerCase();
819
+ if (period === "pm" && h !== 12) {
820
+ h += 12;
821
+ }
822
+ if (period === "am" && h === 12) {
823
+ h = 0;
824
+ }
825
+ }
826
+ if (h < 0 || h > 23) {
827
+ throw new Error(`Invalid hour: ${h}`);
828
+ }
829
+ if (m2 < 0 || m2 > 59) {
830
+ throw new Error(`Invalid minutes: ${m2}`);
831
+ }
832
+ return { h, m: m2 };
833
+ }
834
+ function parsePlainEnglish(expression) {
835
+ for (const { regex, toCron } of PLAIN_ENGLISH_PATTERNS) {
836
+ const match = expression.match(regex);
837
+ if (match) {
838
+ const args = match.slice(1).map((v2) => v2 ?? "");
839
+ return toCron(...args);
840
+ }
841
+ }
842
+ return expression;
843
+ }
844
+ function validateCron(expression) {
845
+ try {
846
+ new E(expression);
847
+ } catch (error) {
848
+ throw new Error(
849
+ `Invalid cron expression "${expression}": ${error instanceof Error ? error.message : String(error)}`
850
+ );
851
+ }
852
+ }
853
+ function nextRun(expression, timezone = "UTC") {
854
+ const cron = new E(expression, { timezone });
855
+ return cron.nextRun();
856
+ }
857
+ function nextRuns(expression, count, timezone = "UTC") {
858
+ const cron = new E(expression, { timezone });
859
+ return cron.nextRuns(count);
860
+ }
861
+ function normalizeInput(input) {
862
+ if (typeof input === "string") {
863
+ return { cron: input };
864
+ }
865
+ return input;
866
+ }
867
+ function resolveSchedule(input) {
868
+ const config = normalizeInput(input);
869
+ const cronExpression = parsePlainEnglish(config.cron);
870
+ validateCron(cronExpression);
871
+ return {
872
+ cronExpression,
873
+ timezone: config.timezone ?? "UTC",
874
+ enabled: config.enabled ?? true,
875
+ overlap: config.overlap ?? "skip",
876
+ timeoutMs: config.timeout != null ? parseDelay(config.timeout) : null
877
+ };
878
+ }
879
+ function extractSchedules(router) {
880
+ const schedules = [];
881
+ for (const [jobName, definition] of Object.entries(router)) {
882
+ if (definition.schedule != null) {
883
+ schedules.push({
884
+ jobName,
885
+ schedule: resolveSchedule(definition.schedule)
886
+ });
887
+ }
888
+ }
889
+ return schedules;
890
+ }
891
+
88
892
  // src/webhook.ts
89
893
  import { createHmac, timingSafeEqual } from "crypto";
90
894
  var WEBHOOK_HEADERS = {
@@ -102,8 +906,8 @@ function signPayload(payload, secret) {
102
906
  }
103
907
  function verifySignature(payload, signature, secret, toleranceSeconds = DEFAULT_TOLERANCE_SECONDS) {
104
908
  const parts = signature.split(",");
105
- const tPart = parts.find((p) => p.startsWith("t="));
106
- const v1Part = parts.find((p) => p.startsWith("v1="));
909
+ const tPart = parts.find((p2) => p2.startsWith("t="));
910
+ const v1Part = parts.find((p2) => p2.startsWith("v1="));
107
911
  if (!tPart || !v1Part) {
108
912
  return false;
109
913
  }
@@ -127,6 +931,12 @@ function verifySignature(payload, signature, secret, toleranceSeconds = DEFAULT_
127
931
  }
128
932
 
129
933
  // src/handler.ts
934
+ var JobFailureError = class extends Error {
935
+ constructor(reason) {
936
+ super(reason);
937
+ this.name = "JobFailureError";
938
+ }
939
+ };
130
940
  async function processJobCallback(router, request, options) {
131
941
  const webhookSecret = options?.webhookSecret ?? process.env.QUEUEBASE_WEBHOOK_SECRET;
132
942
  if (webhookSecret) {
@@ -165,7 +975,10 @@ async function processJobCallback(router, request, options) {
165
975
  input: parseResult.data,
166
976
  jobId,
167
977
  attempt,
168
- maxAttempts
978
+ maxAttempts,
979
+ fail(reason) {
980
+ throw new JobFailureError(reason);
981
+ }
169
982
  };
170
983
  try {
171
984
  const output = await jobDef.handler(context);
@@ -176,14 +989,21 @@ async function processJobCallback(router, request, options) {
176
989
  }
177
990
  }
178
991
  export {
992
+ JobFailureError,
179
993
  WEBHOOK_HEADERS,
180
994
  calculateBackoff,
181
995
  createJobRouter,
996
+ extractSchedules,
182
997
  generateJobId,
183
998
  generatePublicId,
184
999
  job,
1000
+ nextRun,
1001
+ nextRuns,
185
1002
  parseDelay,
1003
+ parsePlainEnglish,
186
1004
  processJobCallback,
1005
+ resolveSchedule,
187
1006
  signPayload,
1007
+ validateCron,
188
1008
  verifySignature
189
1009
  };