@sentry/junior-scheduler 0.57.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 +201 -0
- package/dist/cadence.d.ts +24 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1655 -0
- package/dist/plugin.d.ts +4 -0
- package/dist/prompt.d.ts +7 -0
- package/dist/schedule-tools.d.ts +25 -0
- package/dist/store.d.ts +49 -0
- package/dist/types.d.ts +86 -0
- package/package.json +38 -0
- package/plugin.yaml +2 -0
- package/src/cadence.ts +501 -0
- package/src/index.ts +27 -0
- package/src/plugin.ts +312 -0
- package/src/prompt.ts +89 -0
- package/src/schedule-tools.ts +640 -0
- package/src/store.ts +819 -0
- package/src/types.ts +110 -0
package/src/cadence.ts
ADDED
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ScheduledCalendarFrequency,
|
|
3
|
+
ScheduledLocalTime,
|
|
4
|
+
ScheduledTask,
|
|
5
|
+
ScheduledTaskRecurrence,
|
|
6
|
+
} from "./types";
|
|
7
|
+
|
|
8
|
+
/** Parse an ISO timestamp into a finite Unix timestamp in milliseconds. */
|
|
9
|
+
export function parseScheduleTimestamp(value: string): number | undefined {
|
|
10
|
+
const trimmed = value.trim();
|
|
11
|
+
const match =
|
|
12
|
+
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2})(?:\.\d{1,9})?)?(Z|[+-]\d{2}:\d{2})$/.exec(
|
|
13
|
+
trimmed,
|
|
14
|
+
);
|
|
15
|
+
if (!match) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const year = Number(match[1]);
|
|
20
|
+
const month = Number(match[2]);
|
|
21
|
+
const day = Number(match[3]);
|
|
22
|
+
const hour = Number(match[4]);
|
|
23
|
+
const minute = Number(match[5]);
|
|
24
|
+
const second = match[6] ? Number(match[6]) : 0;
|
|
25
|
+
if (
|
|
26
|
+
!Number.isInteger(year) ||
|
|
27
|
+
!Number.isInteger(month) ||
|
|
28
|
+
!Number.isInteger(day) ||
|
|
29
|
+
!Number.isInteger(hour) ||
|
|
30
|
+
!Number.isInteger(minute) ||
|
|
31
|
+
!Number.isInteger(second) ||
|
|
32
|
+
month < 1 ||
|
|
33
|
+
month > 12 ||
|
|
34
|
+
day < 1 ||
|
|
35
|
+
day > daysInMonth(year, month) ||
|
|
36
|
+
hour < 0 ||
|
|
37
|
+
hour > 23 ||
|
|
38
|
+
minute < 0 ||
|
|
39
|
+
minute > 59 ||
|
|
40
|
+
second < 0 ||
|
|
41
|
+
second > 59
|
|
42
|
+
) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const parsed = Date.parse(trimmed);
|
|
47
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface ZonedDateTimeParts {
|
|
51
|
+
day: number;
|
|
52
|
+
hour: number;
|
|
53
|
+
minute: number;
|
|
54
|
+
month: number;
|
|
55
|
+
second: number;
|
|
56
|
+
weekday: number;
|
|
57
|
+
year: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface LocalDate {
|
|
61
|
+
day: number;
|
|
62
|
+
month: number;
|
|
63
|
+
year: number;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const FORMATTERS = new Map<string, Intl.DateTimeFormat>();
|
|
67
|
+
|
|
68
|
+
function getFormatter(timezone: string): Intl.DateTimeFormat {
|
|
69
|
+
const existing = FORMATTERS.get(timezone);
|
|
70
|
+
if (existing) {
|
|
71
|
+
return existing;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
75
|
+
timeZone: timezone,
|
|
76
|
+
hour12: false,
|
|
77
|
+
year: "numeric",
|
|
78
|
+
month: "2-digit",
|
|
79
|
+
day: "2-digit",
|
|
80
|
+
hour: "2-digit",
|
|
81
|
+
minute: "2-digit",
|
|
82
|
+
second: "2-digit",
|
|
83
|
+
});
|
|
84
|
+
FORMATTERS.set(timezone, formatter);
|
|
85
|
+
return formatter;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function normalizeHour(hour: number): number {
|
|
89
|
+
return hour === 24 ? 0 : hour;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getLocalDateWeekday(date: LocalDate): number {
|
|
93
|
+
return new Date(Date.UTC(date.year, date.month - 1, date.day)).getUTCDay();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Resolve a UTC timestamp into calendar parts for a named time zone. */
|
|
97
|
+
export function getZonedDateTimeParts(
|
|
98
|
+
timestampMs: number,
|
|
99
|
+
timezone: string,
|
|
100
|
+
): ZonedDateTimeParts {
|
|
101
|
+
const parts = getFormatter(timezone).formatToParts(new Date(timestampMs));
|
|
102
|
+
const values = new Map(parts.map((part) => [part.type, part.value]));
|
|
103
|
+
const year = Number(values.get("year"));
|
|
104
|
+
const month = Number(values.get("month"));
|
|
105
|
+
const day = Number(values.get("day"));
|
|
106
|
+
const hour = normalizeHour(Number(values.get("hour")));
|
|
107
|
+
const minute = Number(values.get("minute"));
|
|
108
|
+
const second = Number(values.get("second"));
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
year,
|
|
112
|
+
month,
|
|
113
|
+
day,
|
|
114
|
+
hour,
|
|
115
|
+
minute,
|
|
116
|
+
second,
|
|
117
|
+
weekday: getLocalDateWeekday({ year, month, day }),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getTimeZoneOffsetMs(timestampMs: number, timezone: string): number {
|
|
122
|
+
const parts = getZonedDateTimeParts(timestampMs, timezone);
|
|
123
|
+
return (
|
|
124
|
+
Date.UTC(
|
|
125
|
+
parts.year,
|
|
126
|
+
parts.month - 1,
|
|
127
|
+
parts.day,
|
|
128
|
+
parts.hour,
|
|
129
|
+
parts.minute,
|
|
130
|
+
parts.second,
|
|
131
|
+
) - timestampMs
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function localDateTimeToTimestampMs(args: {
|
|
136
|
+
date: LocalDate;
|
|
137
|
+
time: ScheduledLocalTime;
|
|
138
|
+
timezone: string;
|
|
139
|
+
}): number {
|
|
140
|
+
const localAsUtcMs = Date.UTC(
|
|
141
|
+
args.date.year,
|
|
142
|
+
args.date.month - 1,
|
|
143
|
+
args.date.day,
|
|
144
|
+
args.time.hour,
|
|
145
|
+
args.time.minute,
|
|
146
|
+
0,
|
|
147
|
+
);
|
|
148
|
+
let timestampMs =
|
|
149
|
+
localAsUtcMs - getTimeZoneOffsetMs(localAsUtcMs, args.timezone);
|
|
150
|
+
|
|
151
|
+
for (let index = 0; index < 3; index += 1) {
|
|
152
|
+
const next = localAsUtcMs - getTimeZoneOffsetMs(timestampMs, args.timezone);
|
|
153
|
+
if (next === timestampMs) {
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
timestampMs = next;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return timestampMs;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function compareDate(left: LocalDate, right: LocalDate): number {
|
|
163
|
+
return (
|
|
164
|
+
Date.UTC(left.year, left.month - 1, left.day) -
|
|
165
|
+
Date.UTC(right.year, right.month - 1, right.day)
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function addDays(date: LocalDate, days: number): LocalDate {
|
|
170
|
+
const next = new Date(Date.UTC(date.year, date.month - 1, date.day + days));
|
|
171
|
+
return {
|
|
172
|
+
year: next.getUTCFullYear(),
|
|
173
|
+
month: next.getUTCMonth() + 1,
|
|
174
|
+
day: next.getUTCDate(),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function daysInMonth(year: number, month: number): number {
|
|
179
|
+
return new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function parseLocalDate(value: string): LocalDate | undefined {
|
|
183
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
184
|
+
if (!match) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const year = Number(match[1]);
|
|
189
|
+
const month = Number(match[2]);
|
|
190
|
+
const day = Number(match[3]);
|
|
191
|
+
if (
|
|
192
|
+
!Number.isInteger(year) ||
|
|
193
|
+
!Number.isInteger(month) ||
|
|
194
|
+
!Number.isInteger(day) ||
|
|
195
|
+
month < 1 ||
|
|
196
|
+
month > 12 ||
|
|
197
|
+
day < 1 ||
|
|
198
|
+
day > daysInMonth(year, month)
|
|
199
|
+
) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return { year, month, day };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function formatLocalDate(date: LocalDate): string {
|
|
207
|
+
return [
|
|
208
|
+
String(date.year).padStart(4, "0"),
|
|
209
|
+
String(date.month).padStart(2, "0"),
|
|
210
|
+
String(date.day).padStart(2, "0"),
|
|
211
|
+
].join("-");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function getLocalDate(timestampMs: number, timezone: string): LocalDate {
|
|
215
|
+
const parts = getZonedDateTimeParts(timestampMs, timezone);
|
|
216
|
+
return { year: parts.year, month: parts.month, day: parts.day };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function normalizeWeekdays(values: number[] | undefined): number[] {
|
|
220
|
+
return [
|
|
221
|
+
...new Set((values ?? []).filter((value) => value >= 0 && value <= 6)),
|
|
222
|
+
].sort((a, b) => a - b);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function buildCandidate(args: {
|
|
226
|
+
date: LocalDate;
|
|
227
|
+
recurrence: ScheduledTaskRecurrence;
|
|
228
|
+
timezone: string;
|
|
229
|
+
}): number {
|
|
230
|
+
return localDateTimeToTimestampMs({
|
|
231
|
+
date: args.date,
|
|
232
|
+
time: args.recurrence.time,
|
|
233
|
+
timezone: args.timezone,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function getDailyNextRunAtMs(args: {
|
|
238
|
+
afterMs: number;
|
|
239
|
+
recurrence: ScheduledTaskRecurrence;
|
|
240
|
+
scheduledForMs: number;
|
|
241
|
+
timezone: string;
|
|
242
|
+
}): number | undefined {
|
|
243
|
+
const start = parseLocalDate(args.recurrence.startDate);
|
|
244
|
+
if (!start) {
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
let candidateDate = addDays(
|
|
249
|
+
getLocalDate(args.scheduledForMs, args.timezone),
|
|
250
|
+
args.recurrence.interval,
|
|
251
|
+
);
|
|
252
|
+
if (compareDate(candidateDate, start) < 0) {
|
|
253
|
+
candidateDate = start;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
let candidate = buildCandidate({
|
|
257
|
+
date: candidateDate,
|
|
258
|
+
recurrence: args.recurrence,
|
|
259
|
+
timezone: args.timezone,
|
|
260
|
+
});
|
|
261
|
+
while (candidate <= args.afterMs) {
|
|
262
|
+
candidateDate = addDays(candidateDate, args.recurrence.interval);
|
|
263
|
+
candidate = buildCandidate({
|
|
264
|
+
date: candidateDate,
|
|
265
|
+
recurrence: args.recurrence,
|
|
266
|
+
timezone: args.timezone,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
return candidate;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function getWeeklyNextRunAtMs(args: {
|
|
273
|
+
afterMs: number;
|
|
274
|
+
recurrence: ScheduledTaskRecurrence;
|
|
275
|
+
scheduledForMs: number;
|
|
276
|
+
timezone: string;
|
|
277
|
+
}): number | undefined {
|
|
278
|
+
const start = parseLocalDate(args.recurrence.startDate);
|
|
279
|
+
if (!start) {
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const weekdays = normalizeWeekdays(args.recurrence.weekdays);
|
|
284
|
+
if (weekdays.length === 0) {
|
|
285
|
+
return undefined;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
let candidateDate = addDays(
|
|
289
|
+
getLocalDate(args.scheduledForMs, args.timezone),
|
|
290
|
+
1,
|
|
291
|
+
);
|
|
292
|
+
for (let attempts = 0; attempts < 3660; attempts += 1) {
|
|
293
|
+
const weeksSinceStart = Math.floor(
|
|
294
|
+
(Date.UTC(
|
|
295
|
+
candidateDate.year,
|
|
296
|
+
candidateDate.month - 1,
|
|
297
|
+
candidateDate.day,
|
|
298
|
+
) -
|
|
299
|
+
Date.UTC(start.year, start.month - 1, start.day)) /
|
|
300
|
+
(7 * 24 * 60 * 60 * 1000),
|
|
301
|
+
);
|
|
302
|
+
const isInCycle =
|
|
303
|
+
weeksSinceStart >= 0 && weeksSinceStart % args.recurrence.interval === 0;
|
|
304
|
+
if (isInCycle && weekdays.includes(getLocalDateWeekday(candidateDate))) {
|
|
305
|
+
const candidate = buildCandidate({
|
|
306
|
+
date: candidateDate,
|
|
307
|
+
recurrence: args.recurrence,
|
|
308
|
+
timezone: args.timezone,
|
|
309
|
+
});
|
|
310
|
+
if (candidate > args.afterMs) {
|
|
311
|
+
return candidate;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
candidateDate = addDays(candidateDate, 1);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function getMonthlyNextRunAtMs(args: {
|
|
321
|
+
afterMs: number;
|
|
322
|
+
recurrence: ScheduledTaskRecurrence;
|
|
323
|
+
scheduledForMs: number;
|
|
324
|
+
timezone: string;
|
|
325
|
+
}): number | undefined {
|
|
326
|
+
const start = parseLocalDate(args.recurrence.startDate);
|
|
327
|
+
const dayOfMonth = args.recurrence.dayOfMonth;
|
|
328
|
+
if (!start || !dayOfMonth) {
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const scheduledDate = getLocalDate(args.scheduledForMs, args.timezone);
|
|
333
|
+
let monthIndex = scheduledDate.year * 12 + scheduledDate.month - 1;
|
|
334
|
+
const startMonthIndex = start.year * 12 + start.month - 1;
|
|
335
|
+
|
|
336
|
+
for (let attempts = 0; attempts < 1200; attempts += 1) {
|
|
337
|
+
monthIndex += args.recurrence.interval;
|
|
338
|
+
if (monthIndex < startMonthIndex) {
|
|
339
|
+
monthIndex = startMonthIndex;
|
|
340
|
+
}
|
|
341
|
+
const year = Math.floor(monthIndex / 12);
|
|
342
|
+
const month = (monthIndex % 12) + 1;
|
|
343
|
+
if (dayOfMonth > daysInMonth(year, month)) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
const candidate = buildCandidate({
|
|
347
|
+
date: { year, month, day: dayOfMonth },
|
|
348
|
+
recurrence: args.recurrence,
|
|
349
|
+
timezone: args.timezone,
|
|
350
|
+
});
|
|
351
|
+
if (candidate > args.afterMs) {
|
|
352
|
+
return candidate;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return undefined;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function getYearlyNextRunAtMs(args: {
|
|
360
|
+
afterMs: number;
|
|
361
|
+
recurrence: ScheduledTaskRecurrence;
|
|
362
|
+
scheduledForMs: number;
|
|
363
|
+
timezone: string;
|
|
364
|
+
}): number | undefined {
|
|
365
|
+
const start = parseLocalDate(args.recurrence.startDate);
|
|
366
|
+
const month = args.recurrence.month;
|
|
367
|
+
const dayOfMonth = args.recurrence.dayOfMonth;
|
|
368
|
+
if (!start || !month || !dayOfMonth) {
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
const scheduledDate = getLocalDate(args.scheduledForMs, args.timezone);
|
|
373
|
+
let year = scheduledDate.year;
|
|
374
|
+
|
|
375
|
+
for (let attempts = 0; attempts < 100; attempts += 1) {
|
|
376
|
+
year += args.recurrence.interval;
|
|
377
|
+
if (year < start.year) {
|
|
378
|
+
year = start.year;
|
|
379
|
+
}
|
|
380
|
+
if (dayOfMonth > daysInMonth(year, month)) {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const candidate = buildCandidate({
|
|
384
|
+
date: { year, month, day: dayOfMonth },
|
|
385
|
+
recurrence: args.recurrence,
|
|
386
|
+
timezone: args.timezone,
|
|
387
|
+
});
|
|
388
|
+
if (candidate > args.afterMs) {
|
|
389
|
+
return candidate;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Build a calendar recurrence anchored to an exact first run timestamp. */
|
|
397
|
+
export function buildCalendarRecurrence(args: {
|
|
398
|
+
frequency: ScheduledCalendarFrequency;
|
|
399
|
+
interval?: number;
|
|
400
|
+
nextRunAtMs: number;
|
|
401
|
+
timezone: string;
|
|
402
|
+
weekdays?: number[];
|
|
403
|
+
}): ScheduledTaskRecurrence {
|
|
404
|
+
const interval = args.interval && args.interval > 0 ? args.interval : 1;
|
|
405
|
+
const parts = getZonedDateTimeParts(args.nextRunAtMs, args.timezone);
|
|
406
|
+
const time = { hour: parts.hour, minute: parts.minute };
|
|
407
|
+
const startDate = formatLocalDate(parts);
|
|
408
|
+
|
|
409
|
+
if (args.frequency === "weekly") {
|
|
410
|
+
const weekdays = normalizeWeekdays(args.weekdays);
|
|
411
|
+
return {
|
|
412
|
+
frequency: args.frequency,
|
|
413
|
+
interval,
|
|
414
|
+
startDate,
|
|
415
|
+
time,
|
|
416
|
+
weekdays: weekdays.length > 0 ? weekdays : [parts.weekday],
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (args.frequency === "monthly") {
|
|
421
|
+
return {
|
|
422
|
+
dayOfMonth: parts.day,
|
|
423
|
+
frequency: args.frequency,
|
|
424
|
+
interval,
|
|
425
|
+
startDate,
|
|
426
|
+
time,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (args.frequency === "yearly") {
|
|
431
|
+
return {
|
|
432
|
+
dayOfMonth: parts.day,
|
|
433
|
+
frequency: args.frequency,
|
|
434
|
+
interval,
|
|
435
|
+
month: parts.month,
|
|
436
|
+
startDate,
|
|
437
|
+
time,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
return {
|
|
442
|
+
frequency: args.frequency,
|
|
443
|
+
interval,
|
|
444
|
+
startDate,
|
|
445
|
+
time,
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/** Return the next fire time after a completed run, when the task recurs. */
|
|
450
|
+
export function getNextRunAtMs(
|
|
451
|
+
task: ScheduledTask,
|
|
452
|
+
scheduledForMs: number,
|
|
453
|
+
afterMs: number = scheduledForMs,
|
|
454
|
+
): number | undefined {
|
|
455
|
+
if (task.schedule.kind !== "recurring") {
|
|
456
|
+
return undefined;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const recurrence = task.schedule.recurrence;
|
|
460
|
+
if (
|
|
461
|
+
!recurrence ||
|
|
462
|
+
!Number.isFinite(recurrence.interval) ||
|
|
463
|
+
recurrence.interval <= 0
|
|
464
|
+
) {
|
|
465
|
+
return undefined;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
if (recurrence.frequency === "daily") {
|
|
469
|
+
return getDailyNextRunAtMs({
|
|
470
|
+
recurrence,
|
|
471
|
+
timezone: task.schedule.timezone,
|
|
472
|
+
scheduledForMs,
|
|
473
|
+
afterMs,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (recurrence.frequency === "weekly") {
|
|
478
|
+
return getWeeklyNextRunAtMs({
|
|
479
|
+
recurrence,
|
|
480
|
+
timezone: task.schedule.timezone,
|
|
481
|
+
scheduledForMs,
|
|
482
|
+
afterMs,
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (recurrence.frequency === "monthly") {
|
|
487
|
+
return getMonthlyNextRunAtMs({
|
|
488
|
+
recurrence,
|
|
489
|
+
timezone: task.schedule.timezone,
|
|
490
|
+
scheduledForMs,
|
|
491
|
+
afterMs,
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return getYearlyNextRunAtMs({
|
|
496
|
+
recurrence,
|
|
497
|
+
timezone: task.schedule.timezone,
|
|
498
|
+
scheduledForMs,
|
|
499
|
+
afterMs,
|
|
500
|
+
});
|
|
501
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export { createSchedulerPlugin, schedulerPlugin } from "./plugin";
|
|
2
|
+
export { buildScheduledTaskRunPrompt } from "./prompt";
|
|
3
|
+
export {
|
|
4
|
+
createSlackScheduleCreateTaskTool,
|
|
5
|
+
createSlackScheduleDeleteTaskTool,
|
|
6
|
+
createSlackScheduleListTasksTool,
|
|
7
|
+
createSlackScheduleRunTaskNowTool,
|
|
8
|
+
createSlackScheduleUpdateTaskTool,
|
|
9
|
+
type SchedulerToolContext,
|
|
10
|
+
} from "./schedule-tools";
|
|
11
|
+
export { createSchedulerStore } from "./store";
|
|
12
|
+
export type {
|
|
13
|
+
ScheduledCalendarFrequency,
|
|
14
|
+
ScheduledLocalTime,
|
|
15
|
+
ScheduledRun,
|
|
16
|
+
ScheduledRunStatus,
|
|
17
|
+
ScheduledTask,
|
|
18
|
+
ScheduledTaskConversationAccess,
|
|
19
|
+
ScheduledTaskCredentialSubject,
|
|
20
|
+
ScheduledTaskDestination,
|
|
21
|
+
ScheduledTaskExecutionActor,
|
|
22
|
+
ScheduledTaskPrincipal,
|
|
23
|
+
ScheduledTaskRecurrence,
|
|
24
|
+
ScheduledTaskSchedule,
|
|
25
|
+
ScheduledTaskSpec,
|
|
26
|
+
ScheduledTaskStatus,
|
|
27
|
+
} from "./types";
|