@quave/agenda 1.0.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/LICENSE.md +25 -0
- package/README.md +380 -0
- package/dist/Job.d.ts +190 -0
- package/dist/Job.js +689 -0
- package/dist/Job.js.map +1 -0
- package/dist/JobProcessingQueue.d.ts +47 -0
- package/dist/JobProcessingQueue.js +107 -0
- package/dist/JobProcessingQueue.js.map +1 -0
- package/dist/JobProcessor.d.ts +72 -0
- package/dist/JobProcessor.js +512 -0
- package/dist/JobProcessor.js.map +1 -0
- package/dist/backends/index.d.ts +18 -0
- package/dist/backends/index.js +20 -0
- package/dist/backends/index.js.map +1 -0
- package/dist/cjs/Job.d.ts +190 -0
- package/dist/cjs/Job.js +696 -0
- package/dist/cjs/Job.js.map +1 -0
- package/dist/cjs/JobProcessingQueue.d.ts +47 -0
- package/dist/cjs/JobProcessingQueue.js +111 -0
- package/dist/cjs/JobProcessingQueue.js.map +1 -0
- package/dist/cjs/JobProcessor.d.ts +72 -0
- package/dist/cjs/JobProcessor.js +519 -0
- package/dist/cjs/JobProcessor.js.map +1 -0
- package/dist/cjs/backends/index.d.ts +17 -0
- package/dist/cjs/backends/index.js +20 -0
- package/dist/cjs/backends/index.js.map +1 -0
- package/dist/cjs/decorators/Define.d.ts +33 -0
- package/dist/cjs/decorators/Define.js +47 -0
- package/dist/cjs/decorators/Define.js.map +1 -0
- package/dist/cjs/decorators/Every.d.ts +43 -0
- package/dist/cjs/decorators/Every.js +58 -0
- package/dist/cjs/decorators/Every.js.map +1 -0
- package/dist/cjs/decorators/JobsController.d.ts +43 -0
- package/dist/cjs/decorators/JobsController.js +40 -0
- package/dist/cjs/decorators/JobsController.js.map +1 -0
- package/dist/cjs/decorators/index.d.ts +41 -0
- package/dist/cjs/decorators/index.js +57 -0
- package/dist/cjs/decorators/index.js.map +1 -0
- package/dist/cjs/decorators/metadata.d.ts +50 -0
- package/dist/cjs/decorators/metadata.js +41 -0
- package/dist/cjs/decorators/metadata.js.map +1 -0
- package/dist/cjs/decorators/register.d.ts +52 -0
- package/dist/cjs/decorators/register.js +145 -0
- package/dist/cjs/decorators/register.js.map +1 -0
- package/dist/cjs/index.d.ts +498 -0
- package/dist/cjs/index.js +776 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/notifications/BaseNotificationChannel.d.ts +47 -0
- package/dist/cjs/notifications/BaseNotificationChannel.js +112 -0
- package/dist/cjs/notifications/BaseNotificationChannel.js.map +1 -0
- package/dist/cjs/notifications/InMemoryNotificationChannel.d.ts +13 -0
- package/dist/cjs/notifications/InMemoryNotificationChannel.js +37 -0
- package/dist/cjs/notifications/InMemoryNotificationChannel.js.map +1 -0
- package/dist/cjs/notifications/index.d.ts +2 -0
- package/dist/cjs/notifications/index.js +8 -0
- package/dist/cjs/notifications/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types/AgendaBackend.d.ts +61 -0
- package/dist/cjs/types/AgendaBackend.js +3 -0
- package/dist/cjs/types/AgendaBackend.js.map +1 -0
- package/dist/cjs/types/AgendaConfig.d.ts +10 -0
- package/dist/cjs/types/AgendaConfig.js +3 -0
- package/dist/cjs/types/AgendaConfig.js.map +1 -0
- package/dist/cjs/types/AgendaStatus.d.ts +32 -0
- package/dist/cjs/types/AgendaStatus.js +3 -0
- package/dist/cjs/types/AgendaStatus.js.map +1 -0
- package/dist/cjs/types/DbOptions.d.ts +4 -0
- package/dist/cjs/types/DbOptions.js +3 -0
- package/dist/cjs/types/DbOptions.js.map +1 -0
- package/dist/cjs/types/DrainOptions.d.ts +37 -0
- package/dist/cjs/types/DrainOptions.js +3 -0
- package/dist/cjs/types/DrainOptions.js.map +1 -0
- package/dist/cjs/types/JobDefinition.d.ts +49 -0
- package/dist/cjs/types/JobDefinition.js +3 -0
- package/dist/cjs/types/JobDefinition.js.map +1 -0
- package/dist/cjs/types/JobLogger.d.ts +111 -0
- package/dist/cjs/types/JobLogger.js +3 -0
- package/dist/cjs/types/JobLogger.js.map +1 -0
- package/dist/cjs/types/JobParameters.d.ts +106 -0
- package/dist/cjs/types/JobParameters.js +21 -0
- package/dist/cjs/types/JobParameters.js.map +1 -0
- package/dist/cjs/types/JobQuery.d.ts +79 -0
- package/dist/cjs/types/JobQuery.js +36 -0
- package/dist/cjs/types/JobQuery.js.map +1 -0
- package/dist/cjs/types/JobRepository.d.ts +101 -0
- package/dist/cjs/types/JobRepository.js +3 -0
- package/dist/cjs/types/JobRepository.js.map +1 -0
- package/dist/cjs/types/NotificationChannel.d.ts +120 -0
- package/dist/cjs/types/NotificationChannel.js +3 -0
- package/dist/cjs/types/NotificationChannel.js.map +1 -0
- package/dist/cjs/utils/backoff.d.ts +152 -0
- package/dist/cjs/utils/backoff.js +175 -0
- package/dist/cjs/utils/backoff.js.map +1 -0
- package/dist/cjs/utils/dateConstraints.d.ts +48 -0
- package/dist/cjs/utils/dateConstraints.js +127 -0
- package/dist/cjs/utils/dateConstraints.js.map +1 -0
- package/dist/cjs/utils/isValidDate.d.ts +1 -0
- package/dist/cjs/utils/isValidDate.js +8 -0
- package/dist/cjs/utils/isValidDate.js.map +1 -0
- package/dist/cjs/utils/nextRunAt.d.ts +10 -0
- package/dist/cjs/utils/nextRunAt.js +119 -0
- package/dist/cjs/utils/nextRunAt.js.map +1 -0
- package/dist/cjs/utils/priority.d.ts +13 -0
- package/dist/cjs/utils/priority.js +23 -0
- package/dist/cjs/utils/priority.js.map +1 -0
- package/dist/cjs/utils/processEvery.d.ts +1 -0
- package/dist/cjs/utils/processEvery.js +13 -0
- package/dist/cjs/utils/processEvery.js.map +1 -0
- package/dist/cjs/utils/stack.d.ts +1 -0
- package/dist/cjs/utils/stack.js +21 -0
- package/dist/cjs/utils/stack.js.map +1 -0
- package/dist/cjs/version.d.ts +9 -0
- package/dist/cjs/version.js +13 -0
- package/dist/cjs/version.js.map +1 -0
- package/dist/decorators/Define.d.ts +33 -0
- package/dist/decorators/Define.js +44 -0
- package/dist/decorators/Define.js.map +1 -0
- package/dist/decorators/Every.d.ts +43 -0
- package/dist/decorators/Every.js +55 -0
- package/dist/decorators/Every.js.map +1 -0
- package/dist/decorators/JobsController.d.ts +43 -0
- package/dist/decorators/JobsController.js +37 -0
- package/dist/decorators/JobsController.js.map +1 -0
- package/dist/decorators/index.d.ts +41 -0
- package/dist/decorators/index.js +46 -0
- package/dist/decorators/index.js.map +1 -0
- package/dist/decorators/metadata.d.ts +50 -0
- package/dist/decorators/metadata.js +35 -0
- package/dist/decorators/metadata.js.map +1 -0
- package/dist/decorators/register.d.ts +52 -0
- package/dist/decorators/register.js +139 -0
- package/dist/decorators/register.js.map +1 -0
- package/dist/index.d.ts +498 -0
- package/dist/index.js +744 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/BaseNotificationChannel.d.ts +47 -0
- package/dist/notifications/BaseNotificationChannel.js +108 -0
- package/dist/notifications/BaseNotificationChannel.js.map +1 -0
- package/dist/notifications/InMemoryNotificationChannel.d.ts +13 -0
- package/dist/notifications/InMemoryNotificationChannel.js +33 -0
- package/dist/notifications/InMemoryNotificationChannel.js.map +1 -0
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.js +3 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/types/AgendaBackend.d.ts +61 -0
- package/dist/types/AgendaBackend.js +2 -0
- package/dist/types/AgendaBackend.js.map +1 -0
- package/dist/types/AgendaConfig.d.ts +10 -0
- package/dist/types/AgendaConfig.js +2 -0
- package/dist/types/AgendaConfig.js.map +1 -0
- package/dist/types/AgendaStatus.d.ts +32 -0
- package/dist/types/AgendaStatus.js +2 -0
- package/dist/types/AgendaStatus.js.map +1 -0
- package/dist/types/DbOptions.d.ts +4 -0
- package/dist/types/DbOptions.js +2 -0
- package/dist/types/DbOptions.js.map +1 -0
- package/dist/types/DrainOptions.d.ts +37 -0
- package/dist/types/DrainOptions.js +2 -0
- package/dist/types/DrainOptions.js.map +1 -0
- package/dist/types/JobDefinition.d.ts +49 -0
- package/dist/types/JobDefinition.js +2 -0
- package/dist/types/JobDefinition.js.map +1 -0
- package/dist/types/JobLogger.d.ts +111 -0
- package/dist/types/JobLogger.js +2 -0
- package/dist/types/JobLogger.js.map +1 -0
- package/dist/types/JobParameters.d.ts +106 -0
- package/dist/types/JobParameters.js +17 -0
- package/dist/types/JobParameters.js.map +1 -0
- package/dist/types/JobQuery.d.ts +79 -0
- package/dist/types/JobQuery.js +33 -0
- package/dist/types/JobQuery.js.map +1 -0
- package/dist/types/JobRepository.d.ts +101 -0
- package/dist/types/JobRepository.js +2 -0
- package/dist/types/JobRepository.js.map +1 -0
- package/dist/types/NotificationChannel.d.ts +120 -0
- package/dist/types/NotificationChannel.js +2 -0
- package/dist/types/NotificationChannel.js.map +1 -0
- package/dist/utils/backoff.d.ts +152 -0
- package/dist/utils/backoff.js +167 -0
- package/dist/utils/backoff.js.map +1 -0
- package/dist/utils/dateConstraints.d.ts +48 -0
- package/dist/utils/dateConstraints.js +117 -0
- package/dist/utils/dateConstraints.js.map +1 -0
- package/dist/utils/isValidDate.d.ts +1 -0
- package/dist/utils/isValidDate.js +5 -0
- package/dist/utils/isValidDate.js.map +1 -0
- package/dist/utils/nextRunAt.d.ts +10 -0
- package/dist/utils/nextRunAt.js +110 -0
- package/dist/utils/nextRunAt.js.map +1 -0
- package/dist/utils/priority.d.ts +13 -0
- package/dist/utils/priority.js +20 -0
- package/dist/utils/priority.js.map +1 -0
- package/dist/utils/processEvery.d.ts +1 -0
- package/dist/utils/processEvery.js +7 -0
- package/dist/utils/processEvery.js.map +1 -0
- package/dist/utils/stack.d.ts +1 -0
- package/dist/utils/stack.js +18 -0
- package/dist/utils/stack.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/package.json +79 -0
- package/test/fixtures/forkHelper.js +40 -0
- package/test/fixtures/someJobDefinition.ts +12 -0
- package/test/shared/agenda-test-suite.ts +1876 -0
- package/test/shared/backoff-test-suite.ts +408 -0
- package/test/shared/debounce-test-suite.ts +377 -0
- package/test/shared/full-test-suite.ts +161 -0
- package/test/shared/index.ts +50 -0
- package/test/shared/joblogger-test-suite.ts +305 -0
- package/test/shared/jobprocessor-test-suite.ts +266 -0
- package/test/shared/notification-channel-test-suite.ts +471 -0
- package/test/shared/removeoncomplete-test-suite.ts +228 -0
- package/test/shared/repository-test-suite.ts +708 -0
- package/test/shared/retry-test-suite.ts +174 -0
- package/test/shared/test-utils.ts +100 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backoff strategy utilities for job retry logic
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Apply jitter to a delay value
|
|
6
|
+
* @param delay - Base delay in milliseconds
|
|
7
|
+
* @param jitter - Jitter factor (0-1), where 0 means no jitter and 1 means up to ±100%
|
|
8
|
+
* @returns Delay with jitter applied
|
|
9
|
+
*/
|
|
10
|
+
function applyJitter(delay, jitter) {
|
|
11
|
+
if (jitter <= 0)
|
|
12
|
+
return delay;
|
|
13
|
+
// Random value between -jitter and +jitter
|
|
14
|
+
const jitterAmount = delay * jitter * (Math.random() * 2 - 1);
|
|
15
|
+
return Math.max(0, Math.round(delay + jitterAmount));
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Constant backoff - same delay between each retry
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* agenda.define('myJob', handler, {
|
|
23
|
+
* backoff: constant({ delay: 5000, maxRetries: 5 })
|
|
24
|
+
* });
|
|
25
|
+
* // Retries at: 5s, 5s, 5s, 5s, 5s
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function constant(options = {}) {
|
|
29
|
+
const { delay = 1000, maxDelay = Infinity, maxRetries = 3, jitter = 0 } = options;
|
|
30
|
+
return (context) => {
|
|
31
|
+
if (context.attempt > maxRetries) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
const baseDelay = Math.min(delay, maxDelay);
|
|
35
|
+
return applyJitter(baseDelay, jitter);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Linear backoff - delay increases by a fixed amount each retry
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* agenda.define('myJob', handler, {
|
|
44
|
+
* backoff: linear({ delay: 1000, increment: 2000, maxRetries: 4 })
|
|
45
|
+
* });
|
|
46
|
+
* // Retries at: 1s, 3s, 5s, 7s
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function linear(options = {}) {
|
|
50
|
+
const { delay = 1000, increment = delay, maxDelay = Infinity, maxRetries = 3, jitter = 0 } = options;
|
|
51
|
+
return (context) => {
|
|
52
|
+
if (context.attempt > maxRetries) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
const baseDelay = delay + increment * (context.attempt - 1);
|
|
56
|
+
const cappedDelay = Math.min(baseDelay, maxDelay);
|
|
57
|
+
return applyJitter(cappedDelay, jitter);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Exponential backoff - delay multiplies by a factor each retry
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* agenda.define('myJob', handler, {
|
|
66
|
+
* backoff: exponential({ delay: 1000, factor: 2, maxRetries: 5 })
|
|
67
|
+
* });
|
|
68
|
+
* // Retries at: 1s, 2s, 4s, 8s, 16s
|
|
69
|
+
*
|
|
70
|
+
* // With jitter to prevent thundering herd:
|
|
71
|
+
* agenda.define('myJob', handler, {
|
|
72
|
+
* backoff: exponential({ delay: 1000, factor: 2, maxRetries: 5, jitter: 0.2 })
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
export function exponential(options = {}) {
|
|
77
|
+
const { delay = 1000, factor = 2, maxDelay = Infinity, maxRetries = 3, jitter = 0 } = options;
|
|
78
|
+
return (context) => {
|
|
79
|
+
if (context.attempt > maxRetries) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const baseDelay = delay * Math.pow(factor, context.attempt - 1);
|
|
83
|
+
const cappedDelay = Math.min(baseDelay, maxDelay);
|
|
84
|
+
return applyJitter(cappedDelay, jitter);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Combine multiple strategies - tries each in sequence until one returns non-null
|
|
89
|
+
* Useful for implementing complex retry logic
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* // Retry quickly at first, then back off
|
|
94
|
+
* agenda.define('myJob', handler, {
|
|
95
|
+
* backoff: combine(
|
|
96
|
+
* // First 2 retries: immediate (100ms)
|
|
97
|
+
* (ctx) => ctx.attempt <= 2 ? 100 : null,
|
|
98
|
+
* // Then exponential backoff for 3 more attempts
|
|
99
|
+
* exponential({ delay: 1000, maxRetries: 3 })
|
|
100
|
+
* )
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function combine(...strategies) {
|
|
105
|
+
return (context) => {
|
|
106
|
+
for (const strategy of strategies) {
|
|
107
|
+
const result = strategy(context);
|
|
108
|
+
if (result !== null) {
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Conditional backoff - only retry if condition is met
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* // Only retry on specific errors
|
|
121
|
+
* agenda.define('myJob', handler, {
|
|
122
|
+
* backoff: when(
|
|
123
|
+
* (ctx) => ctx.error.message.includes('timeout'),
|
|
124
|
+
* exponential({ delay: 1000, maxRetries: 3 })
|
|
125
|
+
* )
|
|
126
|
+
* });
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export function when(condition, strategy) {
|
|
130
|
+
return (context) => {
|
|
131
|
+
if (!condition(context)) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
return strategy(context);
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Pre-configured backoff strategies for common use cases
|
|
139
|
+
*/
|
|
140
|
+
export const backoffStrategies = {
|
|
141
|
+
/** Constant 1s delay, 3 retries */
|
|
142
|
+
constant,
|
|
143
|
+
/** Linear increase starting at 1s, 3 retries */
|
|
144
|
+
linear,
|
|
145
|
+
/** Exponential with factor 2, starting at 1s, 3 retries */
|
|
146
|
+
exponential,
|
|
147
|
+
/** Combine multiple strategies */
|
|
148
|
+
combine,
|
|
149
|
+
/** Conditional retry */
|
|
150
|
+
when,
|
|
151
|
+
/**
|
|
152
|
+
* Aggressive retry - quick retries for transient failures
|
|
153
|
+
* 100ms, 200ms, 400ms (3 retries in ~700ms total)
|
|
154
|
+
*/
|
|
155
|
+
aggressive: () => exponential({ delay: 100, factor: 2, maxRetries: 3 }),
|
|
156
|
+
/**
|
|
157
|
+
* Relaxed retry - gentle backoff for rate-limited APIs
|
|
158
|
+
* 5s, 15s, 45s, 135s (4 retries over ~3 minutes)
|
|
159
|
+
*/
|
|
160
|
+
relaxed: () => exponential({ delay: 5000, factor: 3, maxRetries: 4, jitter: 0.1 }),
|
|
161
|
+
/**
|
|
162
|
+
* Standard retry - balanced approach
|
|
163
|
+
* 1s, 2s, 4s, 8s, 16s (5 retries over ~31 seconds)
|
|
164
|
+
*/
|
|
165
|
+
standard: () => exponential({ delay: 1000, factor: 2, maxRetries: 5, jitter: 0.1 })
|
|
166
|
+
};
|
|
167
|
+
//# sourceMappingURL=backoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backoff.js","sourceRoot":"","sources":["../../src/utils/backoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check if a given date should be skipped based on the skip days configuration.
|
|
3
|
+
* @param date - The date to check
|
|
4
|
+
* @param skipDays - Array of days to skip (0 = Sunday, 1 = Monday, ..., 6 = Saturday)
|
|
5
|
+
* @param timezone - Optional timezone for the check
|
|
6
|
+
* @returns true if the day should be skipped
|
|
7
|
+
*/
|
|
8
|
+
export declare function shouldSkipDay(date: Date, skipDays?: number[], timezone?: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Applies skip days constraint to a date, moving forward to the next valid day.
|
|
11
|
+
* Preserves the time of day from the original date.
|
|
12
|
+
* @param date - The original date
|
|
13
|
+
* @param skipDays - Array of days to skip (0 = Sunday, 1 = Monday, ..., 6 = Saturday)
|
|
14
|
+
* @param timezone - Optional timezone
|
|
15
|
+
* @returns The adjusted date on a valid day, or null if no valid day found
|
|
16
|
+
*/
|
|
17
|
+
export declare function applySkipDays(date: Date, skipDays?: number[], timezone?: string): Date | null;
|
|
18
|
+
/**
|
|
19
|
+
* Applies date range constraints to a nextRunAt date.
|
|
20
|
+
* - If nextRunAt is before startDate, returns startDate
|
|
21
|
+
* - If nextRunAt is after endDate, returns null (job should not run)
|
|
22
|
+
* @param nextRunAt - The computed next run time
|
|
23
|
+
* @param startDate - Optional start date constraint
|
|
24
|
+
* @param endDate - Optional end date constraint
|
|
25
|
+
* @returns The adjusted date, or null if outside valid range
|
|
26
|
+
*/
|
|
27
|
+
export declare function applyDateRangeConstraints(nextRunAt: Date, startDate?: Date, endDate?: Date): Date | null;
|
|
28
|
+
/**
|
|
29
|
+
* Apply all date constraints (date range and skip days) to a computed nextRunAt.
|
|
30
|
+
* This is the main function to use when computing nextRunAt.
|
|
31
|
+
* @param nextRunAt - The base computed next run time
|
|
32
|
+
* @param options - Constraint options
|
|
33
|
+
* @returns The adjusted date respecting all constraints, or null if invalid
|
|
34
|
+
*/
|
|
35
|
+
export declare function applyAllDateConstraints(nextRunAt: Date, options: {
|
|
36
|
+
startDate?: Date;
|
|
37
|
+
endDate?: Date;
|
|
38
|
+
skipDays?: number[];
|
|
39
|
+
timezone?: string;
|
|
40
|
+
}): Date | null;
|
|
41
|
+
/**
|
|
42
|
+
* Check if a date is within the valid date range.
|
|
43
|
+
* @param date - The date to check
|
|
44
|
+
* @param startDate - Optional start date constraint
|
|
45
|
+
* @param endDate - Optional end date constraint
|
|
46
|
+
* @returns true if the date is within the valid range
|
|
47
|
+
*/
|
|
48
|
+
export declare function isWithinDateRange(date: Date, startDate?: Date, endDate?: Date): boolean;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { DateTime } from 'luxon';
|
|
2
|
+
import debug from 'debug';
|
|
3
|
+
const log = debug('agenda:dateConstraints');
|
|
4
|
+
/**
|
|
5
|
+
* Check if a given date should be skipped based on the skip days configuration.
|
|
6
|
+
* @param date - The date to check
|
|
7
|
+
* @param skipDays - Array of days to skip (0 = Sunday, 1 = Monday, ..., 6 = Saturday)
|
|
8
|
+
* @param timezone - Optional timezone for the check
|
|
9
|
+
* @returns true if the day should be skipped
|
|
10
|
+
*/
|
|
11
|
+
export function shouldSkipDay(date, skipDays, timezone) {
|
|
12
|
+
if (!skipDays || skipDays.length === 0) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const dt = timezone
|
|
16
|
+
? DateTime.fromJSDate(date, { zone: timezone })
|
|
17
|
+
: DateTime.fromJSDate(date);
|
|
18
|
+
// Luxon weekday: 1 = Monday, 7 = Sunday
|
|
19
|
+
// Convert to JS weekday: 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
|
20
|
+
const jsWeekday = dt.weekday === 7 ? 0 : dt.weekday;
|
|
21
|
+
return skipDays.includes(jsWeekday);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Applies skip days constraint to a date, moving forward to the next valid day.
|
|
25
|
+
* Preserves the time of day from the original date.
|
|
26
|
+
* @param date - The original date
|
|
27
|
+
* @param skipDays - Array of days to skip (0 = Sunday, 1 = Monday, ..., 6 = Saturday)
|
|
28
|
+
* @param timezone - Optional timezone
|
|
29
|
+
* @returns The adjusted date on a valid day, or null if no valid day found
|
|
30
|
+
*/
|
|
31
|
+
export function applySkipDays(date, skipDays, timezone) {
|
|
32
|
+
if (!skipDays || skipDays.length === 0) {
|
|
33
|
+
return date;
|
|
34
|
+
}
|
|
35
|
+
// Validate skip days - if all days are skipped, return null
|
|
36
|
+
if (skipDays.length >= 7) {
|
|
37
|
+
log('all days are marked as skip days, returning null');
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
let dt = timezone
|
|
41
|
+
? DateTime.fromJSDate(date, { zone: timezone })
|
|
42
|
+
: DateTime.fromJSDate(date);
|
|
43
|
+
// Luxon weekday: 1 = Monday, 7 = Sunday
|
|
44
|
+
// Convert to JS weekday: 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
|
45
|
+
const getJsWeekday = (luxonDt) => luxonDt.weekday === 7 ? 0 : luxonDt.weekday;
|
|
46
|
+
// Terminates within 6 steps: covering all 7 weekdays needs 7 distinct
|
|
47
|
+
// entries, which the length >= 7 guard above already rejected.
|
|
48
|
+
while (skipDays.includes(getJsWeekday(dt))) {
|
|
49
|
+
dt = dt.plus({ days: 1 });
|
|
50
|
+
log('skipping day, moved to %s', dt.toISO());
|
|
51
|
+
}
|
|
52
|
+
return dt.toJSDate();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Applies date range constraints to a nextRunAt date.
|
|
56
|
+
* - If nextRunAt is before startDate, returns startDate
|
|
57
|
+
* - If nextRunAt is after endDate, returns null (job should not run)
|
|
58
|
+
* @param nextRunAt - The computed next run time
|
|
59
|
+
* @param startDate - Optional start date constraint
|
|
60
|
+
* @param endDate - Optional end date constraint
|
|
61
|
+
* @returns The adjusted date, or null if outside valid range
|
|
62
|
+
*/
|
|
63
|
+
export function applyDateRangeConstraints(nextRunAt, startDate, endDate) {
|
|
64
|
+
let result = nextRunAt;
|
|
65
|
+
// If before start date, move to start date
|
|
66
|
+
if (startDate && result < startDate) {
|
|
67
|
+
log('nextRunAt %s is before startDate %s, adjusting', result.toISOString(), startDate.toISOString());
|
|
68
|
+
result = new Date(startDate);
|
|
69
|
+
}
|
|
70
|
+
// If after end date, return null (job should stop)
|
|
71
|
+
if (endDate && result > endDate) {
|
|
72
|
+
log('nextRunAt %s is after endDate %s, returning null', result.toISOString(), endDate.toISOString());
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Apply all date constraints (date range and skip days) to a computed nextRunAt.
|
|
79
|
+
* This is the main function to use when computing nextRunAt.
|
|
80
|
+
* @param nextRunAt - The base computed next run time
|
|
81
|
+
* @param options - Constraint options
|
|
82
|
+
* @returns The adjusted date respecting all constraints, or null if invalid
|
|
83
|
+
*/
|
|
84
|
+
export function applyAllDateConstraints(nextRunAt, options) {
|
|
85
|
+
const { startDate, endDate, skipDays, timezone } = options;
|
|
86
|
+
// Step 1: If before startDate, move to startDate. The endDate check
|
|
87
|
+
// happens in step 3, after skip days may have moved the date.
|
|
88
|
+
let result = startDate && nextRunAt < startDate ? new Date(startDate) : nextRunAt;
|
|
89
|
+
// Step 2: Apply skip days
|
|
90
|
+
result = applySkipDays(result, skipDays, timezone);
|
|
91
|
+
if (!result) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
// Step 3: Check end date constraint again (skip days may have moved the date)
|
|
95
|
+
if (endDate && result > endDate) {
|
|
96
|
+
log('after skip days adjustment, date %s is after endDate %s', result.toISOString(), endDate.toISOString());
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if a date is within the valid date range.
|
|
103
|
+
* @param date - The date to check
|
|
104
|
+
* @param startDate - Optional start date constraint
|
|
105
|
+
* @param endDate - Optional end date constraint
|
|
106
|
+
* @returns true if the date is within the valid range
|
|
107
|
+
*/
|
|
108
|
+
export function isWithinDateRange(date, startDate, endDate) {
|
|
109
|
+
if (startDate && date < startDate) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
if (endDate && date > endDate) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=dateConstraints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dateConstraints.js","sourceRoot":"","sources":["../../src/utils/dateConstraints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,GAAG,GAAG,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAE5C;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC5B,IAAU,EACV,QAAmB,EACnB,QAAiB;IAEjB,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,EAAE,GAAG,QAAQ;QAClB,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC/C,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAE7B,wCAAwC;IACxC,mEAAmE;IACnE,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC;IAEpD,OAAO,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC5B,IAAU,EACV,QAAmB,EACnB,QAAiB;IAEjB,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,IAAI,CAAC;IACb,CAAC;IAED,4DAA4D;IAC5D,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QAC1B,GAAG,CAAC,kDAAkD,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,EAAE,GAAG,QAAQ;QAChB,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC/C,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAE7B,wCAAwC;IACxC,mEAAmE;IACnE,MAAM,YAAY,GAAG,CAAC,OAAiB,EAAE,EAAE,CAC1C,OAAO,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAE7C,sEAAsE;IACtE,+DAA+D;IAC/D,OAAO,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QAC5C,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;QAC1B,GAAG,CAAC,2BAA2B,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACxC,SAAe,EACf,SAAgB,EAChB,OAAc;IAEd,IAAI,MAAM,GAAG,SAAS,CAAC;IAEvB,2CAA2C;IAC3C,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,EAAE,CAAC;QACrC,GAAG,CAAC,gDAAgD,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;QACrG,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9B,CAAC;IAED,mDAAmD;IACnD,IAAI,OAAO,IAAI,MAAM,GAAG,OAAO,EAAE,CAAC;QACjC,GAAG,CAAC,kDAAkD,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QACrG,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACtC,SAAe,EACf,OAKC;IAED,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAE3D,oEAAoE;IACpE,8DAA8D;IAC9D,IAAI,MAAM,GACT,SAAS,IAAI,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEtE,0BAA0B;IAC1B,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IACb,CAAC;IAED,8EAA8E;IAC9E,IAAI,OAAO,IAAI,MAAM,GAAG,OAAO,EAAE,CAAC;QACjC,GAAG,CAAC,yDAAyD,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QAC5G,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAChC,IAAU,EACV,SAAgB,EAChB,OAAc;IAEd,IAAI,SAAS,IAAI,IAAI,GAAG,SAAS,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,OAAO,IAAI,IAAI,GAAG,OAAO,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isValidDate(date: unknown): date is Date;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isValidDate.js","sourceRoot":"","sources":["../../src/utils/isValidDate.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,IAAa;IACxC,mDAAmD;IACnD,OAAO,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,IAAc,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,KAAK,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { JobParameters } from '../types/JobParameters.js';
|
|
2
|
+
export declare function isValidHumanInterval(value: unknown): value is string;
|
|
3
|
+
/**
|
|
4
|
+
* Internal method that computes the interval
|
|
5
|
+
*/
|
|
6
|
+
export declare const computeFromInterval: (attrs: JobParameters<unknown>) => Date | null;
|
|
7
|
+
/**
|
|
8
|
+
* Internal method to compute next run time from the repeat string
|
|
9
|
+
*/
|
|
10
|
+
export declare function computeFromRepeatAt(attrs: JobParameters<unknown>): Date | null;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { DateTime } from 'luxon';
|
|
2
|
+
import date from 'date.js';
|
|
3
|
+
import debug from 'debug';
|
|
4
|
+
import { CronExpressionParser } from 'cron-parser';
|
|
5
|
+
import humanInterval from 'human-interval';
|
|
6
|
+
import { isValidDate } from './isValidDate.js';
|
|
7
|
+
import { applyAllDateConstraints } from './dateConstraints.js';
|
|
8
|
+
const log = debug('agenda:nextRunAt');
|
|
9
|
+
const dateForTimezone = (timezoneDate, timezone) => DateTime.fromJSDate(timezoneDate, { zone: timezone });
|
|
10
|
+
export function isValidHumanInterval(value) {
|
|
11
|
+
const transformedValue = humanInterval(value);
|
|
12
|
+
return typeof transformedValue === 'number' && Number.isNaN(transformedValue) === false;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Internal method that computes the interval
|
|
16
|
+
*/
|
|
17
|
+
export const computeFromInterval = (attrs) => {
|
|
18
|
+
const previousNextRunAt = attrs.nextRunAt || new Date();
|
|
19
|
+
log('[%s:%s] computing next run via interval [%s]', attrs.name, attrs._id, attrs.repeatInterval);
|
|
20
|
+
const lastRun = dateForTimezone(attrs.lastRunAt || new Date(), attrs.repeatTimezone);
|
|
21
|
+
const cronOptions = {
|
|
22
|
+
currentDate: lastRun.toJSDate(),
|
|
23
|
+
tz: attrs.repeatTimezone
|
|
24
|
+
};
|
|
25
|
+
let nextRunAt = null;
|
|
26
|
+
let error;
|
|
27
|
+
if (typeof attrs.repeatInterval === 'string') {
|
|
28
|
+
try {
|
|
29
|
+
let cronTime = CronExpressionParser.parse(attrs.repeatInterval, cronOptions);
|
|
30
|
+
let nextDate = cronTime.next().toDate();
|
|
31
|
+
if (nextDate.valueOf() === lastRun.valueOf() ||
|
|
32
|
+
nextDate.valueOf() <= previousNextRunAt.valueOf()) {
|
|
33
|
+
// Handle cronTime giving back the same date for the next run time
|
|
34
|
+
cronOptions.currentDate = new Date(lastRun.valueOf() + 1000);
|
|
35
|
+
cronTime = CronExpressionParser.parse(attrs.repeatInterval, cronOptions);
|
|
36
|
+
nextDate = cronTime.next().toDate();
|
|
37
|
+
}
|
|
38
|
+
nextRunAt = nextDate;
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
error = err;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (isValidHumanInterval(attrs.repeatInterval)) {
|
|
45
|
+
if (!attrs.lastRunAt) {
|
|
46
|
+
nextRunAt = new Date(lastRun.valueOf());
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const intervalValue = humanInterval(attrs.repeatInterval);
|
|
50
|
+
nextRunAt = new Date(lastRun.valueOf() + intervalValue);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!isValidDate(nextRunAt)) {
|
|
54
|
+
log('[%s:%s] failed to calculate nextRunAt due to invalid repeat interval', attrs.name, attrs._id);
|
|
55
|
+
throw new Error(`failed to calculate nextRunAt due to invalid repeat interval (${attrs.repeatInterval}): ${error || 'no readable human interval'}`);
|
|
56
|
+
}
|
|
57
|
+
// Apply date constraints (startDate, endDate, skipDays)
|
|
58
|
+
if (attrs.startDate || attrs.endDate || attrs.skipDays) {
|
|
59
|
+
nextRunAt = applyAllDateConstraints(nextRunAt, {
|
|
60
|
+
startDate: attrs.startDate,
|
|
61
|
+
endDate: attrs.endDate,
|
|
62
|
+
skipDays: attrs.skipDays,
|
|
63
|
+
timezone: attrs.repeatTimezone
|
|
64
|
+
});
|
|
65
|
+
if (nextRunAt === null) {
|
|
66
|
+
log('[%s:%s] nextRunAt is null after applying date constraints', attrs.name, attrs._id);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return nextRunAt;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Internal method to compute next run time from the repeat string
|
|
73
|
+
*/
|
|
74
|
+
export function computeFromRepeatAt(attrs) {
|
|
75
|
+
const lastRun = attrs.lastRunAt || new Date();
|
|
76
|
+
const repeatAt = attrs.repeatAt;
|
|
77
|
+
if (!repeatAt) {
|
|
78
|
+
throw new Error('repeatAt is required');
|
|
79
|
+
}
|
|
80
|
+
const nextDate = date(repeatAt).valueOf();
|
|
81
|
+
// If you do not specify offset date for below test it will fail for ms
|
|
82
|
+
const offset = Date.now();
|
|
83
|
+
if (offset === date(repeatAt, new Date(offset)).valueOf()) {
|
|
84
|
+
log('[%s:%s] failed to calculate repeatAt due to invalid format', attrs.name, attrs._id);
|
|
85
|
+
throw new Error('failed to calculate repeatAt time due to invalid format');
|
|
86
|
+
}
|
|
87
|
+
let nextRunAt;
|
|
88
|
+
if (nextDate === lastRun.valueOf()) {
|
|
89
|
+
nextRunAt = date('tomorrow at ' + repeatAt);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
nextRunAt = date(repeatAt);
|
|
93
|
+
}
|
|
94
|
+
// Apply date constraints (startDate, endDate, skipDays)
|
|
95
|
+
if (attrs.startDate || attrs.endDate || attrs.skipDays) {
|
|
96
|
+
const constrainedDate = applyAllDateConstraints(nextRunAt, {
|
|
97
|
+
startDate: attrs.startDate,
|
|
98
|
+
endDate: attrs.endDate,
|
|
99
|
+
skipDays: attrs.skipDays,
|
|
100
|
+
timezone: attrs.repeatTimezone
|
|
101
|
+
});
|
|
102
|
+
if (constrainedDate === null) {
|
|
103
|
+
log('[%s:%s] nextRunAt is null after applying date constraints', attrs.name, attrs._id);
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
nextRunAt = constrainedDate;
|
|
107
|
+
}
|
|
108
|
+
return nextRunAt;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=nextRunAt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextRunAt.js","sourceRoot":"","sources":["../../src/utils/nextRunAt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type JobPriority = number | keyof typeof priorityMap;
|
|
2
|
+
declare const priorityMap: {
|
|
3
|
+
lowest: number;
|
|
4
|
+
low: number;
|
|
5
|
+
normal: number;
|
|
6
|
+
high: number;
|
|
7
|
+
highest: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Internal method to turn priority into a number
|
|
11
|
+
*/
|
|
12
|
+
export declare function parsePriority(priority?: JobPriority): number;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const priorityMap = {
|
|
2
|
+
lowest: -20,
|
|
3
|
+
low: -10,
|
|
4
|
+
normal: 0,
|
|
5
|
+
high: 10,
|
|
6
|
+
highest: 20
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Internal method to turn priority into a number
|
|
10
|
+
*/
|
|
11
|
+
export function parsePriority(priority) {
|
|
12
|
+
if (typeof priority === 'number') {
|
|
13
|
+
return priority;
|
|
14
|
+
}
|
|
15
|
+
if (typeof priority === 'string' && priorityMap[priority]) {
|
|
16
|
+
return priorityMap[priority];
|
|
17
|
+
}
|
|
18
|
+
return priorityMap.normal;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=priority.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"priority.js","sourceRoot":"","sources":["../../src/utils/priority.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG;IACnB,MAAM,EAAE,CAAC,EAAE;IACX,GAAG,EAAE,CAAC,EAAE;IACR,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,EAAE;IACR,OAAO,EAAE,EAAE;CACX,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,QAAsB;IACnD,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3D,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,WAAW,CAAC,MAAM,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function calculateProcessEvery(input?: number | string): number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"processEvery.js","sourceRoot":"","sources":["../../src/utils/processEvery.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAE3C,MAAM,UAAU,qBAAqB,CAAC,QAAyB,IAAI;IAClE,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,OAAQ,aAAa,CAAC,KAAK,CAAY,IAAI,IAAI,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getCallerFilePath(position?: number): string | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function getCallerFilePath(position = 2) {
|
|
2
|
+
if (position >= Error.stackTraceLimit) {
|
|
3
|
+
throw new TypeError(`getCallerFile(position) requires position be less then Error.stackTraceLimit but position was: \`${position}\` and Error.stackTraceLimit was: \`${Error.stackTraceLimit}\``);
|
|
4
|
+
}
|
|
5
|
+
const oldPrepareStackTrace = Error.prepareStackTrace;
|
|
6
|
+
Error.prepareStackTrace = (_, stack) => stack;
|
|
7
|
+
const { stack } = new Error();
|
|
8
|
+
Error.prepareStackTrace = oldPrepareStackTrace;
|
|
9
|
+
if (stack !== null && typeof stack === 'object') {
|
|
10
|
+
// stack[0] holds this file
|
|
11
|
+
// stack[1] holds where this function was called
|
|
12
|
+
// stack[2] holds the file we're interested in
|
|
13
|
+
const callSite = stack[position];
|
|
14
|
+
return callSite?.getFileName() ?? undefined;
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stack.js","sourceRoot":"","sources":["../../src/utils/stack.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iBAAiB,CAAC,QAAQ,GAAG,CAAC;IAC7C,IAAI,QAAQ,IAAI,KAAK,CAAC,eAAe,EAAE,CAAC;QACvC,MAAM,IAAI,SAAS,CAClB,oGAAoG,QAAQ,uCAAuC,KAAK,CAAC,eAAe,IAAI,CAC5K,CAAC;IACH,CAAC;IAED,MAAM,oBAAoB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IACrD,KAAK,CAAC,iBAAiB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC;IAC9C,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,KAAK,EAAE,CAAC;IAC9B,KAAK,CAAC,iBAAiB,GAAG,oBAAoB,CAAC;IAE/C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACjD,2BAA2B;QAC3B,gDAAgD;QAChD,8CAA8C;QAC9C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAgC,CAAC;QAChE,OAAO,QAAQ,EAAE,WAAW,EAAE,IAAI,SAAS,CAAC;IAC7C,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package version, reported by getRunningStats().
|
|
3
|
+
*
|
|
4
|
+
* Kept as a source constant (instead of importing package.json) so the
|
|
5
|
+
* emitted code stays free of import.meta and JSON import attributes —
|
|
6
|
+
* required for the CommonJS build and for old runtimes (Meteor 2.x runs
|
|
7
|
+
* Node 14). A unit test asserts it matches package.json.
|
|
8
|
+
*/
|
|
9
|
+
export declare const agendaVersion = "1.0.0";
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package version, reported by getRunningStats().
|
|
3
|
+
*
|
|
4
|
+
* Kept as a source constant (instead of importing package.json) so the
|
|
5
|
+
* emitted code stays free of import.meta and JSON import attributes —
|
|
6
|
+
* required for the CommonJS build and for old runtimes (Meteor 2.x runs
|
|
7
|
+
* Node 14). A unit test asserts it matches package.json.
|
|
8
|
+
*/
|
|
9
|
+
export const agendaVersion = '1.0.0';
|
|
10
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC"}
|