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.
Files changed (54) hide show
  1. package/dist/cli/commands/workflows.d.ts +1 -0
  2. package/dist/cli/index.js +3682 -9076
  3. package/dist/cli/utils/auth.d.ts +4 -1
  4. package/dist/cli/utils/auth.js +32 -8
  5. package/dist/cli/utils/config.d.ts +23 -0
  6. package/dist/cli/utils/env-sync.d.ts +46 -0
  7. package/dist/cli/utils/mcp-http-client.d.ts +74 -0
  8. package/dist/cli/utils/migration-approval.d.ts +39 -0
  9. package/dist/cli/utils/mock-context.d.ts +19 -9
  10. package/dist/cli/utils/sse.d.ts +33 -0
  11. package/dist/cli/utils.d.ts +5 -1
  12. package/dist/compiler/types.d.ts +11 -9
  13. package/dist/config/schema-loader.d.ts +15 -2
  14. package/dist/config/types/model.d.ts +2 -0
  15. package/dist/config/types/page.d.ts +9 -0
  16. package/dist/context/index.d.ts +2 -2
  17. package/dist/context/resolver.d.ts +29 -28
  18. package/dist/context/types.d.ts +195 -37
  19. package/dist/core/client.d.ts +189 -233
  20. package/dist/dedicated/server.js +264 -166
  21. package/dist/esm/index.mjs +1161 -7674
  22. package/dist/index.d.ts +11 -6
  23. package/dist/index.js +1206 -7672
  24. package/dist/scheduling/calculateWaitTime.d.ts +16 -0
  25. package/dist/scheduling/index.d.ts +11 -0
  26. package/dist/scheduling/index.js +334 -0
  27. package/dist/scheduling/index.mjs +305 -0
  28. package/dist/scheduling/isTimeInWindow.d.ts +15 -0
  29. package/dist/scheduling/types-workflow.d.ts +54 -0
  30. package/dist/scheduling/types.d.ts +166 -0
  31. package/dist/schemas/agent-schema-v3.d.ts +406 -60
  32. package/dist/schemas/agent-schema-v3.js +248 -75
  33. package/dist/schemas/agent-schema-v3.mjs +234 -73
  34. package/dist/schemas/agent-schema.js +3 -7295
  35. package/dist/schemas/agent-schema.mjs +3 -7323
  36. package/dist/schemas/crm-schema.d.ts +53 -19
  37. package/dist/schemas/index.d.ts +1 -1
  38. package/dist/schemas.d.ts +128 -40
  39. package/dist/server/route-handlers/handlers.d.ts +7 -0
  40. package/dist/server/utils/env.d.ts +9 -0
  41. package/dist/server/utils/index.d.ts +1 -0
  42. package/dist/server/utils/mcp-response.d.ts +11 -0
  43. package/dist/server.js +264 -166
  44. package/dist/serverless/server.mjs +264 -166
  45. package/dist/skills/index.d.ts +1 -1
  46. package/dist/skills/types.d.ts +34 -23
  47. package/dist/skills/types.js +8 -17
  48. package/dist/skills/types.mjs +7 -16
  49. package/dist/types/index.d.ts +3 -3
  50. package/dist/types/server.d.ts +1 -0
  51. package/dist/types/tool-context.d.ts +31 -4
  52. package/dist/types/tool-response.d.ts +2 -0
  53. package/dist/types/tool.d.ts +35 -1
  54. 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;