skedyul 1.2.43 → 1.2.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/workflows.d.ts +1 -0
- package/dist/cli/index.js +3682 -9076
- package/dist/cli/utils/auth.d.ts +4 -1
- package/dist/cli/utils/auth.js +32 -8
- package/dist/cli/utils/config.d.ts +23 -0
- package/dist/cli/utils/env-sync.d.ts +46 -0
- package/dist/cli/utils/mcp-http-client.d.ts +74 -0
- package/dist/cli/utils/migration-approval.d.ts +39 -0
- package/dist/cli/utils/mock-context.d.ts +19 -9
- package/dist/cli/utils/sse.d.ts +33 -0
- package/dist/cli/utils.d.ts +5 -1
- package/dist/compiler/types.d.ts +11 -9
- package/dist/config/schema-loader.d.ts +15 -2
- package/dist/config/types/model.d.ts +2 -0
- package/dist/config/types/page.d.ts +9 -0
- package/dist/context/index.d.ts +2 -2
- package/dist/context/resolver.d.ts +29 -28
- package/dist/context/types.d.ts +195 -37
- package/dist/core/client.d.ts +189 -233
- package/dist/dedicated/server.js +264 -166
- package/dist/esm/index.mjs +1161 -7674
- package/dist/index.d.ts +11 -6
- package/dist/index.js +1206 -7672
- package/dist/scheduling/calculateWaitTime.d.ts +16 -0
- package/dist/scheduling/index.d.ts +11 -0
- package/dist/scheduling/index.js +334 -0
- package/dist/scheduling/index.mjs +305 -0
- package/dist/scheduling/isTimeInWindow.d.ts +15 -0
- package/dist/scheduling/types-workflow.d.ts +54 -0
- package/dist/scheduling/types.d.ts +166 -0
- package/dist/schemas/agent-schema-v3.d.ts +406 -60
- package/dist/schemas/agent-schema-v3.js +248 -75
- package/dist/schemas/agent-schema-v3.mjs +234 -73
- package/dist/schemas/agent-schema.js +3 -7295
- package/dist/schemas/agent-schema.mjs +3 -7323
- package/dist/schemas/crm-schema.d.ts +53 -19
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas.d.ts +128 -40
- package/dist/server/route-handlers/handlers.d.ts +7 -0
- package/dist/server/utils/env.d.ts +9 -0
- package/dist/server/utils/index.d.ts +1 -0
- package/dist/server/utils/mcp-response.d.ts +11 -0
- package/dist/server.js +264 -166
- package/dist/serverless/server.mjs +264 -166
- package/dist/skills/index.d.ts +1 -1
- package/dist/skills/types.d.ts +34 -23
- package/dist/skills/types.js +8 -17
- package/dist/skills/types.mjs +7 -16
- package/dist/types/index.d.ts +3 -3
- package/dist/types/server.d.ts +1 -0
- package/dist/types/tool-context.d.ts +31 -4
- package/dist/types/tool-response.d.ts +2 -0
- package/dist/types/tool.d.ts +35 -1
- package/package.json +8 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate Wait Time
|
|
3
|
+
*
|
|
4
|
+
* Calculates when to schedule a message or wait step based on relative/absolute time
|
|
5
|
+
* and optional time window constraints.
|
|
6
|
+
*
|
|
7
|
+
* This is the source of truth - skedyul-core re-exports for backward compatibility.
|
|
8
|
+
*/
|
|
9
|
+
import type { WaitInputType, CalculateWaitTimeResult } from './types-workflow';
|
|
10
|
+
/**
|
|
11
|
+
* Calculate the wait time for a wait step
|
|
12
|
+
* @param step The input parameters for the wait step
|
|
13
|
+
* @param now The current date/time
|
|
14
|
+
* @returns The time to wait in milliseconds and the scheduled date
|
|
15
|
+
*/
|
|
16
|
+
export declare function calculateWaitTime(step: WaitInputType, now: Date): CalculateWaitTimeResult;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduling Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides scheduling utilities that are safe to use in Temporal workflows.
|
|
5
|
+
* It intentionally avoids importing zod to prevent bundler issues.
|
|
6
|
+
*
|
|
7
|
+
* For zod schemas, import from './types' directly (not workflow-safe).
|
|
8
|
+
*/
|
|
9
|
+
export type { TimeStamp, DayOfWeek, TimeWindowSlot, WaitUnit, WaitInputRelative, WaitInputAbsolute, WaitInputType, CalculateWaitTimeResult, TimeWindowPolicy, } from './types-workflow';
|
|
10
|
+
export { calculateWaitTime } from './calculateWaitTime';
|
|
11
|
+
export { isTimeInWindowSlot, isTimeInPolicy } from './isTimeInWindow';
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/scheduling/index.ts
|
|
21
|
+
var scheduling_exports = {};
|
|
22
|
+
__export(scheduling_exports, {
|
|
23
|
+
calculateWaitTime: () => calculateWaitTime,
|
|
24
|
+
isTimeInPolicy: () => isTimeInPolicy,
|
|
25
|
+
isTimeInWindowSlot: () => isTimeInWindowSlot2
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(scheduling_exports);
|
|
28
|
+
|
|
29
|
+
// src/scheduling/calculateWaitTime.ts
|
|
30
|
+
var dayNameToNumber = {
|
|
31
|
+
sunday: 0,
|
|
32
|
+
monday: 1,
|
|
33
|
+
tuesday: 2,
|
|
34
|
+
wednesday: 3,
|
|
35
|
+
thursday: 4,
|
|
36
|
+
friday: 5,
|
|
37
|
+
saturday: 6
|
|
38
|
+
};
|
|
39
|
+
function normalizeTimeToMinutes(timeStamp) {
|
|
40
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
41
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
42
|
+
}
|
|
43
|
+
if (typeof timeStamp === "number") {
|
|
44
|
+
return timeStamp * 60;
|
|
45
|
+
}
|
|
46
|
+
const minute = timeStamp.minute ?? 0;
|
|
47
|
+
const second = timeStamp.second ?? 0;
|
|
48
|
+
return timeStamp.hour * 60 + minute + Math.floor(second / 60);
|
|
49
|
+
}
|
|
50
|
+
function getHourFromTimeStamp(timeStamp) {
|
|
51
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
52
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
53
|
+
}
|
|
54
|
+
if (typeof timeStamp === "number") {
|
|
55
|
+
return timeStamp;
|
|
56
|
+
}
|
|
57
|
+
return timeStamp.hour;
|
|
58
|
+
}
|
|
59
|
+
function getMinuteFromTimeStamp(timeStamp) {
|
|
60
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
61
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
62
|
+
}
|
|
63
|
+
if (typeof timeStamp === "number") {
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
return timeStamp.minute ?? 0;
|
|
67
|
+
}
|
|
68
|
+
function getTimezoneInfo(date, timezone) {
|
|
69
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
70
|
+
timeZone: timezone,
|
|
71
|
+
year: "numeric",
|
|
72
|
+
month: "2-digit",
|
|
73
|
+
day: "2-digit",
|
|
74
|
+
hour: "2-digit",
|
|
75
|
+
minute: "2-digit",
|
|
76
|
+
second: "2-digit",
|
|
77
|
+
hour12: false
|
|
78
|
+
});
|
|
79
|
+
const parts = formatter.formatToParts(date);
|
|
80
|
+
const partsObj = parts.reduce(
|
|
81
|
+
(acc, part) => {
|
|
82
|
+
acc[part.type] = part.value;
|
|
83
|
+
return acc;
|
|
84
|
+
},
|
|
85
|
+
{}
|
|
86
|
+
);
|
|
87
|
+
return {
|
|
88
|
+
day: new Date(
|
|
89
|
+
parseInt(partsObj.year ?? "0"),
|
|
90
|
+
parseInt(partsObj.month ?? "1") - 1,
|
|
91
|
+
parseInt(partsObj.day ?? "1")
|
|
92
|
+
).getDay(),
|
|
93
|
+
hour: parseInt(partsObj.hour ?? "0"),
|
|
94
|
+
minute: parseInt(partsObj.minute ?? "0"),
|
|
95
|
+
totalMinutes: parseInt(partsObj.hour ?? "0") * 60 + parseInt(partsObj.minute ?? "0")
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function isTimeInWindowSlot(date, window) {
|
|
99
|
+
if (!window || window.startTime === void 0 || window.endTime === void 0) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
const {
|
|
103
|
+
days: daysOfWeek,
|
|
104
|
+
startTime: windowStartTime,
|
|
105
|
+
endTime: windowEndTime,
|
|
106
|
+
timezone
|
|
107
|
+
} = window;
|
|
108
|
+
const tz = timezone ?? "UTC";
|
|
109
|
+
const windowStartMinutes = normalizeTimeToMinutes(windowStartTime);
|
|
110
|
+
const windowEndMinutes = normalizeTimeToMinutes(windowEndTime);
|
|
111
|
+
const allowedDays = daysOfWeek.map((day) => {
|
|
112
|
+
return dayNameToNumber[day.toLowerCase()] ?? parseInt(day);
|
|
113
|
+
}).filter((day) => !isNaN(day) && day >= 0 && day <= 6);
|
|
114
|
+
const tzInfo = getTimezoneInfo(date, tz);
|
|
115
|
+
return allowedDays.includes(tzInfo.day) && tzInfo.totalMinutes >= windowStartMinutes && tzInfo.totalMinutes < windowEndMinutes;
|
|
116
|
+
}
|
|
117
|
+
function calculateWaitTime(step, now) {
|
|
118
|
+
const nowTime = now.getTime();
|
|
119
|
+
switch (step.mode) {
|
|
120
|
+
case "absolute": {
|
|
121
|
+
const scheduleAtTime = typeof step.scheduleAt === "string" ? new Date(step.scheduleAt).getTime() : step.scheduleAt;
|
|
122
|
+
return {
|
|
123
|
+
waitTime: Math.max(0, scheduleAtTime - nowTime),
|
|
124
|
+
scheduledAt: new Date(scheduleAtTime)
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
case "relative": {
|
|
128
|
+
if (!step.amount && (!step.windows || step.windows.length === 0)) {
|
|
129
|
+
return {
|
|
130
|
+
waitTime: 0,
|
|
131
|
+
scheduledAt: now
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
let relativeDelay = 0;
|
|
135
|
+
if (step.amount && step.unit) {
|
|
136
|
+
switch (step.unit) {
|
|
137
|
+
case "seconds":
|
|
138
|
+
case "second":
|
|
139
|
+
relativeDelay = step.amount * 1e3;
|
|
140
|
+
break;
|
|
141
|
+
case "minutes":
|
|
142
|
+
case "minute":
|
|
143
|
+
relativeDelay = step.amount * 60 * 1e3;
|
|
144
|
+
break;
|
|
145
|
+
case "hours":
|
|
146
|
+
case "hour":
|
|
147
|
+
relativeDelay = step.amount * 60 * 60 * 1e3;
|
|
148
|
+
break;
|
|
149
|
+
case "days":
|
|
150
|
+
case "day":
|
|
151
|
+
relativeDelay = step.amount * 24 * 60 * 60 * 1e3;
|
|
152
|
+
break;
|
|
153
|
+
case "weeks":
|
|
154
|
+
case "week":
|
|
155
|
+
relativeDelay = step.amount * 7 * 24 * 60 * 60 * 1e3;
|
|
156
|
+
break;
|
|
157
|
+
case "months":
|
|
158
|
+
case "month": {
|
|
159
|
+
relativeDelay = step.amount * 30 * 24 * 60 * 60 * 1e3;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case "years":
|
|
163
|
+
case "year": {
|
|
164
|
+
relativeDelay = step.amount * 365 * 24 * 60 * 60 * 1e3;
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (!step.windows || step.windows.length === 0) {
|
|
170
|
+
return {
|
|
171
|
+
waitTime: relativeDelay,
|
|
172
|
+
scheduledAt: new Date(nowTime + relativeDelay)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
const targetDate = new Date(nowTime + relativeDelay);
|
|
176
|
+
for (const window of step.windows) {
|
|
177
|
+
if (isTimeInWindowSlot(targetDate, window)) {
|
|
178
|
+
return {
|
|
179
|
+
waitTime: relativeDelay,
|
|
180
|
+
scheduledAt: new Date(nowTime + relativeDelay)
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
let earliestScheduledTime = null;
|
|
185
|
+
let earliestWaitTime = Infinity;
|
|
186
|
+
for (const window of step.windows) {
|
|
187
|
+
if (!window || window.startTime === void 0 || window.endTime === void 0) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const { days: daysOfWeek, startTime: windowStartTime, timezone } = window;
|
|
191
|
+
const tz = timezone ?? "UTC";
|
|
192
|
+
const windowStartMinutes = normalizeTimeToMinutes(windowStartTime);
|
|
193
|
+
const windowStartHour = getHourFromTimeStamp(windowStartTime);
|
|
194
|
+
const windowStartMinute = getMinuteFromTimeStamp(windowStartTime);
|
|
195
|
+
const allowedDays = daysOfWeek.map((day) => {
|
|
196
|
+
return dayNameToNumber[day.toLowerCase()] ?? parseInt(day);
|
|
197
|
+
}).filter((day) => !isNaN(day) && day >= 0 && day <= 6);
|
|
198
|
+
const targetTzInfo = getTimezoneInfo(targetDate, tz);
|
|
199
|
+
const currentDay = targetTzInfo.day;
|
|
200
|
+
const currentHour = targetTzInfo.hour;
|
|
201
|
+
const currentMinute = targetTzInfo.minute;
|
|
202
|
+
const currentTotalMinutes = targetTzInfo.totalMinutes;
|
|
203
|
+
let windowWaitTime;
|
|
204
|
+
let windowScheduledTime;
|
|
205
|
+
if (allowedDays.includes(currentDay) && currentTotalMinutes < windowStartMinutes) {
|
|
206
|
+
const minutesUntilWindow = windowStartMinutes - currentTotalMinutes;
|
|
207
|
+
windowWaitTime = minutesUntilWindow * 60 * 1e3;
|
|
208
|
+
windowScheduledTime = new Date(targetDate.getTime() + windowWaitTime);
|
|
209
|
+
} else {
|
|
210
|
+
let daysToAdd = 7;
|
|
211
|
+
for (let i = 1; i <= 7; i++) {
|
|
212
|
+
const nextDay = (currentDay + i) % 7;
|
|
213
|
+
if (allowedDays.includes(nextDay)) {
|
|
214
|
+
daysToAdd = i;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const millisecondsPerDay = 24 * 60 * 60 * 1e3;
|
|
219
|
+
const millisecondsPerHour = 60 * 60 * 1e3;
|
|
220
|
+
const millisecondsPerMinute = 60 * 1e3;
|
|
221
|
+
const daysMs = daysToAdd * millisecondsPerDay;
|
|
222
|
+
const hoursAdjustment = (windowStartHour - currentHour) * millisecondsPerHour;
|
|
223
|
+
const minutesAdjustment = (windowStartMinute - currentMinute) * millisecondsPerMinute;
|
|
224
|
+
windowWaitTime = daysMs + hoursAdjustment + minutesAdjustment;
|
|
225
|
+
windowScheduledTime = new Date(targetDate.getTime() + windowWaitTime);
|
|
226
|
+
}
|
|
227
|
+
if (windowWaitTime < earliestWaitTime) {
|
|
228
|
+
earliestWaitTime = windowWaitTime;
|
|
229
|
+
earliestScheduledTime = windowScheduledTime;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (earliestScheduledTime) {
|
|
233
|
+
return {
|
|
234
|
+
waitTime: relativeDelay + earliestWaitTime,
|
|
235
|
+
scheduledAt: earliestScheduledTime
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
throw new Error("No valid time windows found for scheduling");
|
|
239
|
+
}
|
|
240
|
+
default:
|
|
241
|
+
throw new Error(`Unsupported wait mode: ${step.mode}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/scheduling/isTimeInWindow.ts
|
|
246
|
+
var dayNameToNumber2 = {
|
|
247
|
+
sunday: 0,
|
|
248
|
+
monday: 1,
|
|
249
|
+
tuesday: 2,
|
|
250
|
+
wednesday: 3,
|
|
251
|
+
thursday: 4,
|
|
252
|
+
friday: 5,
|
|
253
|
+
saturday: 6
|
|
254
|
+
};
|
|
255
|
+
function normalizeTimeToMinutes2(timeStamp) {
|
|
256
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
257
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
258
|
+
}
|
|
259
|
+
if (typeof timeStamp === "number") {
|
|
260
|
+
return timeStamp * 60;
|
|
261
|
+
}
|
|
262
|
+
const minute = timeStamp.minute ?? 0;
|
|
263
|
+
const second = timeStamp.second ?? 0;
|
|
264
|
+
return timeStamp.hour * 60 + minute + Math.floor(second / 60);
|
|
265
|
+
}
|
|
266
|
+
function getTimezoneInfo2(date, timezone) {
|
|
267
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
268
|
+
timeZone: timezone,
|
|
269
|
+
year: "numeric",
|
|
270
|
+
month: "2-digit",
|
|
271
|
+
day: "2-digit",
|
|
272
|
+
hour: "2-digit",
|
|
273
|
+
minute: "2-digit",
|
|
274
|
+
second: "2-digit",
|
|
275
|
+
hour12: false
|
|
276
|
+
});
|
|
277
|
+
const parts = formatter.formatToParts(date);
|
|
278
|
+
const partsObj = parts.reduce(
|
|
279
|
+
(acc, part) => {
|
|
280
|
+
acc[part.type] = part.value;
|
|
281
|
+
return acc;
|
|
282
|
+
},
|
|
283
|
+
{}
|
|
284
|
+
);
|
|
285
|
+
return {
|
|
286
|
+
day: new Date(
|
|
287
|
+
parseInt(partsObj.year ?? "0"),
|
|
288
|
+
parseInt(partsObj.month ?? "1") - 1,
|
|
289
|
+
parseInt(partsObj.day ?? "1")
|
|
290
|
+
).getDay(),
|
|
291
|
+
hour: parseInt(partsObj.hour ?? "0"),
|
|
292
|
+
minute: parseInt(partsObj.minute ?? "0"),
|
|
293
|
+
totalMinutes: parseInt(partsObj.hour ?? "0") * 60 + parseInt(partsObj.minute ?? "0")
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function isTimeInWindowSlot2(date, slot, timezone) {
|
|
297
|
+
if (!slot || slot.startTime === void 0 || slot.endTime === void 0) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const {
|
|
301
|
+
days: daysOfWeek,
|
|
302
|
+
startTime: windowStartTime,
|
|
303
|
+
endTime: windowEndTime
|
|
304
|
+
} = slot;
|
|
305
|
+
const tz = timezone ?? slot.timezone ?? "UTC";
|
|
306
|
+
const windowStartMinutes = normalizeTimeToMinutes2(windowStartTime);
|
|
307
|
+
const windowEndMinutes = normalizeTimeToMinutes2(windowEndTime);
|
|
308
|
+
const allowedDays = daysOfWeek.map((day) => {
|
|
309
|
+
return dayNameToNumber2[day.toLowerCase()] ?? parseInt(day);
|
|
310
|
+
}).filter((day) => !isNaN(day) && day >= 0 && day <= 6);
|
|
311
|
+
const tzInfo = getTimezoneInfo2(date, tz);
|
|
312
|
+
return allowedDays.includes(tzInfo.day) && tzInfo.totalMinutes >= windowStartMinutes && tzInfo.totalMinutes < windowEndMinutes;
|
|
313
|
+
}
|
|
314
|
+
function isTimeInPolicy(date, policy) {
|
|
315
|
+
if (!policy || !policy.windows || policy.windows.length === 0) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
for (const slot of policy.windows) {
|
|
319
|
+
const slotWithTimezone = {
|
|
320
|
+
...slot,
|
|
321
|
+
timezone: slot.timezone ?? policy.timezone
|
|
322
|
+
};
|
|
323
|
+
if (isTimeInWindowSlot2(date, slotWithTimezone, policy.timezone)) {
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
330
|
+
0 && (module.exports = {
|
|
331
|
+
calculateWaitTime,
|
|
332
|
+
isTimeInPolicy,
|
|
333
|
+
isTimeInWindowSlot
|
|
334
|
+
});
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// src/scheduling/calculateWaitTime.ts
|
|
2
|
+
var dayNameToNumber = {
|
|
3
|
+
sunday: 0,
|
|
4
|
+
monday: 1,
|
|
5
|
+
tuesday: 2,
|
|
6
|
+
wednesday: 3,
|
|
7
|
+
thursday: 4,
|
|
8
|
+
friday: 5,
|
|
9
|
+
saturday: 6
|
|
10
|
+
};
|
|
11
|
+
function normalizeTimeToMinutes(timeStamp) {
|
|
12
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
13
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
14
|
+
}
|
|
15
|
+
if (typeof timeStamp === "number") {
|
|
16
|
+
return timeStamp * 60;
|
|
17
|
+
}
|
|
18
|
+
const minute = timeStamp.minute ?? 0;
|
|
19
|
+
const second = timeStamp.second ?? 0;
|
|
20
|
+
return timeStamp.hour * 60 + minute + Math.floor(second / 60);
|
|
21
|
+
}
|
|
22
|
+
function getHourFromTimeStamp(timeStamp) {
|
|
23
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
24
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
25
|
+
}
|
|
26
|
+
if (typeof timeStamp === "number") {
|
|
27
|
+
return timeStamp;
|
|
28
|
+
}
|
|
29
|
+
return timeStamp.hour;
|
|
30
|
+
}
|
|
31
|
+
function getMinuteFromTimeStamp(timeStamp) {
|
|
32
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
33
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
34
|
+
}
|
|
35
|
+
if (typeof timeStamp === "number") {
|
|
36
|
+
return 0;
|
|
37
|
+
}
|
|
38
|
+
return timeStamp.minute ?? 0;
|
|
39
|
+
}
|
|
40
|
+
function getTimezoneInfo(date, timezone) {
|
|
41
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
42
|
+
timeZone: timezone,
|
|
43
|
+
year: "numeric",
|
|
44
|
+
month: "2-digit",
|
|
45
|
+
day: "2-digit",
|
|
46
|
+
hour: "2-digit",
|
|
47
|
+
minute: "2-digit",
|
|
48
|
+
second: "2-digit",
|
|
49
|
+
hour12: false
|
|
50
|
+
});
|
|
51
|
+
const parts = formatter.formatToParts(date);
|
|
52
|
+
const partsObj = parts.reduce(
|
|
53
|
+
(acc, part) => {
|
|
54
|
+
acc[part.type] = part.value;
|
|
55
|
+
return acc;
|
|
56
|
+
},
|
|
57
|
+
{}
|
|
58
|
+
);
|
|
59
|
+
return {
|
|
60
|
+
day: new Date(
|
|
61
|
+
parseInt(partsObj.year ?? "0"),
|
|
62
|
+
parseInt(partsObj.month ?? "1") - 1,
|
|
63
|
+
parseInt(partsObj.day ?? "1")
|
|
64
|
+
).getDay(),
|
|
65
|
+
hour: parseInt(partsObj.hour ?? "0"),
|
|
66
|
+
minute: parseInt(partsObj.minute ?? "0"),
|
|
67
|
+
totalMinutes: parseInt(partsObj.hour ?? "0") * 60 + parseInt(partsObj.minute ?? "0")
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function isTimeInWindowSlot(date, window) {
|
|
71
|
+
if (!window || window.startTime === void 0 || window.endTime === void 0) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const {
|
|
75
|
+
days: daysOfWeek,
|
|
76
|
+
startTime: windowStartTime,
|
|
77
|
+
endTime: windowEndTime,
|
|
78
|
+
timezone
|
|
79
|
+
} = window;
|
|
80
|
+
const tz = timezone ?? "UTC";
|
|
81
|
+
const windowStartMinutes = normalizeTimeToMinutes(windowStartTime);
|
|
82
|
+
const windowEndMinutes = normalizeTimeToMinutes(windowEndTime);
|
|
83
|
+
const allowedDays = daysOfWeek.map((day) => {
|
|
84
|
+
return dayNameToNumber[day.toLowerCase()] ?? parseInt(day);
|
|
85
|
+
}).filter((day) => !isNaN(day) && day >= 0 && day <= 6);
|
|
86
|
+
const tzInfo = getTimezoneInfo(date, tz);
|
|
87
|
+
return allowedDays.includes(tzInfo.day) && tzInfo.totalMinutes >= windowStartMinutes && tzInfo.totalMinutes < windowEndMinutes;
|
|
88
|
+
}
|
|
89
|
+
function calculateWaitTime(step, now) {
|
|
90
|
+
const nowTime = now.getTime();
|
|
91
|
+
switch (step.mode) {
|
|
92
|
+
case "absolute": {
|
|
93
|
+
const scheduleAtTime = typeof step.scheduleAt === "string" ? new Date(step.scheduleAt).getTime() : step.scheduleAt;
|
|
94
|
+
return {
|
|
95
|
+
waitTime: Math.max(0, scheduleAtTime - nowTime),
|
|
96
|
+
scheduledAt: new Date(scheduleAtTime)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
case "relative": {
|
|
100
|
+
if (!step.amount && (!step.windows || step.windows.length === 0)) {
|
|
101
|
+
return {
|
|
102
|
+
waitTime: 0,
|
|
103
|
+
scheduledAt: now
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
let relativeDelay = 0;
|
|
107
|
+
if (step.amount && step.unit) {
|
|
108
|
+
switch (step.unit) {
|
|
109
|
+
case "seconds":
|
|
110
|
+
case "second":
|
|
111
|
+
relativeDelay = step.amount * 1e3;
|
|
112
|
+
break;
|
|
113
|
+
case "minutes":
|
|
114
|
+
case "minute":
|
|
115
|
+
relativeDelay = step.amount * 60 * 1e3;
|
|
116
|
+
break;
|
|
117
|
+
case "hours":
|
|
118
|
+
case "hour":
|
|
119
|
+
relativeDelay = step.amount * 60 * 60 * 1e3;
|
|
120
|
+
break;
|
|
121
|
+
case "days":
|
|
122
|
+
case "day":
|
|
123
|
+
relativeDelay = step.amount * 24 * 60 * 60 * 1e3;
|
|
124
|
+
break;
|
|
125
|
+
case "weeks":
|
|
126
|
+
case "week":
|
|
127
|
+
relativeDelay = step.amount * 7 * 24 * 60 * 60 * 1e3;
|
|
128
|
+
break;
|
|
129
|
+
case "months":
|
|
130
|
+
case "month": {
|
|
131
|
+
relativeDelay = step.amount * 30 * 24 * 60 * 60 * 1e3;
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case "years":
|
|
135
|
+
case "year": {
|
|
136
|
+
relativeDelay = step.amount * 365 * 24 * 60 * 60 * 1e3;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (!step.windows || step.windows.length === 0) {
|
|
142
|
+
return {
|
|
143
|
+
waitTime: relativeDelay,
|
|
144
|
+
scheduledAt: new Date(nowTime + relativeDelay)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const targetDate = new Date(nowTime + relativeDelay);
|
|
148
|
+
for (const window of step.windows) {
|
|
149
|
+
if (isTimeInWindowSlot(targetDate, window)) {
|
|
150
|
+
return {
|
|
151
|
+
waitTime: relativeDelay,
|
|
152
|
+
scheduledAt: new Date(nowTime + relativeDelay)
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
let earliestScheduledTime = null;
|
|
157
|
+
let earliestWaitTime = Infinity;
|
|
158
|
+
for (const window of step.windows) {
|
|
159
|
+
if (!window || window.startTime === void 0 || window.endTime === void 0) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const { days: daysOfWeek, startTime: windowStartTime, timezone } = window;
|
|
163
|
+
const tz = timezone ?? "UTC";
|
|
164
|
+
const windowStartMinutes = normalizeTimeToMinutes(windowStartTime);
|
|
165
|
+
const windowStartHour = getHourFromTimeStamp(windowStartTime);
|
|
166
|
+
const windowStartMinute = getMinuteFromTimeStamp(windowStartTime);
|
|
167
|
+
const allowedDays = daysOfWeek.map((day) => {
|
|
168
|
+
return dayNameToNumber[day.toLowerCase()] ?? parseInt(day);
|
|
169
|
+
}).filter((day) => !isNaN(day) && day >= 0 && day <= 6);
|
|
170
|
+
const targetTzInfo = getTimezoneInfo(targetDate, tz);
|
|
171
|
+
const currentDay = targetTzInfo.day;
|
|
172
|
+
const currentHour = targetTzInfo.hour;
|
|
173
|
+
const currentMinute = targetTzInfo.minute;
|
|
174
|
+
const currentTotalMinutes = targetTzInfo.totalMinutes;
|
|
175
|
+
let windowWaitTime;
|
|
176
|
+
let windowScheduledTime;
|
|
177
|
+
if (allowedDays.includes(currentDay) && currentTotalMinutes < windowStartMinutes) {
|
|
178
|
+
const minutesUntilWindow = windowStartMinutes - currentTotalMinutes;
|
|
179
|
+
windowWaitTime = minutesUntilWindow * 60 * 1e3;
|
|
180
|
+
windowScheduledTime = new Date(targetDate.getTime() + windowWaitTime);
|
|
181
|
+
} else {
|
|
182
|
+
let daysToAdd = 7;
|
|
183
|
+
for (let i = 1; i <= 7; i++) {
|
|
184
|
+
const nextDay = (currentDay + i) % 7;
|
|
185
|
+
if (allowedDays.includes(nextDay)) {
|
|
186
|
+
daysToAdd = i;
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const millisecondsPerDay = 24 * 60 * 60 * 1e3;
|
|
191
|
+
const millisecondsPerHour = 60 * 60 * 1e3;
|
|
192
|
+
const millisecondsPerMinute = 60 * 1e3;
|
|
193
|
+
const daysMs = daysToAdd * millisecondsPerDay;
|
|
194
|
+
const hoursAdjustment = (windowStartHour - currentHour) * millisecondsPerHour;
|
|
195
|
+
const minutesAdjustment = (windowStartMinute - currentMinute) * millisecondsPerMinute;
|
|
196
|
+
windowWaitTime = daysMs + hoursAdjustment + minutesAdjustment;
|
|
197
|
+
windowScheduledTime = new Date(targetDate.getTime() + windowWaitTime);
|
|
198
|
+
}
|
|
199
|
+
if (windowWaitTime < earliestWaitTime) {
|
|
200
|
+
earliestWaitTime = windowWaitTime;
|
|
201
|
+
earliestScheduledTime = windowScheduledTime;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (earliestScheduledTime) {
|
|
205
|
+
return {
|
|
206
|
+
waitTime: relativeDelay + earliestWaitTime,
|
|
207
|
+
scheduledAt: earliestScheduledTime
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
throw new Error("No valid time windows found for scheduling");
|
|
211
|
+
}
|
|
212
|
+
default:
|
|
213
|
+
throw new Error(`Unsupported wait mode: ${step.mode}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// src/scheduling/isTimeInWindow.ts
|
|
218
|
+
var dayNameToNumber2 = {
|
|
219
|
+
sunday: 0,
|
|
220
|
+
monday: 1,
|
|
221
|
+
tuesday: 2,
|
|
222
|
+
wednesday: 3,
|
|
223
|
+
thursday: 4,
|
|
224
|
+
friday: 5,
|
|
225
|
+
saturday: 6
|
|
226
|
+
};
|
|
227
|
+
function normalizeTimeToMinutes2(timeStamp) {
|
|
228
|
+
if (timeStamp === void 0 || timeStamp === null) {
|
|
229
|
+
throw new Error("timeStamp is required and cannot be undefined or null");
|
|
230
|
+
}
|
|
231
|
+
if (typeof timeStamp === "number") {
|
|
232
|
+
return timeStamp * 60;
|
|
233
|
+
}
|
|
234
|
+
const minute = timeStamp.minute ?? 0;
|
|
235
|
+
const second = timeStamp.second ?? 0;
|
|
236
|
+
return timeStamp.hour * 60 + minute + Math.floor(second / 60);
|
|
237
|
+
}
|
|
238
|
+
function getTimezoneInfo2(date, timezone) {
|
|
239
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
240
|
+
timeZone: timezone,
|
|
241
|
+
year: "numeric",
|
|
242
|
+
month: "2-digit",
|
|
243
|
+
day: "2-digit",
|
|
244
|
+
hour: "2-digit",
|
|
245
|
+
minute: "2-digit",
|
|
246
|
+
second: "2-digit",
|
|
247
|
+
hour12: false
|
|
248
|
+
});
|
|
249
|
+
const parts = formatter.formatToParts(date);
|
|
250
|
+
const partsObj = parts.reduce(
|
|
251
|
+
(acc, part) => {
|
|
252
|
+
acc[part.type] = part.value;
|
|
253
|
+
return acc;
|
|
254
|
+
},
|
|
255
|
+
{}
|
|
256
|
+
);
|
|
257
|
+
return {
|
|
258
|
+
day: new Date(
|
|
259
|
+
parseInt(partsObj.year ?? "0"),
|
|
260
|
+
parseInt(partsObj.month ?? "1") - 1,
|
|
261
|
+
parseInt(partsObj.day ?? "1")
|
|
262
|
+
).getDay(),
|
|
263
|
+
hour: parseInt(partsObj.hour ?? "0"),
|
|
264
|
+
minute: parseInt(partsObj.minute ?? "0"),
|
|
265
|
+
totalMinutes: parseInt(partsObj.hour ?? "0") * 60 + parseInt(partsObj.minute ?? "0")
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
function isTimeInWindowSlot2(date, slot, timezone) {
|
|
269
|
+
if (!slot || slot.startTime === void 0 || slot.endTime === void 0) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
const {
|
|
273
|
+
days: daysOfWeek,
|
|
274
|
+
startTime: windowStartTime,
|
|
275
|
+
endTime: windowEndTime
|
|
276
|
+
} = slot;
|
|
277
|
+
const tz = timezone ?? slot.timezone ?? "UTC";
|
|
278
|
+
const windowStartMinutes = normalizeTimeToMinutes2(windowStartTime);
|
|
279
|
+
const windowEndMinutes = normalizeTimeToMinutes2(windowEndTime);
|
|
280
|
+
const allowedDays = daysOfWeek.map((day) => {
|
|
281
|
+
return dayNameToNumber2[day.toLowerCase()] ?? parseInt(day);
|
|
282
|
+
}).filter((day) => !isNaN(day) && day >= 0 && day <= 6);
|
|
283
|
+
const tzInfo = getTimezoneInfo2(date, tz);
|
|
284
|
+
return allowedDays.includes(tzInfo.day) && tzInfo.totalMinutes >= windowStartMinutes && tzInfo.totalMinutes < windowEndMinutes;
|
|
285
|
+
}
|
|
286
|
+
function isTimeInPolicy(date, policy) {
|
|
287
|
+
if (!policy || !policy.windows || policy.windows.length === 0) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
for (const slot of policy.windows) {
|
|
291
|
+
const slotWithTimezone = {
|
|
292
|
+
...slot,
|
|
293
|
+
timezone: slot.timezone ?? policy.timezone
|
|
294
|
+
};
|
|
295
|
+
if (isTimeInWindowSlot2(date, slotWithTimezone, policy.timezone)) {
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
export {
|
|
302
|
+
calculateWaitTime,
|
|
303
|
+
isTimeInPolicy,
|
|
304
|
+
isTimeInWindowSlot2 as isTimeInWindowSlot
|
|
305
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time Window Detection
|
|
3
|
+
*
|
|
4
|
+
* Helper functions to check if a given time falls within a time window policy.
|
|
5
|
+
* Used for detecting the current time context (business hours, after hours, etc.)
|
|
6
|
+
*/
|
|
7
|
+
import type { TimeWindowSlot, TimeWindowPolicy } from './types-workflow';
|
|
8
|
+
/**
|
|
9
|
+
* Check if a date falls within a specific time window slot
|
|
10
|
+
*/
|
|
11
|
+
export declare function isTimeInWindowSlot(date: Date, slot: TimeWindowSlot, timezone?: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Check if a date falls within any slot of a time window policy
|
|
14
|
+
*/
|
|
15
|
+
export declare function isTimeInPolicy(date: Date, policy: TimeWindowPolicy): boolean;
|