semola 0.5.2 → 0.5.3
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/README.md +88 -13
- package/dist/cron/builder/index.cjs +166 -0
- package/dist/cron/builder/index.d.cts +28 -0
- package/dist/cron/builder/index.d.cts.map +1 -0
- package/dist/cron/builder/index.d.mts +28 -0
- package/dist/cron/builder/index.d.mts.map +1 -0
- package/dist/cron/builder/index.mjs +163 -0
- package/dist/cron/builder/index.mjs.map +1 -0
- package/dist/cron/builder/types.cjs +27 -0
- package/dist/cron/builder/types.d.cts +79 -0
- package/dist/cron/builder/types.d.cts.map +1 -0
- package/dist/cron/builder/types.d.mts +79 -0
- package/dist/cron/builder/types.d.mts.map +1 -0
- package/dist/cron/builder/types.mjs +28 -0
- package/dist/cron/builder/types.mjs.map +1 -0
- package/dist/cron/core/index.cjs +308 -0
- package/dist/cron/core/index.d.cts +39 -0
- package/dist/cron/core/index.d.cts.map +1 -0
- package/dist/cron/core/index.d.mts +39 -0
- package/dist/cron/core/index.d.mts.map +1 -0
- package/dist/cron/core/index.mjs +310 -0
- package/dist/cron/core/index.mjs.map +1 -0
- package/dist/cron/{scanner.cjs → core/scanner.cjs} +2 -2
- package/dist/cron/{scanner.mjs → core/scanner.mjs} +2 -2
- package/dist/cron/core/scanner.mjs.map +1 -0
- package/dist/cron/{types.d.cts → core/types.d.cts} +1 -1
- package/dist/cron/core/types.d.cts.map +1 -0
- package/dist/cron/{types.d.mts → core/types.d.mts} +1 -1
- package/dist/cron/core/types.d.mts.map +1 -0
- package/dist/errors/types.d.cts +1 -1
- package/dist/errors/types.d.mts +1 -1
- package/dist/lib/cache/index.d.cts +3 -3
- package/dist/lib/cache/index.d.mts +3 -3
- package/dist/lib/cron/index.cjs +12 -275
- package/dist/lib/cron/index.d.cts +4 -39
- package/dist/lib/cron/index.d.mts +4 -39
- package/dist/lib/cron/index.mjs +4 -277
- package/dist/lib/errors/index.d.cts +2 -2
- package/dist/lib/errors/index.d.cts.map +1 -1
- package/dist/lib/errors/index.d.mts +2 -2
- package/dist/lib/errors/index.d.mts.map +1 -1
- package/dist/lib/errors/index.mjs.map +1 -1
- package/dist/lib/i18n/index.cjs +6 -1
- package/dist/lib/i18n/index.d.cts.map +1 -1
- package/dist/lib/i18n/index.d.mts.map +1 -1
- package/dist/lib/i18n/index.mjs +6 -1
- package/dist/lib/i18n/index.mjs.map +1 -1
- package/dist/lib/logging/index.cjs +18 -0
- package/dist/lib/logging/index.d.cts +7 -0
- package/dist/lib/logging/index.d.mts +7 -0
- package/dist/lib/logging/index.mjs +5 -0
- package/dist/lib/orm/index.cjs +20 -0
- package/dist/lib/orm/index.d.cts +7 -0
- package/dist/lib/orm/index.d.mts +7 -0
- package/dist/lib/orm/index.mjs +6 -0
- package/dist/lib/prompts/index.d.cts +8 -8
- package/dist/lib/prompts/index.d.mts +8 -8
- package/dist/lib/pubsub/index.cjs +82 -13
- package/dist/lib/pubsub/index.d.cts +14 -5
- package/dist/lib/pubsub/index.d.cts.map +1 -1
- package/dist/lib/pubsub/index.d.mts +14 -5
- package/dist/lib/pubsub/index.d.mts.map +1 -1
- package/dist/lib/pubsub/index.mjs +82 -13
- package/dist/lib/pubsub/index.mjs.map +1 -1
- package/dist/lib/queue/index.d.cts +2 -2
- package/dist/lib/queue/index.d.mts +2 -2
- package/dist/lib/workflow/index.cjs +534 -0
- package/dist/lib/workflow/index.d.cts +7 -0
- package/dist/lib/workflow/index.d.cts.map +1 -0
- package/dist/lib/workflow/index.d.mts +7 -0
- package/dist/lib/workflow/index.d.mts.map +1 -0
- package/dist/lib/workflow/index.mjs +535 -0
- package/dist/lib/workflow/index.mjs.map +1 -0
- package/dist/logging/core/index.cjs +99 -0
- package/dist/logging/core/index.d.cts +26 -0
- package/dist/logging/core/index.d.cts.map +1 -0
- package/dist/logging/core/index.d.mts +26 -0
- package/dist/logging/core/index.d.mts.map +1 -0
- package/dist/logging/core/index.mjs +99 -0
- package/dist/logging/core/index.mjs.map +1 -0
- package/dist/logging/core/types.cjs +10 -0
- package/dist/logging/core/types.d.cts +22 -0
- package/dist/logging/core/types.d.cts.map +1 -0
- package/dist/logging/core/types.d.mts +22 -0
- package/dist/logging/core/types.d.mts.map +1 -0
- package/dist/logging/core/types.mjs +12 -0
- package/dist/logging/core/types.mjs.map +1 -0
- package/dist/logging/formatter/index.cjs +119 -0
- package/dist/logging/formatter/index.d.cts +27 -0
- package/dist/logging/formatter/index.d.cts.map +1 -0
- package/dist/logging/formatter/index.d.mts +27 -0
- package/dist/logging/formatter/index.d.mts.map +1 -0
- package/dist/logging/formatter/index.mjs +115 -0
- package/dist/logging/formatter/index.mjs.map +1 -0
- package/dist/logging/formatter/types.d.cts +5 -0
- package/dist/logging/formatter/types.d.cts.map +1 -0
- package/dist/logging/formatter/types.d.mts +5 -0
- package/dist/logging/formatter/types.d.mts.map +1 -0
- package/dist/logging/provider/index.cjs +165 -0
- package/dist/logging/provider/index.d.cts +28 -0
- package/dist/logging/provider/index.d.cts.map +1 -0
- package/dist/logging/provider/index.d.mts +28 -0
- package/dist/logging/provider/index.d.mts.map +1 -0
- package/dist/logging/provider/index.mjs +165 -0
- package/dist/logging/provider/index.mjs.map +1 -0
- package/dist/logging/provider/types.d.cts +23 -0
- package/dist/logging/provider/types.d.cts.map +1 -0
- package/dist/logging/provider/types.d.mts +23 -0
- package/dist/logging/provider/types.d.mts.map +1 -0
- package/dist/orm/column.cjs +137 -0
- package/dist/orm/column.d.cts +121 -0
- package/dist/orm/column.d.cts.map +1 -0
- package/dist/orm/column.d.mts +121 -0
- package/dist/orm/column.d.mts.map +1 -0
- package/dist/orm/column.mjs +132 -0
- package/dist/orm/column.mjs.map +1 -0
- package/dist/orm/dialect/index.cjs +14 -0
- package/dist/orm/dialect/index.mjs +16 -0
- package/dist/orm/dialect/index.mjs.map +1 -0
- package/dist/orm/dialect/mysql.cjs +31 -0
- package/dist/orm/dialect/mysql.mjs +33 -0
- package/dist/orm/dialect/mysql.mjs.map +1 -0
- package/dist/orm/dialect/postgres.cjs +23 -0
- package/dist/orm/dialect/postgres.mjs +25 -0
- package/dist/orm/dialect/postgres.mjs.map +1 -0
- package/dist/orm/dialect/sqlite.cjs +31 -0
- package/dist/orm/dialect/sqlite.mjs +33 -0
- package/dist/orm/dialect/sqlite.mjs.map +1 -0
- package/dist/orm/dialect/utils.cjs +8 -0
- package/dist/orm/dialect/utils.mjs +10 -0
- package/dist/orm/dialect/utils.mjs.map +1 -0
- package/dist/orm/internal/table-columns.cjs +31 -0
- package/dist/orm/internal/table-columns.mjs +32 -0
- package/dist/orm/internal/table-columns.mjs.map +1 -0
- package/dist/orm/internal/table-lookup.cjs +35 -0
- package/dist/orm/internal/table-lookup.mjs +35 -0
- package/dist/orm/internal/table-lookup.mjs.map +1 -0
- package/dist/orm/internal/table-relations.cjs +28 -0
- package/dist/orm/internal/table-relations.mjs +29 -0
- package/dist/orm/internal/table-relations.mjs.map +1 -0
- package/dist/orm/migration/config.cjs +7 -0
- package/dist/orm/migration/config.d.cts +7 -0
- package/dist/orm/migration/config.d.cts.map +1 -0
- package/dist/orm/migration/config.d.mts +7 -0
- package/dist/orm/migration/config.d.mts.map +1 -0
- package/dist/orm/migration/config.mjs +8 -0
- package/dist/orm/migration/config.mjs.map +1 -0
- package/dist/orm/migration/types.d.cts +20 -0
- package/dist/orm/migration/types.d.cts.map +1 -0
- package/dist/orm/migration/types.d.mts +20 -0
- package/dist/orm/migration/types.d.mts.map +1 -0
- package/dist/orm/orm.cjs +41 -0
- package/dist/orm/orm.d.cts +18 -0
- package/dist/orm/orm.d.cts.map +1 -0
- package/dist/orm/orm.d.mts +18 -0
- package/dist/orm/orm.d.mts.map +1 -0
- package/dist/orm/orm.mjs +43 -0
- package/dist/orm/orm.mjs.map +1 -0
- package/dist/orm/relation.cjs +18 -0
- package/dist/orm/relation.d.cts +8 -0
- package/dist/orm/relation.d.cts.map +1 -0
- package/dist/orm/relation.d.mts +8 -0
- package/dist/orm/relation.d.mts.map +1 -0
- package/dist/orm/relation.mjs +19 -0
- package/dist/orm/relation.mjs.map +1 -0
- package/dist/orm/runtime/builders/mutations.cjs +29 -0
- package/dist/orm/runtime/builders/mutations.mjs +28 -0
- package/dist/orm/runtime/builders/mutations.mjs.map +1 -0
- package/dist/orm/runtime/builders/select.cjs +18 -0
- package/dist/orm/runtime/builders/select.mjs +19 -0
- package/dist/orm/runtime/builders/select.mjs.map +1 -0
- package/dist/orm/runtime/client.cjs +90 -0
- package/dist/orm/runtime/client.mjs +92 -0
- package/dist/orm/runtime/client.mjs.map +1 -0
- package/dist/orm/runtime/context.cjs +49 -0
- package/dist/orm/runtime/context.mjs +51 -0
- package/dist/orm/runtime/context.mjs.map +1 -0
- package/dist/orm/runtime/dialect/index.cjs +11 -0
- package/dist/orm/runtime/dialect/index.mjs +13 -0
- package/dist/orm/runtime/dialect/index.mjs.map +1 -0
- package/dist/orm/runtime/dialect/mysql.cjs +95 -0
- package/dist/orm/runtime/dialect/mysql.mjs +97 -0
- package/dist/orm/runtime/dialect/mysql.mjs.map +1 -0
- package/dist/orm/runtime/dialect/postgres.cjs +51 -0
- package/dist/orm/runtime/dialect/postgres.mjs +53 -0
- package/dist/orm/runtime/dialect/postgres.mjs.map +1 -0
- package/dist/orm/runtime/dialect/sqlite.cjs +4 -0
- package/dist/orm/runtime/dialect/sqlite.mjs +7 -0
- package/dist/orm/runtime/dialect/sqlite.mjs.map +1 -0
- package/dist/orm/runtime/errors.cjs +19 -0
- package/dist/orm/runtime/errors.mjs +21 -0
- package/dist/orm/runtime/errors.mjs.map +1 -0
- package/dist/orm/runtime/hydrate/many.cjs +46 -0
- package/dist/orm/runtime/hydrate/many.mjs +48 -0
- package/dist/orm/runtime/hydrate/many.mjs.map +1 -0
- package/dist/orm/runtime/hydrate/one.cjs +38 -0
- package/dist/orm/runtime/hydrate/one.mjs +40 -0
- package/dist/orm/runtime/hydrate/one.mjs.map +1 -0
- package/dist/orm/runtime/hydrate.cjs +49 -0
- package/dist/orm/runtime/hydrate.mjs +51 -0
- package/dist/orm/runtime/hydrate.mjs.map +1 -0
- package/dist/orm/runtime/rows.cjs +30 -0
- package/dist/orm/runtime/rows.mjs +31 -0
- package/dist/orm/runtime/rows.mjs.map +1 -0
- package/dist/orm/runtime/utils.cjs +27 -0
- package/dist/orm/runtime/utils.mjs +27 -0
- package/dist/orm/runtime/utils.mjs.map +1 -0
- package/dist/orm/sql/parse-array.cjs +64 -0
- package/dist/orm/sql/parse-array.mjs +66 -0
- package/dist/orm/sql/parse-array.mjs.map +1 -0
- package/dist/orm/sql/plan/select.cjs +36 -0
- package/dist/orm/sql/plan/select.mjs +38 -0
- package/dist/orm/sql/plan/select.mjs.map +1 -0
- package/dist/orm/sql/plan/where/operators.cjs +95 -0
- package/dist/orm/sql/plan/where/operators.mjs +97 -0
- package/dist/orm/sql/plan/where/operators.mjs.map +1 -0
- package/dist/orm/sql/plan/where.cjs +59 -0
- package/dist/orm/sql/plan/where.mjs +61 -0
- package/dist/orm/sql/plan/where.mjs.map +1 -0
- package/dist/orm/sql/serialize/clauses.cjs +36 -0
- package/dist/orm/sql/serialize/clauses.mjs +37 -0
- package/dist/orm/sql/serialize/clauses.mjs.map +1 -0
- package/dist/orm/sql/serialize/joins.cjs +31 -0
- package/dist/orm/sql/serialize/joins.mjs +33 -0
- package/dist/orm/sql/serialize/joins.mjs.map +1 -0
- package/dist/orm/sql/serialize/values.cjs +30 -0
- package/dist/orm/sql/serialize/values.mjs +32 -0
- package/dist/orm/sql/serialize/values.mjs.map +1 -0
- package/dist/orm/sql/serialize/where/predicate.cjs +73 -0
- package/dist/orm/sql/serialize/where/predicate.mjs +75 -0
- package/dist/orm/sql/serialize/where/predicate.mjs.map +1 -0
- package/dist/orm/sql/serialize/where/tree.cjs +26 -0
- package/dist/orm/sql/serialize/where/tree.mjs +28 -0
- package/dist/orm/sql/serialize/where/tree.mjs.map +1 -0
- package/dist/orm/sql/serialize/where.cjs +10 -0
- package/dist/orm/sql/serialize/where.mjs +12 -0
- package/dist/orm/sql/serialize/where.mjs.map +1 -0
- package/dist/orm/sql/serialize.cjs +24 -0
- package/dist/orm/sql/serialize.mjs +25 -0
- package/dist/orm/sql/serialize.mjs.map +1 -0
- package/dist/orm/table.cjs +12 -0
- package/dist/orm/table.d.cts +12 -0
- package/dist/orm/table.d.cts.map +1 -0
- package/dist/orm/table.d.mts +12 -0
- package/dist/orm/table.d.mts.map +1 -0
- package/dist/orm/table.mjs +14 -0
- package/dist/orm/table.mjs.map +1 -0
- package/dist/orm/types.d.cts +183 -0
- package/dist/orm/types.d.cts.map +1 -0
- package/dist/orm/types.d.mts +183 -0
- package/dist/orm/types.d.mts.map +1 -0
- package/dist/workflow/types.d.cts +83 -0
- package/dist/workflow/types.d.cts.map +1 -0
- package/dist/workflow/types.d.mts +83 -0
- package/dist/workflow/types.d.mts.map +1 -0
- package/package.json +29 -3
- package/dist/cron/scanner.mjs.map +0 -1
- package/dist/cron/types.d.cts.map +0 -1
- package/dist/cron/types.d.mts.map +0 -1
- package/dist/lib/cron/index.d.cts.map +0 -1
- package/dist/lib/cron/index.d.mts.map +0 -1
- package/dist/lib/cron/index.mjs.map +0 -1
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
import { err, mightThrow, ok } from "../../lib/errors/index.mjs";
|
|
2
|
+
import { FieldAmount, Scanner } from "./scanner.mjs";
|
|
3
|
+
//#region src/lib/cron/core/index.ts
|
|
4
|
+
const RETRY_DELAY_MS = 3600 * 1e3;
|
|
5
|
+
const MAX_YEARS = 4;
|
|
6
|
+
const ALIASES = {
|
|
7
|
+
"@yearly": "0 0 1 1 *",
|
|
8
|
+
"@monthly": "0 0 1 * *",
|
|
9
|
+
"@weekly": "0 0 * * 0",
|
|
10
|
+
"@daily": "0 0 * * *",
|
|
11
|
+
"@hourly": "0 * * * *",
|
|
12
|
+
"@minutely": "* * * * *"
|
|
13
|
+
};
|
|
14
|
+
const CronSecondRange = {
|
|
15
|
+
min: 0,
|
|
16
|
+
max: 59
|
|
17
|
+
};
|
|
18
|
+
const CronMinuteRange = {
|
|
19
|
+
min: 0,
|
|
20
|
+
max: 59
|
|
21
|
+
};
|
|
22
|
+
const CronHourRange = {
|
|
23
|
+
min: 0,
|
|
24
|
+
max: 23
|
|
25
|
+
};
|
|
26
|
+
const CronDayRange = {
|
|
27
|
+
min: 1,
|
|
28
|
+
max: 31
|
|
29
|
+
};
|
|
30
|
+
const CronMonthRange = {
|
|
31
|
+
min: 1,
|
|
32
|
+
max: 12
|
|
33
|
+
};
|
|
34
|
+
const CronDayOfWeekRange = {
|
|
35
|
+
min: 0,
|
|
36
|
+
max: 6
|
|
37
|
+
};
|
|
38
|
+
var Cron = class {
|
|
39
|
+
options;
|
|
40
|
+
status = "idle";
|
|
41
|
+
timeoutId = null;
|
|
42
|
+
second = Array(CronSecondRange.max + 1).fill(0);
|
|
43
|
+
minute = Array(CronMinuteRange.max + 1).fill(0);
|
|
44
|
+
hour = Array(CronHourRange.max + 1).fill(0);
|
|
45
|
+
day = Array(CronDayRange.max + 1).fill(0);
|
|
46
|
+
month = Array(CronMonthRange.max + 1).fill(0);
|
|
47
|
+
dayOfWeek = Array(CronDayOfWeekRange.max + 1).fill(0);
|
|
48
|
+
hasSeconds;
|
|
49
|
+
_dayWildcard = false;
|
|
50
|
+
_dowWildcard = false;
|
|
51
|
+
fillRange(values, min, max) {
|
|
52
|
+
for (let i = min; i <= max; i++) values[i] = 1;
|
|
53
|
+
}
|
|
54
|
+
handleStep(part, values, min, max) {
|
|
55
|
+
const [rangePart, stepStr] = part.split("/");
|
|
56
|
+
if (!rangePart) return err("InvalidValueError", `'${rangePart}' is empty`);
|
|
57
|
+
if (!stepStr) return err("InvalidValueError", `'${stepStr}' is empty`);
|
|
58
|
+
const step = Number(stepStr);
|
|
59
|
+
if (!Number.isInteger(step)) return err("InvalidValueError", `'${step}' is not a valid number`);
|
|
60
|
+
if (step <= 0) return err("OutOfBoundError", `Expected ${step} > 0`);
|
|
61
|
+
if (rangePart === "*") {
|
|
62
|
+
for (let i = min; i <= max; i += step) values[i] = 1;
|
|
63
|
+
return ok(true);
|
|
64
|
+
}
|
|
65
|
+
if (rangePart.includes("-")) return this.handleStepRange(rangePart, step, values, min, max);
|
|
66
|
+
return this.handleStepSingle(rangePart, step, values, min, max);
|
|
67
|
+
}
|
|
68
|
+
handleStepRange(range, step, values, min, max) {
|
|
69
|
+
const [startStr, endStr] = range.split("-");
|
|
70
|
+
if (!endStr) return err("InvalidValueError", `'${endStr}' is empty`);
|
|
71
|
+
let start = min;
|
|
72
|
+
if (startStr && startStr.length > 0) start = Number(startStr);
|
|
73
|
+
const end = Number(endStr);
|
|
74
|
+
if (!Number.isInteger(start)) return err("InvalidValueError", `'${start}' is not a valid number`);
|
|
75
|
+
if (!Number.isInteger(end)) return err("InvalidValueError", `'${end}' is not a valid number`);
|
|
76
|
+
if (start < min) return err("OutOfBoundError", `Expected ${start} >= ${min}`);
|
|
77
|
+
if (end > max) return err("OutOfBoundError", `Expected ${end} <= ${max}`);
|
|
78
|
+
if (start > end) return err("OutOfBoundError", `Expected ${start} <= ${end}`);
|
|
79
|
+
for (let i = start; i <= end; i += step) values[i] = 1;
|
|
80
|
+
return ok(true);
|
|
81
|
+
}
|
|
82
|
+
handleStepSingle(value, step, values, min, max) {
|
|
83
|
+
const start = Number(value);
|
|
84
|
+
if (!Number.isInteger(start)) return err("InvalidValueError", `'${start}' is not a valid number`);
|
|
85
|
+
if (start < min) return err("OutOfBoundError", `Expected ${start} >= ${min}`);
|
|
86
|
+
if (start > max) return err("OutOfBoundError", `Expected ${start} <= ${max}`);
|
|
87
|
+
for (let i = start; i <= max; i += step) values[i] = 1;
|
|
88
|
+
return ok(true);
|
|
89
|
+
}
|
|
90
|
+
handleRange(part, values, min, max) {
|
|
91
|
+
const [startStr, endStr] = part.split("-");
|
|
92
|
+
if (!startStr) return err("InvalidValueError", `'${startStr}' is empty`);
|
|
93
|
+
if (!endStr) return err("InvalidValueError", `'${endStr}' is empty`);
|
|
94
|
+
const start = Number(startStr);
|
|
95
|
+
const end = Number(endStr);
|
|
96
|
+
if (!Number.isInteger(start)) return err("InvalidValueError", `'${start}' is not a valid number`);
|
|
97
|
+
if (!Number.isInteger(end)) return err("InvalidValueError", `'${end}' is not a valid number`);
|
|
98
|
+
if (start < min) return err("OutOfBoundError", `Expected ${start} >= ${min}`);
|
|
99
|
+
if (end > max) return err("OutOfBoundError", `Expected ${end} <= ${max}`);
|
|
100
|
+
if (start > end) return err("OutOfBoundError", `Expected ${start} <= ${end}`);
|
|
101
|
+
for (let i = start; i <= end; i++) values[i] = 1;
|
|
102
|
+
return ok(true);
|
|
103
|
+
}
|
|
104
|
+
handleNumber(value, values, min, max) {
|
|
105
|
+
const n = Number(value);
|
|
106
|
+
if (!Number.isInteger(n)) return err("InvalidValueError", `'${value}' is not a valid number`);
|
|
107
|
+
if (n < min) return err("OutOfBoundError", `Expected ${n} >= ${min}`);
|
|
108
|
+
if (n > max) return err("OutOfBoundError", `Expected ${n} <= ${max}`);
|
|
109
|
+
values[n] = 1;
|
|
110
|
+
return ok(true);
|
|
111
|
+
}
|
|
112
|
+
constructor(options) {
|
|
113
|
+
this.options = options;
|
|
114
|
+
const expr = this.resolveAlias(options.schedule);
|
|
115
|
+
const [error, tokens] = new Scanner(expr).scan();
|
|
116
|
+
if (error) throw new Error(`${error.type}: ${error.message}`);
|
|
117
|
+
this.hasSeconds = expr.trim().split(/\s+/).length === FieldAmount.max;
|
|
118
|
+
const [parsingError, _] = this.parse(tokens);
|
|
119
|
+
if (parsingError) throw new Error(`${parsingError.type}: ${parsingError.message}`);
|
|
120
|
+
}
|
|
121
|
+
resolveAlias(schedule) {
|
|
122
|
+
return ALIASES[schedule] || schedule;
|
|
123
|
+
}
|
|
124
|
+
parse(tokens) {
|
|
125
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
126
|
+
const token = tokens[i];
|
|
127
|
+
if (!token) return err("InvalidValueError", "Undefined token");
|
|
128
|
+
const tokenType = token.getTokenType();
|
|
129
|
+
switch (token.getField()) {
|
|
130
|
+
case "second": {
|
|
131
|
+
const [error, _] = this.handleField(token, this.second, CronSecondRange.min, CronSecondRange.max);
|
|
132
|
+
if (error) return err(error.type, `${error.message} in field '${token.getField()}'`);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "minute": {
|
|
136
|
+
const [error, _] = this.handleField(token, this.minute, CronMinuteRange.min, CronMinuteRange.max);
|
|
137
|
+
if (error) return err(error.type, `${error.message} in field '${token.getField()}'`);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case "hour": {
|
|
141
|
+
const [error, _] = this.handleField(token, this.hour, CronHourRange.min, CronHourRange.max);
|
|
142
|
+
if (error) return err(error.type, `${error.message} in field '${token.getField()}'`);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case "day": {
|
|
146
|
+
if (tokenType === "any") this._dayWildcard = true;
|
|
147
|
+
const [error, _] = this.handleField(token, this.day, CronDayRange.min, CronDayRange.max);
|
|
148
|
+
if (error) return err(error.type, `${error.message} in field '${token.getField()}'`);
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case "month": {
|
|
152
|
+
const [error, _] = this.handleField(token, this.month, CronMonthRange.min, CronMonthRange.max);
|
|
153
|
+
if (error) return err(error.type, `${error.message} in field '${token.getField()}'`);
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case "weekday": {
|
|
157
|
+
if (tokenType === "any") this._dowWildcard = true;
|
|
158
|
+
const [error, _] = this.handleField(token, this.dayOfWeek, CronDayOfWeekRange.min, CronDayOfWeekRange.max);
|
|
159
|
+
if (error) return err(error.type, `${error.message} in field '${token.getField()}'`);
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
default: return err("InvalidValueError", `Invalid field '${token.getField()}'`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return ok(true);
|
|
166
|
+
}
|
|
167
|
+
handleField(token, field, min, max) {
|
|
168
|
+
switch (token.getTokenType()) {
|
|
169
|
+
case "any":
|
|
170
|
+
this.fillRange(field, min, max);
|
|
171
|
+
break;
|
|
172
|
+
case "number": {
|
|
173
|
+
const [error, _] = this.handleNumber(token.getComponent(), field, min, max);
|
|
174
|
+
if (error) return err(error.type, error.message);
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
case "range": {
|
|
178
|
+
const component = token.getComponent();
|
|
179
|
+
const [error, _] = this.handleRange(component, field, min, max);
|
|
180
|
+
if (error) return err(error.type, error.message);
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
case "step": {
|
|
184
|
+
const component = token.getComponent();
|
|
185
|
+
const [error, _] = this.handleStep(component, field, min, max);
|
|
186
|
+
if (error) return err(error.type, error.message);
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
default: return err("InvalidValueError", `Invalid token type '${token.getTokenType()}'`);
|
|
190
|
+
}
|
|
191
|
+
return ok(true);
|
|
192
|
+
}
|
|
193
|
+
matches(date) {
|
|
194
|
+
const s = date.getSeconds();
|
|
195
|
+
const m = date.getMinutes();
|
|
196
|
+
const h = date.getHours();
|
|
197
|
+
const d = date.getDate();
|
|
198
|
+
const mon = date.getMonth();
|
|
199
|
+
const dow = date.getDay();
|
|
200
|
+
const isSecondMatch = this.hasSeconds ? this.second[s] === 1 : true;
|
|
201
|
+
const isMinuteMatch = this.minute[m] === 1;
|
|
202
|
+
const isHourMatch = this.hour[h] === 1;
|
|
203
|
+
const isMonthMatch = this.month[mon + 1] === 1;
|
|
204
|
+
let isDayOrDowMatch;
|
|
205
|
+
if (!this._dayWildcard && !this._dowWildcard) isDayOrDowMatch = this.day[d] === 1 || this.dayOfWeek[dow] === 1;
|
|
206
|
+
else isDayOrDowMatch = this.day[d] === 1 && this.dayOfWeek[dow] === 1;
|
|
207
|
+
return isSecondMatch && isMinuteMatch && isHourMatch && isDayOrDowMatch && isMonthMatch;
|
|
208
|
+
}
|
|
209
|
+
getNextRun() {
|
|
210
|
+
const date = /* @__PURE__ */ new Date();
|
|
211
|
+
if (this.hasSeconds) {
|
|
212
|
+
date.setMilliseconds(0);
|
|
213
|
+
date.setSeconds(date.getSeconds() + 1);
|
|
214
|
+
} else {
|
|
215
|
+
date.setSeconds(0, 0);
|
|
216
|
+
date.setMinutes(date.getMinutes() + 1);
|
|
217
|
+
}
|
|
218
|
+
const deadline = new Date(date);
|
|
219
|
+
deadline.setFullYear(deadline.getFullYear() + MAX_YEARS);
|
|
220
|
+
while (date < deadline) {
|
|
221
|
+
const s = date.getSeconds();
|
|
222
|
+
const m = date.getMinutes();
|
|
223
|
+
const h = date.getHours();
|
|
224
|
+
const d = date.getDate();
|
|
225
|
+
const mon = date.getMonth();
|
|
226
|
+
const dow = date.getDay();
|
|
227
|
+
if (this.month[mon + 1] === 0) {
|
|
228
|
+
date.setDate(1);
|
|
229
|
+
date.setMonth(mon + 1);
|
|
230
|
+
date.setHours(0, 0, 0, 0);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
let isDayOrDowMatch;
|
|
234
|
+
if (!this._dayWildcard && !this._dowWildcard) isDayOrDowMatch = this.day[d] === 0 && this.dayOfWeek[dow] === 0;
|
|
235
|
+
else isDayOrDowMatch = this.day[d] === 0 || this.dayOfWeek[dow] === 0;
|
|
236
|
+
if (isDayOrDowMatch) {
|
|
237
|
+
date.setDate(d + 1);
|
|
238
|
+
date.setHours(0, 0, 0, 0);
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (this.hour[h] === 0) {
|
|
242
|
+
date.setHours(h + 1);
|
|
243
|
+
date.setMinutes(0, 0, 0);
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (this.minute[m] === 0) {
|
|
247
|
+
date.setMinutes(m + 1);
|
|
248
|
+
date.setSeconds(0, 0);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (this.hasSeconds && this.second[s] === 0) {
|
|
252
|
+
date.setSeconds(s + 1);
|
|
253
|
+
date.setMilliseconds(0);
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
return new Date(date);
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
start() {
|
|
261
|
+
if (this.status !== "idle") return;
|
|
262
|
+
this.status = "running";
|
|
263
|
+
this.next();
|
|
264
|
+
}
|
|
265
|
+
stop() {
|
|
266
|
+
this.status = "idle";
|
|
267
|
+
if (this.timeoutId) {
|
|
268
|
+
clearTimeout(this.timeoutId);
|
|
269
|
+
this.timeoutId = null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
pause() {
|
|
273
|
+
if (this.status !== "running") return;
|
|
274
|
+
this.status = "paused";
|
|
275
|
+
if (this.timeoutId) {
|
|
276
|
+
clearTimeout(this.timeoutId);
|
|
277
|
+
this.timeoutId = null;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
resume() {
|
|
281
|
+
if (this.status !== "paused") return;
|
|
282
|
+
this.status = "running";
|
|
283
|
+
this.next();
|
|
284
|
+
}
|
|
285
|
+
getStatus() {
|
|
286
|
+
return this.status;
|
|
287
|
+
}
|
|
288
|
+
next() {
|
|
289
|
+
if (this.status !== "running") return;
|
|
290
|
+
const nextRun = this.getNextRun();
|
|
291
|
+
if (!nextRun) {
|
|
292
|
+
this.timeoutId = setTimeout(() => this.next(), RETRY_DELAY_MS);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const delay = nextRun.getTime() - Date.now();
|
|
296
|
+
this.timeoutId = setTimeout(() => {
|
|
297
|
+
this.run();
|
|
298
|
+
}, Math.max(0, delay));
|
|
299
|
+
}
|
|
300
|
+
async run() {
|
|
301
|
+
if (this.status !== "running") return;
|
|
302
|
+
const handlerResult = this.options.handler();
|
|
303
|
+
await mightThrow(Promise.resolve(handlerResult));
|
|
304
|
+
if (this.status === "running") this.next();
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
//#endregion
|
|
308
|
+
export { Cron };
|
|
309
|
+
|
|
310
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/lib/cron/core/index.ts"],"sourcesContent":["import { err, mightThrow, ok } from \"../../errors/index.js\";\nimport { FieldAmount, Scanner, type Token } from \"./scanner.js\";\nimport type { CronOptions, CronParsingError, CronStatus } from \"./types.js\";\n\nconst RETRY_DELAY_MS = 60 * 60 * 1000; // 1 hour\nconst MAX_YEARS = 4;\n\nconst ALIASES: Record<string, string> = {\n \"@yearly\": \"0 0 1 1 *\",\n \"@monthly\": \"0 0 1 * *\",\n \"@weekly\": \"0 0 * * 0\",\n \"@daily\": \"0 0 * * *\",\n \"@hourly\": \"0 * * * *\",\n \"@minutely\": \"* * * * *\",\n};\n\nconst CronSecondRange = {\n min: 0,\n max: 59,\n} as const;\n\nconst CronMinuteRange = {\n min: 0,\n max: 59,\n} as const;\n\nconst CronHourRange = {\n min: 0,\n max: 23,\n} as const;\n\nconst CronDayRange = {\n min: 1,\n max: 31,\n} as const;\n\nconst CronMonthRange = {\n min: 1,\n max: 12,\n} as const;\n\nconst CronDayOfWeekRange = {\n min: 0,\n max: 6,\n} as const;\n\nexport class Cron {\n private options: CronOptions;\n private status: CronStatus = \"idle\";\n private timeoutId: NodeJS.Timeout | null = null;\n\n // Array-based storage using 1-indexed slots (0 = don't run, 1 = run)\n private second = Array<number>(CronSecondRange.max + 1).fill(0); // 0-59\n private minute = Array<number>(CronMinuteRange.max + 1).fill(0); // 0-59\n private hour = Array<number>(CronHourRange.max + 1).fill(0); // 0-23\n private day = Array<number>(CronDayRange.max + 1).fill(0); // indices 1-31 (0 unused)\n private month = Array<number>(CronMonthRange.max + 1).fill(0); // indices 1-12 (0 unused)\n private dayOfWeek = Array<number>(CronDayOfWeekRange.max + 1).fill(0); // 0-6\n private hasSeconds: boolean;\n private _dayWildcard = false;\n private _dowWildcard = false;\n\n // Fill all values from min to max with 1\n private fillRange(values: number[], min: number, max: number) {\n for (let i = min; i <= max; i++) {\n values[i] = 1;\n }\n }\n\n private handleStep(part: string, values: number[], min: number, max: number) {\n // Split step format into range and step components\n const [rangePart, stepStr] = part.split(\"/\");\n\n if (!rangePart) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${rangePart}' is empty`,\n );\n }\n\n if (!stepStr) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${stepStr}' is empty`,\n );\n }\n\n const step = Number(stepStr);\n\n // Validate step is a positive integer\n if (!Number.isInteger(step)) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${step}' is not a valid number`,\n );\n }\n\n if (step <= 0) {\n return err<CronParsingError>(\"OutOfBoundError\", `Expected ${step} > 0`);\n }\n\n if (rangePart === \"*\") {\n // Wildcard with step: apply step across entire range\n for (let i = min; i <= max; i += step) {\n values[i] = 1;\n }\n\n return ok(true);\n }\n\n if (rangePart.includes(\"-\")) {\n // Range with step: delegate to specialized handler\n return this.handleStepRange(rangePart, step, values, min, max);\n }\n\n // Single value with step: delegate to specialized handler\n return this.handleStepSingle(rangePart, step, values, min, max);\n }\n\n private handleStepRange(\n range: string,\n step: number,\n values: number[],\n min: number,\n max: number,\n ) {\n // Split range into start and end values\n const [startStr, endStr] = range.split(\"-\");\n\n if (!endStr) {\n return err<CronParsingError>(\"InvalidValueError\", `'${endStr}' is empty`);\n }\n\n let start = min;\n if (startStr && startStr.length > 0) {\n start = Number(startStr);\n }\n\n const end = Number(endStr);\n\n // Validate range boundaries are integers within bounds\n if (!Number.isInteger(start)) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${start}' is not a valid number`,\n );\n }\n\n if (!Number.isInteger(end)) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${end}' is not a valid number`,\n );\n }\n\n if (start < min) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${start} >= ${min}`,\n );\n }\n\n if (end > max) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${end} <= ${max}`,\n );\n }\n\n if (start > end) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${start} <= ${end}`,\n );\n }\n\n // Apply step through range\n for (let i = start; i <= end; i += step) {\n values[i] = 1;\n }\n\n return ok(true);\n }\n\n private handleStepSingle(\n value: string,\n step: number,\n values: number[],\n min: number,\n max: number,\n ) {\n const start = Number(value);\n\n // Validate starting value is an integer within bounds\n if (!Number.isInteger(start)) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${start}' is not a valid number`,\n );\n }\n\n if (start < min) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${start} >= ${min}`,\n );\n }\n\n if (start > max) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${start} <= ${max}`,\n );\n }\n\n // Apply step from start to end of range\n for (let i = start; i <= max; i += step) {\n values[i] = 1;\n }\n\n return ok(true);\n }\n\n private handleRange(\n part: string,\n values: number[],\n min: number,\n max: number,\n ) {\n // Split range into start and end values\n const [startStr, endStr] = part.split(\"-\");\n\n if (!startStr) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${startStr}' is empty`,\n );\n }\n\n if (!endStr) {\n return err<CronParsingError>(\"InvalidValueError\", `'${endStr}' is empty`);\n }\n\n const start = Number(startStr);\n const end = Number(endStr);\n\n // Validate range boundaries are integers within bounds\n if (!Number.isInteger(start)) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${start}' is not a valid number`,\n );\n }\n\n if (!Number.isInteger(end)) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${end}' is not a valid number`,\n );\n }\n\n if (start < min) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${start} >= ${min}`,\n );\n }\n\n if (end > max) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${end} <= ${max}`,\n );\n }\n\n if (start > end) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${start} <= ${end}`,\n );\n }\n\n // Mark all values in the range\n for (let i = start; i <= end; i++) {\n values[i] = 1;\n }\n\n return ok(true);\n }\n\n private handleNumber(\n value: string,\n values: number[],\n min: number,\n max: number,\n ) {\n const n = Number(value);\n\n // Validate value is an integer within bounds\n if (!Number.isInteger(n)) {\n return err<CronParsingError>(\n \"InvalidValueError\",\n `'${value}' is not a valid number`,\n );\n }\n\n if (n < min) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${n} >= ${min}`,\n );\n }\n if (n > max) {\n return err<CronParsingError>(\n \"OutOfBoundError\",\n `Expected ${n} <= ${max}`,\n );\n }\n\n values[n] = 1;\n\n return ok(true);\n }\n\n public constructor(options: CronOptions) {\n this.options = options;\n\n // Resolve alias or use raw expression\n const expr = this.resolveAlias(options.schedule);\n const [error, tokens] = new Scanner(expr).scan();\n if (error) throw new Error(`${error.type}: ${error.message}`);\n\n const fields = expr.trim().split(/\\s+/);\n this.hasSeconds = fields.length === FieldAmount.max;\n\n // Parse and validate the cron expression\n const [parsingError, _] = this.parse(tokens);\n\n if (parsingError) {\n throw new Error(`${parsingError.type}: ${parsingError.message}`);\n }\n }\n\n // Map alias to standard cron expression if present\n private resolveAlias(schedule: string) {\n return ALIASES[schedule] || schedule;\n }\n\n private parse(tokens: Token[]) {\n for (let i = 0; i < tokens.length; i++) {\n const token = tokens[i];\n\n if (!token) {\n return err<CronParsingError>(\"InvalidValueError\", \"Undefined token\");\n }\n\n const tokenType = token.getTokenType();\n\n switch (token.getField()) {\n case \"second\": {\n const [error, _] = this.handleField(\n token,\n this.second,\n CronSecondRange.min,\n CronSecondRange.max,\n );\n\n if (error) {\n return err<CronParsingError>(\n error.type,\n `${error.message} in field '${token.getField()}'`,\n );\n }\n\n break;\n }\n case \"minute\": {\n const [error, _] = this.handleField(\n token,\n this.minute,\n CronMinuteRange.min,\n CronMinuteRange.max,\n );\n\n if (error) {\n return err<CronParsingError>(\n error.type,\n `${error.message} in field '${token.getField()}'`,\n );\n }\n\n break;\n }\n case \"hour\": {\n const [error, _] = this.handleField(\n token,\n this.hour,\n CronHourRange.min,\n CronHourRange.max,\n );\n\n if (error) {\n return err<CronParsingError>(\n error.type,\n `${error.message} in field '${token.getField()}'`,\n );\n }\n\n break;\n }\n case \"day\": {\n if (tokenType === \"any\") {\n this._dayWildcard = true;\n }\n\n const [error, _] = this.handleField(\n token,\n this.day,\n CronDayRange.min,\n CronDayRange.max,\n );\n\n if (error) {\n return err<CronParsingError>(\n error.type,\n `${error.message} in field '${token.getField()}'`,\n );\n }\n\n break;\n }\n case \"month\": {\n const [error, _] = this.handleField(\n token,\n this.month,\n CronMonthRange.min,\n CronMonthRange.max,\n );\n\n if (error) {\n return err<CronParsingError>(\n error.type,\n `${error.message} in field '${token.getField()}'`,\n );\n }\n\n break;\n }\n case \"weekday\": {\n if (tokenType === \"any\") {\n this._dowWildcard = true;\n }\n\n const [error, _] = this.handleField(\n token,\n this.dayOfWeek,\n CronDayOfWeekRange.min,\n CronDayOfWeekRange.max,\n );\n\n if (error) {\n return err<CronParsingError>(\n error.type,\n `${error.message} in field '${token.getField()}'`,\n );\n }\n\n break;\n }\n default:\n return err<CronParsingError>(\n \"InvalidValueError\",\n `Invalid field '${token.getField()}'`,\n );\n }\n }\n\n return ok(true);\n }\n\n private handleField(token: Token, field: number[], min: number, max: number) {\n switch (token.getTokenType()) {\n case \"any\": {\n this.fillRange(field, min, max);\n break;\n }\n case \"number\": {\n const [error, _] = this.handleNumber(\n token.getComponent(),\n field,\n min,\n max,\n );\n if (error) return err<CronParsingError>(error.type, error.message);\n\n break;\n }\n case \"range\": {\n const component = token.getComponent();\n const [error, _] = this.handleRange(component, field, min, max);\n if (error) return err<CronParsingError>(error.type, error.message);\n\n break;\n }\n case \"step\": {\n const component = token.getComponent();\n const [error, _] = this.handleStep(component, field, min, max);\n if (error) return err<CronParsingError>(error.type, error.message);\n\n break;\n }\n default:\n return err<CronParsingError>(\n \"InvalidValueError\",\n `Invalid token type '${token.getTokenType()}'`,\n );\n }\n\n return ok(true);\n }\n\n public matches(date: Date) {\n // Extract date/time components\n const s = date.getSeconds();\n const m = date.getMinutes();\n const h = date.getHours();\n const d = date.getDate();\n const mon = date.getMonth();\n const dow = date.getDay();\n\n // Check each component against configured values\n const isSecondMatch = this.hasSeconds ? this.second[s] === 1 : true;\n const isMinuteMatch = this.minute[m] === 1;\n const isHourMatch = this.hour[h] === 1;\n const isMonthMatch = this.month[mon + 1] === 1;\n\n // Standard cron: when both day-of-month and day-of-week are restricted (not *),\n // fire if EITHER matches. When at least one is *, use AND (the wildcard is always 1).\n let isDayOrDowMatch: boolean;\n\n if (!this._dayWildcard && !this._dowWildcard) {\n isDayOrDowMatch = this.day[d] === 1 || this.dayOfWeek[dow] === 1;\n } else {\n isDayOrDowMatch = this.day[d] === 1 && this.dayOfWeek[dow] === 1;\n }\n\n return (\n isSecondMatch &&\n isMinuteMatch &&\n isHourMatch &&\n isDayOrDowMatch &&\n isMonthMatch\n );\n }\n\n public getNextRun() {\n const date = new Date();\n\n // Start from next minute/second\n if (this.hasSeconds) {\n date.setMilliseconds(0);\n date.setSeconds(date.getSeconds() + 1);\n } else {\n date.setSeconds(0, 0);\n date.setMinutes(date.getMinutes() + 1);\n }\n\n // Search up to 4 years to cover leap-day schedules (next Feb 29 can be ~4 years away)\n const deadline = new Date(date);\n deadline.setFullYear(deadline.getFullYear() + MAX_YEARS);\n\n while (date < deadline) {\n const s = date.getSeconds();\n const m = date.getMinutes();\n const h = date.getHours();\n const d = date.getDate();\n const mon = date.getMonth();\n const dow = date.getDay();\n\n if (this.month[mon + 1] === 0) {\n date.setDate(1);\n date.setMonth(mon + 1);\n date.setHours(0, 0, 0, 0);\n continue;\n }\n\n let isDayOrDowMatch: boolean;\n if (!this._dayWildcard && !this._dowWildcard) {\n isDayOrDowMatch = this.day[d] === 0 && this.dayOfWeek[dow] === 0;\n } else {\n isDayOrDowMatch = this.day[d] === 0 || this.dayOfWeek[dow] === 0;\n }\n\n if (isDayOrDowMatch) {\n date.setDate(d + 1);\n date.setHours(0, 0, 0, 0);\n continue;\n }\n\n if (this.hour[h] === 0) {\n date.setHours(h + 1);\n date.setMinutes(0, 0, 0);\n continue;\n }\n\n if (this.minute[m] === 0) {\n date.setMinutes(m + 1);\n date.setSeconds(0, 0);\n continue;\n }\n\n if (this.hasSeconds && this.second[s] === 0) {\n date.setSeconds(s + 1);\n date.setMilliseconds(0);\n continue;\n }\n\n return new Date(date);\n }\n\n return null;\n }\n\n public start() {\n if (this.status !== \"idle\") return;\n\n this.status = \"running\";\n this.next();\n }\n\n public stop() {\n this.status = \"idle\";\n\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = null;\n }\n }\n\n public pause() {\n if (this.status !== \"running\") return;\n\n this.status = \"paused\";\n\n if (this.timeoutId) {\n clearTimeout(this.timeoutId);\n this.timeoutId = null;\n }\n }\n\n public resume() {\n if (this.status !== \"paused\") return;\n\n this.status = \"running\";\n this.next();\n }\n\n public getStatus() {\n return this.status;\n }\n\n private next() {\n if (this.status !== \"running\") return;\n\n const nextRun = this.getNextRun();\n\n if (!nextRun) {\n this.timeoutId = setTimeout(() => this.next(), RETRY_DELAY_MS);\n return;\n }\n\n const delay = nextRun.getTime() - Date.now();\n const actualDelay = Math.max(0, delay);\n\n this.timeoutId = setTimeout(() => {\n this.run();\n }, actualDelay);\n }\n\n private async run() {\n if (this.status !== \"running\") return;\n\n const handlerResult = this.options.handler();\n await mightThrow(Promise.resolve(handlerResult));\n\n if (this.status === \"running\") {\n this.next();\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.mjs","names":[],"sources":["../../../src/lib/cron/core/scanner.ts"],"sourcesContent":["import { err, ok } from \"../../errors/index.js\";\nimport type { CronScannerError } from \"./types.js\";\n\nexport const FieldAmount = {\n min: 5,\n max: 6,\n} as const;\n\ntype TokenValueType = string | number;\ntype CronFieldType = \"second\" | \"minute\" | \"hour\" | \"day\" | \"month\" | \"weekday\";\ntype ComponentType = {\n content: string;\n field: CronFieldType;\n};\n\ntype TokenType = \"any\" | \"range\" | \"step\" | \"number\";\n\nexport class Token {\n private readonly type: TokenType;\n private readonly component: string;\n private readonly value: TokenValueType;\n\n private readonly field: CronFieldType;\n\n public constructor(\n component: string,\n type: TokenType,\n value: TokenValueType,\n field: CronFieldType,\n ) {\n this.component = component;\n this.type = type;\n this.value = value;\n this.field = field;\n }\n\n public getComponent() {\n return this.component;\n }\n\n public getTokenType() {\n return this.type;\n }\n\n public getTokenValue() {\n return this.value;\n }\n\n public getField() {\n return this.field;\n }\n\n public toString() {\n const header = `component=\"${this.component}\", type=${this.type}`;\n const body = `field=\"${this.field}\", value=${this.value}`;\n\n return `Token{${header}, ${body}}`;\n }\n\n public equals(other: Token) {\n if (!other) return false;\n\n const isComponentEqual = this.component === other.getComponent();\n const isTokenTypeEqual = this.type === other.getTokenType();\n const isTokenValueEqual = this.value === other.getTokenValue();\n const isFieldEqual = this.field === other.getField();\n\n return (\n isComponentEqual && isTokenTypeEqual && isTokenValueEqual && isFieldEqual\n );\n }\n}\n\nexport class Scanner {\n private expression: string;\n private current: number;\n private start: number;\n private tokens: Token[];\n\n public constructor(expression: string) {\n this.expression = expression;\n this.current = 0;\n this.start = 0;\n this.tokens = [];\n }\n\n public scan() {\n if (this.expression.length === 0) {\n return err<CronScannerError>(\n \"EmptyCronExpressionError\",\n \"Cron expression have zero length\",\n );\n }\n\n const fields = this.expression.trim().split(/\\s+/);\n const hasMinLen = fields.length === FieldAmount.min;\n const hasMaxLen = fields.length === FieldAmount.max;\n\n if (!hasMinLen && !hasMaxLen) {\n return err<CronScannerError>(\n \"CronLengthError\",\n `Invalid number of fields for '${this.expression}'. Expected 5 or 6 fields but got ${fields.length} field(s)`,\n );\n }\n\n const components = this.createComponent(fields);\n\n for (let idx = 0; idx < components.length; idx++) {\n const component = components[idx];\n if (!component) {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid cron expression: ${this.expression}`,\n );\n }\n\n this.current = 0;\n this.start = 0;\n const [error, _] = this.scanComponent(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n }\n\n return ok(this.tokens);\n }\n\n private scanComponent(component: ComponentType) {\n const { field, content } = component;\n while (this.current < content.length) {\n let currentCh = this.advance(content);\n\n switch (currentCh) {\n case \"*\": {\n const ch = this.peek(content);\n if (this.match(content, \"/\")) {\n const [error, _] = this.handleStep(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n } else if (!ch || ch === \",\") {\n this.addToken(\"*\", \"any\", \"*\", field);\n } else {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid any expression '${content}' for field '${field}'`,\n );\n }\n\n break;\n }\n case \"-\": {\n currentCh = this.advance(content);\n if (this.isDigit(currentCh)) {\n const [error, _] = this.handleRangeWithStep(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n } else {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid range expression '${content}' for field '${field}'`,\n );\n }\n break;\n }\n case \",\": {\n if (this.current === 1 && this.start === 0) {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid list expression '${content}' for field '${field}'`,\n );\n }\n\n const next = this.peek(content);\n if (!next || next === \",\") {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid list expression '${content}' for field '${field}'`,\n );\n }\n\n break;\n }\n default: {\n if (this.isDigit(currentCh)) {\n const [error, _] = this.handleNumber(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n } else {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid cron expression '${this.expression}' in field '${field}'`,\n );\n }\n\n break;\n }\n }\n\n this.start = this.current;\n }\n\n return ok(true);\n }\n\n private addToken(\n component: string,\n type: TokenType,\n value: TokenValueType,\n field: CronFieldType,\n ) {\n const token = new Token(component, type, value, field);\n this.tokens.push(token);\n }\n\n private advance(content: string) {\n const currentCh = content.charAt(this.current);\n this.current += 1;\n\n return currentCh;\n }\n\n private match(content: string, expected: string) {\n if (this.current >= content.length) return false;\n if (content.charAt(this.current) !== expected) return false;\n\n this.current += 1;\n return true;\n }\n\n private peek(content: string) {\n if (this.current >= content.length) return undefined;\n\n return content.charAt(this.current);\n }\n\n private handleStep(component: ComponentType) {\n const { field, content } = component;\n let ch = this.peek(content);\n const slashIdx = this.current - 1;\n\n while (ch && this.isDigit(ch)) {\n this.advance(content);\n ch = this.peek(content);\n }\n\n if (ch && ch !== \",\") {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid step expression '${content}' for field '${field}'`,\n );\n }\n\n const tokenContent = content.substring(this.start, this.current);\n const value = content.slice(slashIdx + 1, this.current);\n\n if (value.length === 0) {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid step expression '${content}' for field '${field}'`,\n );\n }\n\n this.addToken(tokenContent, \"step\", Number(value), field);\n return ok(true);\n }\n\n private handleRangeWithStep(component: ComponentType) {\n const { field, content } = component;\n let ch = this.peek(content);\n\n while (ch && this.isDigit(ch)) {\n this.advance(content);\n ch = this.peek(content);\n }\n\n if (!ch) {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid range expression '${content}' for field '${field}'`,\n );\n }\n\n if (this.match(content, \"/\")) {\n const [error, _] = this.handleStep(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n\n return ok(true);\n }\n\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid range expression '${content}' for field '${field}'`,\n );\n }\n\n private handleNumber(component: ComponentType) {\n const { field, content } = component;\n let ch = this.peek(content);\n this.start = this.current - 1;\n\n while (ch && this.isDigit(ch)) {\n this.advance(content);\n ch = this.peek(content);\n }\n\n if (!ch) {\n // Reached the end of the component\n const item = content.substring(this.start);\n this.addToken(item, \"number\", Number(item), field);\n return ok(true);\n }\n\n if (this.match(content, \"-\")) {\n const [error, _] = this.handleRange(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n\n return ok(true);\n }\n\n if (this.match(content, \"/\")) {\n const [error, _] = this.handleStep(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n\n return ok(true);\n }\n\n if (!this.isDigit(ch) && ch !== \",\") {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid number '${content}' for field '${field}'`,\n );\n }\n\n const item = content.substring(this.start, this.current);\n this.addToken(item, \"number\", Number(item), field);\n return ok(true);\n }\n\n private handleRange(component: ComponentType) {\n const { field, content } = component;\n let ch = this.peek(content);\n\n if (!ch) {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid range expression '${content}' for field '${field}'`,\n );\n }\n\n while (ch && this.isDigit(ch)) {\n this.advance(content);\n ch = this.peek(content);\n }\n\n if (!ch) {\n // Reached the end of the component\n const tokenContent = content.substring(this.start);\n this.addToken(tokenContent, \"range\", tokenContent, field);\n\n return ok(true);\n }\n\n if (this.match(content, \"/\")) {\n const [error, _] = this.handleStep(component);\n if (error) return err<CronScannerError>(error.type, error.message);\n\n return ok(true);\n }\n\n if (ch && ch !== \",\") {\n return err<CronScannerError>(\n \"CronExpressionError\",\n `Invalid range expression '${content}' for field '${field}'`,\n );\n }\n\n const tokenContent = content.substring(this.start, this.current);\n this.addToken(tokenContent, \"range\", tokenContent, field);\n return ok(true);\n }\n\n private isDigit(ch: string) {\n return ch >= \"0\" && ch <= \"9\";\n }\n\n private createComponent(fields: string[]) {\n const fieldNames = [\n \"second\",\n \"minute\",\n \"hour\",\n \"day\",\n \"month\",\n \"weekday\",\n ] as const;\n const components = [];\n let offset = 1;\n if (fields.length === FieldAmount.max) offset = 0;\n\n for (let idx = 0; idx < fields.length; idx++) {\n const fieldName = fieldNames[idx + offset];\n const content = fields[idx];\n if (!fieldName || !content) break;\n\n components.push({ content, field: fieldName });\n }\n\n return components;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.cts","names":[],"sources":["../../../src/lib/cron/core/types.ts"],"mappings":";KAAY,SAAA;AAAA,KAQA,UAAA;AAAA,KASA,WAAA;EACV,IAAA;EACA,QAAA,EAAU,SAAA;EACV,OAAA,eAAsB,OAAA;AAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../../src/lib/cron/core/types.ts"],"mappings":";KAAY,SAAA;AAAA,KAQA,UAAA;AAAA,KASA,WAAA;EACV,IAAA;EACA,QAAA,EAAU,SAAA;EACV,OAAA,eAAsB,OAAA;AAAA"}
|
package/dist/errors/types.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/lib/errors/types.d.ts
|
|
2
|
-
type CommonError = "NotFoundError" | "UnauthorizedError" | "InternalServerError" | "ValidationError" | (string & {});
|
|
2
|
+
type CommonError = "NotFoundError" | "UnauthorizedError" | "InternalServerError" | "ValidationError" | "MigrationError" | "SchemaError" | (string & {});
|
|
3
3
|
//#endregion
|
|
4
4
|
export { CommonError };
|
|
5
5
|
//# sourceMappingURL=types.d.cts.map
|
package/dist/errors/types.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/lib/errors/types.d.ts
|
|
2
|
-
type CommonError = "NotFoundError" | "UnauthorizedError" | "InternalServerError" | "ValidationError" | (string & {});
|
|
2
|
+
type CommonError = "NotFoundError" | "UnauthorizedError" | "InternalServerError" | "ValidationError" | "MigrationError" | "SchemaError" | (string & {});
|
|
3
3
|
//#endregion
|
|
4
4
|
export { CommonError };
|
|
5
5
|
//# sourceMappingURL=types.d.mts.map
|
|
@@ -12,7 +12,7 @@ declare class Cache<T> {
|
|
|
12
12
|
}, null] | readonly [{
|
|
13
13
|
readonly type: "CacheError";
|
|
14
14
|
readonly message: string;
|
|
15
|
-
}, null] | readonly [null, T
|
|
15
|
+
}, null] | readonly [null, T]>;
|
|
16
16
|
set(key: string, value: T): Promise<readonly [{
|
|
17
17
|
readonly type: "CacheError";
|
|
18
18
|
readonly message: string;
|
|
@@ -20,10 +20,10 @@ declare class Cache<T> {
|
|
|
20
20
|
readonly type: "InvalidTTLError";
|
|
21
21
|
readonly message: string;
|
|
22
22
|
}, null]>;
|
|
23
|
-
delete(key: string): Promise<readonly [{
|
|
23
|
+
delete(key: string): Promise<readonly [null, number] | readonly [{
|
|
24
24
|
readonly type: "CacheError";
|
|
25
25
|
readonly message: string;
|
|
26
|
-
}, null]
|
|
26
|
+
}, null]>;
|
|
27
27
|
private fail;
|
|
28
28
|
private get isEnabled();
|
|
29
29
|
private resolveKey;
|
|
@@ -12,7 +12,7 @@ declare class Cache<T> {
|
|
|
12
12
|
}, null] | readonly [{
|
|
13
13
|
readonly type: "CacheError";
|
|
14
14
|
readonly message: string;
|
|
15
|
-
}, null] | readonly [null, T
|
|
15
|
+
}, null] | readonly [null, T]>;
|
|
16
16
|
set(key: string, value: T): Promise<readonly [{
|
|
17
17
|
readonly type: "CacheError";
|
|
18
18
|
readonly message: string;
|
|
@@ -20,10 +20,10 @@ declare class Cache<T> {
|
|
|
20
20
|
readonly type: "InvalidTTLError";
|
|
21
21
|
readonly message: string;
|
|
22
22
|
}, null]>;
|
|
23
|
-
delete(key: string): Promise<readonly [{
|
|
23
|
+
delete(key: string): Promise<readonly [null, number] | readonly [{
|
|
24
24
|
readonly type: "CacheError";
|
|
25
25
|
readonly message: string;
|
|
26
|
-
}, null]
|
|
26
|
+
}, null]>;
|
|
27
27
|
private fail;
|
|
28
28
|
private get isEnabled();
|
|
29
29
|
private resolveKey;
|