ai-workflows 2.0.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -5
- package/.turbo/turbo-test.log +169 -0
- package/CHANGELOG.md +29 -0
- package/LICENSE +21 -0
- package/README.md +303 -184
- package/dist/barrier.d.ts +153 -0
- package/dist/barrier.d.ts.map +1 -0
- package/dist/barrier.js +339 -0
- package/dist/barrier.js.map +1 -0
- package/dist/cascade-context.d.ts +149 -0
- package/dist/cascade-context.d.ts.map +1 -0
- package/dist/cascade-context.js +324 -0
- package/dist/cascade-context.js.map +1 -0
- package/dist/cascade-executor.d.ts +196 -0
- package/dist/cascade-executor.d.ts.map +1 -0
- package/dist/cascade-executor.js +384 -0
- package/dist/cascade-executor.js.map +1 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +4 -1
- package/dist/context.js.map +1 -1
- package/dist/dependency-graph.d.ts +157 -0
- package/dist/dependency-graph.d.ts.map +1 -0
- package/dist/dependency-graph.js +382 -0
- package/dist/dependency-graph.js.map +1 -0
- package/dist/every.d.ts +31 -2
- package/dist/every.d.ts.map +1 -1
- package/dist/every.js +63 -32
- package/dist/every.js.map +1 -1
- package/dist/graph/index.d.ts +8 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +8 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/topological-sort.d.ts +121 -0
- package/dist/graph/topological-sort.d.ts.map +1 -0
- package/dist/graph/topological-sort.js +292 -0
- package/dist/graph/topological-sort.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/on.d.ts +35 -10
- package/dist/on.d.ts.map +1 -1
- package/dist/on.js +52 -18
- package/dist/on.js.map +1 -1
- package/dist/send.d.ts +0 -5
- package/dist/send.d.ts.map +1 -1
- package/dist/send.js +1 -14
- package/dist/send.js.map +1 -1
- package/dist/timer-registry.d.ts +52 -0
- package/dist/timer-registry.d.ts.map +1 -0
- package/dist/timer-registry.js +120 -0
- package/dist/timer-registry.js.map +1 -0
- package/dist/types.d.ts +171 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -1
- package/dist/types.js.map +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +22 -18
- package/dist/workflow.js.map +1 -1
- package/package.json +12 -16
- package/src/barrier.ts +466 -0
- package/src/cascade-context.ts +488 -0
- package/src/cascade-executor.ts +587 -0
- package/src/context.js +83 -0
- package/src/context.ts +12 -7
- package/src/dependency-graph.ts +518 -0
- package/src/every.js +267 -0
- package/src/every.ts +104 -35
- package/src/graph/index.ts +19 -0
- package/src/graph/topological-sort.ts +414 -0
- package/src/index.js +71 -0
- package/src/index.ts +78 -0
- package/src/on.js +79 -0
- package/src/on.ts +81 -25
- package/src/send.js +111 -0
- package/src/send.ts +1 -16
- package/src/timer-registry.ts +145 -0
- package/src/types.js +4 -0
- package/src/types.ts +218 -11
- package/src/workflow.js +455 -0
- package/src/workflow.ts +32 -23
- package/test/barrier-join.test.ts +434 -0
- package/test/barrier-unhandled-rejections.test.ts +359 -0
- package/test/cascade-context.test.ts +390 -0
- package/test/cascade-executor.test.ts +859 -0
- package/test/context.test.js +116 -0
- package/test/dependency-graph.test.ts +512 -0
- package/test/every.test.js +282 -0
- package/test/graph/topological-sort.test.ts +586 -0
- package/test/on.test.js +80 -0
- package/test/schedule-timer-cleanup.test.ts +344 -0
- package/test/send-race-conditions.test.ts +410 -0
- package/test/send.test.js +89 -0
- package/test/type-safety-every.test.ts +303 -0
- package/test/types-event-handler.test.ts +225 -0
- package/test/types-proxy-autocomplete.test.ts +345 -0
- package/test/workflow.test.js +224 -0
- package/vitest.config.js +7 -0
package/src/every.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schedule registration using natural language
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* every.hour($ => { ... })
|
|
6
|
+
* every.Thursday.at8am($ => { ... })
|
|
7
|
+
* every.weekday.at9am($ => { ... })
|
|
8
|
+
* every('hour during business hours', $ => { ... })
|
|
9
|
+
* every('first Monday of the month at 9am', $ => { ... })
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Registry of schedule handlers
|
|
13
|
+
*/
|
|
14
|
+
const scheduleRegistry = [];
|
|
15
|
+
/**
|
|
16
|
+
* Get all registered schedule handlers
|
|
17
|
+
*/
|
|
18
|
+
export function getScheduleHandlers() {
|
|
19
|
+
return [...scheduleRegistry];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Clear all registered schedule handlers
|
|
23
|
+
*/
|
|
24
|
+
export function clearScheduleHandlers() {
|
|
25
|
+
scheduleRegistry.length = 0;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Register a schedule handler directly
|
|
29
|
+
*/
|
|
30
|
+
export function registerScheduleHandler(interval, handler) {
|
|
31
|
+
scheduleRegistry.push({
|
|
32
|
+
interval,
|
|
33
|
+
handler,
|
|
34
|
+
source: handler.toString(),
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Well-known cron patterns for common schedules
|
|
39
|
+
*/
|
|
40
|
+
const KNOWN_PATTERNS = {
|
|
41
|
+
// Time units
|
|
42
|
+
'second': '* * * * * *',
|
|
43
|
+
'minute': '* * * * *',
|
|
44
|
+
'hour': '0 * * * *',
|
|
45
|
+
'day': '0 0 * * *',
|
|
46
|
+
'week': '0 0 * * 0',
|
|
47
|
+
'month': '0 0 1 * *',
|
|
48
|
+
'year': '0 0 1 1 *',
|
|
49
|
+
// Days of week
|
|
50
|
+
'Monday': '0 0 * * 1',
|
|
51
|
+
'Tuesday': '0 0 * * 2',
|
|
52
|
+
'Wednesday': '0 0 * * 3',
|
|
53
|
+
'Thursday': '0 0 * * 4',
|
|
54
|
+
'Friday': '0 0 * * 5',
|
|
55
|
+
'Saturday': '0 0 * * 6',
|
|
56
|
+
'Sunday': '0 0 * * 0',
|
|
57
|
+
// Common patterns
|
|
58
|
+
'weekday': '0 0 * * 1-5',
|
|
59
|
+
'weekend': '0 0 * * 0,6',
|
|
60
|
+
'midnight': '0 0 * * *',
|
|
61
|
+
'noon': '0 12 * * *',
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Time suffixes for day-based schedules
|
|
65
|
+
*/
|
|
66
|
+
const TIME_PATTERNS = {
|
|
67
|
+
'at6am': { hour: 6, minute: 0 },
|
|
68
|
+
'at7am': { hour: 7, minute: 0 },
|
|
69
|
+
'at8am': { hour: 8, minute: 0 },
|
|
70
|
+
'at9am': { hour: 9, minute: 0 },
|
|
71
|
+
'at10am': { hour: 10, minute: 0 },
|
|
72
|
+
'at11am': { hour: 11, minute: 0 },
|
|
73
|
+
'at12pm': { hour: 12, minute: 0 },
|
|
74
|
+
'atnoon': { hour: 12, minute: 0 },
|
|
75
|
+
'at1pm': { hour: 13, minute: 0 },
|
|
76
|
+
'at2pm': { hour: 14, minute: 0 },
|
|
77
|
+
'at3pm': { hour: 15, minute: 0 },
|
|
78
|
+
'at4pm': { hour: 16, minute: 0 },
|
|
79
|
+
'at5pm': { hour: 17, minute: 0 },
|
|
80
|
+
'at6pm': { hour: 18, minute: 0 },
|
|
81
|
+
'at7pm': { hour: 19, minute: 0 },
|
|
82
|
+
'at8pm': { hour: 20, minute: 0 },
|
|
83
|
+
'at9pm': { hour: 21, minute: 0 },
|
|
84
|
+
'atmidnight': { hour: 0, minute: 0 },
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Parse a known pattern or return null
|
|
88
|
+
*/
|
|
89
|
+
function parseKnownPattern(pattern) {
|
|
90
|
+
return KNOWN_PATTERNS[pattern] ?? null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Combine a day pattern with a time pattern
|
|
94
|
+
*/
|
|
95
|
+
function combineWithTime(baseCron, time) {
|
|
96
|
+
const parts = baseCron.split(' ');
|
|
97
|
+
parts[0] = String(time.minute);
|
|
98
|
+
parts[1] = String(time.hour);
|
|
99
|
+
return parts.join(' ');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* AI-powered cron conversion (placeholder - will use ai-functions)
|
|
103
|
+
*/
|
|
104
|
+
let cronConverter = null;
|
|
105
|
+
/**
|
|
106
|
+
* Set the AI cron converter function
|
|
107
|
+
*/
|
|
108
|
+
export function setCronConverter(converter) {
|
|
109
|
+
cronConverter = converter;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Convert natural language to cron expression
|
|
113
|
+
*/
|
|
114
|
+
export async function toCron(description) {
|
|
115
|
+
// First check known patterns
|
|
116
|
+
const known = parseKnownPattern(description);
|
|
117
|
+
if (known)
|
|
118
|
+
return known;
|
|
119
|
+
// If we have an AI converter, use it
|
|
120
|
+
if (cronConverter) {
|
|
121
|
+
return cronConverter(description);
|
|
122
|
+
}
|
|
123
|
+
// Otherwise, assume it's already a cron expression or throw
|
|
124
|
+
if (/^[\d\*\-\/\,\s]+$/.test(description)) {
|
|
125
|
+
return description;
|
|
126
|
+
}
|
|
127
|
+
throw new Error(`Unknown schedule pattern: "${description}". ` +
|
|
128
|
+
`Set up AI conversion with setCronConverter() for natural language schedules.`);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create the `every` proxy
|
|
132
|
+
*/
|
|
133
|
+
function createEveryProxy() {
|
|
134
|
+
const handler = {
|
|
135
|
+
get(_target, prop) {
|
|
136
|
+
// Check if it's a known pattern
|
|
137
|
+
const pattern = KNOWN_PATTERNS[prop];
|
|
138
|
+
if (pattern) {
|
|
139
|
+
// Return an object that can either be called directly or have time accessors
|
|
140
|
+
const result = (handlerFn) => {
|
|
141
|
+
registerScheduleHandler({ type: 'cron', expression: pattern, natural: prop }, handlerFn);
|
|
142
|
+
};
|
|
143
|
+
// Add time accessors
|
|
144
|
+
return new Proxy(result, {
|
|
145
|
+
get(_t, timeKey) {
|
|
146
|
+
const time = TIME_PATTERNS[timeKey];
|
|
147
|
+
if (time) {
|
|
148
|
+
const cron = combineWithTime(pattern, time);
|
|
149
|
+
return (handlerFn) => {
|
|
150
|
+
registerScheduleHandler({ type: 'cron', expression: cron, natural: `${prop}.${timeKey}` }, handlerFn);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return undefined;
|
|
154
|
+
},
|
|
155
|
+
apply(_t, _thisArg, args) {
|
|
156
|
+
registerScheduleHandler({ type: 'cron', expression: pattern, natural: prop }, args[0]);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
// Check for plural time units (e.g., seconds(5), minutes(30))
|
|
161
|
+
const pluralUnits = {
|
|
162
|
+
seconds: 'second',
|
|
163
|
+
minutes: 'minute',
|
|
164
|
+
hours: 'hour',
|
|
165
|
+
days: 'day',
|
|
166
|
+
weeks: 'week',
|
|
167
|
+
};
|
|
168
|
+
if (pluralUnits[prop]) {
|
|
169
|
+
return (value) => (handlerFn) => {
|
|
170
|
+
registerScheduleHandler({ type: pluralUnits[prop], value, natural: `${value} ${prop}` }, handlerFn);
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return undefined;
|
|
174
|
+
},
|
|
175
|
+
apply(_target, _thisArg, args) {
|
|
176
|
+
// Called as every('natural language description', handler)
|
|
177
|
+
const [description, handler] = args;
|
|
178
|
+
if (typeof description === 'string' && typeof handler === 'function') {
|
|
179
|
+
// Register with natural language - will be converted to cron at runtime
|
|
180
|
+
registerScheduleHandler({ type: 'natural', description }, handler);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
return new Proxy(function () { }, handler);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* The `every` function/object for registering scheduled handlers
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* import { every } from 'ai-workflows'
|
|
192
|
+
*
|
|
193
|
+
* // Simple intervals
|
|
194
|
+
* every.hour($ => $.log('Hourly task'))
|
|
195
|
+
* every.day($ => $.log('Daily task'))
|
|
196
|
+
*
|
|
197
|
+
* // Day + time combinations
|
|
198
|
+
* every.Monday.at9am($ => $.log('Monday morning standup'))
|
|
199
|
+
* every.weekday.at8am($ => $.log('Workday start'))
|
|
200
|
+
* every.Friday.at5pm($ => $.log('End of week report'))
|
|
201
|
+
*
|
|
202
|
+
* // Plural intervals with values
|
|
203
|
+
* every.minutes(30)($ => $.log('Every 30 minutes'))
|
|
204
|
+
* every.hours(4)($ => $.log('Every 4 hours'))
|
|
205
|
+
*
|
|
206
|
+
* // Natural language (requires AI converter)
|
|
207
|
+
* every('hour during business hours', $ => { ... })
|
|
208
|
+
* every('first Monday of the month at 9am', $ => { ... })
|
|
209
|
+
* every('every 15 minutes between 9am and 5pm on weekdays', $ => { ... })
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
export const every = createEveryProxy();
|
|
213
|
+
/**
|
|
214
|
+
* Convert interval to milliseconds (for simulation/testing)
|
|
215
|
+
*/
|
|
216
|
+
export function intervalToMs(interval) {
|
|
217
|
+
switch (interval.type) {
|
|
218
|
+
case 'second':
|
|
219
|
+
return (interval.value ?? 1) * 1000;
|
|
220
|
+
case 'minute':
|
|
221
|
+
return (interval.value ?? 1) * 60 * 1000;
|
|
222
|
+
case 'hour':
|
|
223
|
+
return (interval.value ?? 1) * 60 * 60 * 1000;
|
|
224
|
+
case 'day':
|
|
225
|
+
return (interval.value ?? 1) * 24 * 60 * 60 * 1000;
|
|
226
|
+
case 'week':
|
|
227
|
+
return (interval.value ?? 1) * 7 * 24 * 60 * 60 * 1000;
|
|
228
|
+
case 'cron':
|
|
229
|
+
case 'natural':
|
|
230
|
+
// Cron/natural expressions need special handling
|
|
231
|
+
return 0;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Format interval for display
|
|
236
|
+
*/
|
|
237
|
+
export function formatInterval(interval) {
|
|
238
|
+
if ('natural' in interval && interval.natural) {
|
|
239
|
+
return interval.natural;
|
|
240
|
+
}
|
|
241
|
+
switch (interval.type) {
|
|
242
|
+
case 'second':
|
|
243
|
+
return interval.value && interval.value > 1
|
|
244
|
+
? `every ${interval.value} seconds`
|
|
245
|
+
: 'every second';
|
|
246
|
+
case 'minute':
|
|
247
|
+
return interval.value && interval.value > 1
|
|
248
|
+
? `every ${interval.value} minutes`
|
|
249
|
+
: 'every minute';
|
|
250
|
+
case 'hour':
|
|
251
|
+
return interval.value && interval.value > 1
|
|
252
|
+
? `every ${interval.value} hours`
|
|
253
|
+
: 'every hour';
|
|
254
|
+
case 'day':
|
|
255
|
+
return interval.value && interval.value > 1
|
|
256
|
+
? `every ${interval.value} days`
|
|
257
|
+
: 'every day';
|
|
258
|
+
case 'week':
|
|
259
|
+
return interval.value && interval.value > 1
|
|
260
|
+
? `every ${interval.value} weeks`
|
|
261
|
+
: 'every week';
|
|
262
|
+
case 'cron':
|
|
263
|
+
return `cron: ${interval.expression}`;
|
|
264
|
+
case 'natural':
|
|
265
|
+
return interval.description;
|
|
266
|
+
}
|
|
267
|
+
}
|
package/src/every.ts
CHANGED
|
@@ -9,7 +9,16 @@
|
|
|
9
9
|
* every('first Monday of the month at 9am', $ => { ... })
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type {
|
|
12
|
+
import type {
|
|
13
|
+
ScheduleHandler,
|
|
14
|
+
ScheduleRegistration,
|
|
15
|
+
ScheduleInterval,
|
|
16
|
+
EveryProxyTarget,
|
|
17
|
+
EveryProxy,
|
|
18
|
+
EveryProxyHandler,
|
|
19
|
+
DayScheduleProxyHandler,
|
|
20
|
+
} from './types.js'
|
|
21
|
+
import { PLURAL_UNITS, isPluralUnitKey } from './types.js'
|
|
13
22
|
|
|
14
23
|
/**
|
|
15
24
|
* Registry of schedule handlers
|
|
@@ -151,65 +160,125 @@ export async function toCron(description: string): Promise<string> {
|
|
|
151
160
|
}
|
|
152
161
|
|
|
153
162
|
/**
|
|
154
|
-
*
|
|
163
|
+
* Schedule registration callback type
|
|
164
|
+
* Used by createTypedEveryProxy to customize handler registration
|
|
155
165
|
*/
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
166
|
+
export type EveryProxyRegistrationCallback = (
|
|
167
|
+
interval: ScheduleInterval,
|
|
168
|
+
handler: ScheduleHandler
|
|
169
|
+
) => void
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Create a typed EveryProxy with proper TypeScript generics
|
|
173
|
+
*
|
|
174
|
+
* This factory function creates a callable proxy that supports:
|
|
175
|
+
* - Direct calls: every('natural language', handler)
|
|
176
|
+
* - Simple patterns: every.hour(handler)
|
|
177
|
+
* - Day + time: every.Monday.at9am(handler)
|
|
178
|
+
* - Intervals: every.minutes(30)(handler)
|
|
179
|
+
*
|
|
180
|
+
* @param registerCallback - Function called when a handler is registered
|
|
181
|
+
* @returns A properly typed EveryProxy
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* // Create proxy with custom registration
|
|
186
|
+
* const myEvery = createTypedEveryProxy((interval, handler) => {
|
|
187
|
+
* myRegistry.push({ interval, handler })
|
|
188
|
+
* })
|
|
189
|
+
*
|
|
190
|
+
* myEvery.hour(handler) // Properly typed!
|
|
191
|
+
* myEvery.Monday.at9am(handler) // Chained access typed!
|
|
192
|
+
* ```
|
|
193
|
+
*/
|
|
194
|
+
export function createTypedEveryProxy(registerCallback: EveryProxyRegistrationCallback): EveryProxy {
|
|
195
|
+
// Create typed handler for day schedule patterns with time modifiers
|
|
196
|
+
const createDayScheduleHandler = (
|
|
197
|
+
pattern: string,
|
|
198
|
+
prop: string
|
|
199
|
+
): DayScheduleProxyHandler => ({
|
|
200
|
+
get(
|
|
201
|
+
_target: (handler: ScheduleHandler) => void,
|
|
202
|
+
timeKey: string,
|
|
203
|
+
_receiver: unknown
|
|
204
|
+
): ((handler: ScheduleHandler) => void) | undefined {
|
|
205
|
+
const time = TIME_PATTERNS[timeKey]
|
|
206
|
+
if (time) {
|
|
207
|
+
const cron = combineWithTime(pattern, time)
|
|
208
|
+
return (handlerFn: ScheduleHandler) => {
|
|
209
|
+
registerCallback({ type: 'cron', expression: cron, natural: `${prop}.${timeKey}` }, handlerFn)
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return undefined
|
|
213
|
+
},
|
|
214
|
+
apply(
|
|
215
|
+
_target: (handler: ScheduleHandler) => void,
|
|
216
|
+
_thisArg: unknown,
|
|
217
|
+
args: [ScheduleHandler]
|
|
218
|
+
): void {
|
|
219
|
+
registerCallback({ type: 'cron', expression: pattern, natural: prop }, args[0])
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
// Create the main EveryProxy handler
|
|
224
|
+
const everyHandler: EveryProxyHandler = {
|
|
225
|
+
get(
|
|
226
|
+
_target: EveryProxyTarget,
|
|
227
|
+
prop: string,
|
|
228
|
+
_receiver: unknown
|
|
229
|
+
): unknown {
|
|
159
230
|
// Check if it's a known pattern
|
|
160
231
|
const pattern = KNOWN_PATTERNS[prop]
|
|
161
232
|
if (pattern) {
|
|
162
233
|
// Return an object that can either be called directly or have time accessors
|
|
163
234
|
const result = (handlerFn: ScheduleHandler) => {
|
|
164
|
-
|
|
235
|
+
registerCallback({ type: 'cron', expression: pattern, natural: prop }, handlerFn)
|
|
165
236
|
}
|
|
166
|
-
// Add time accessors
|
|
167
|
-
return new Proxy(result,
|
|
168
|
-
get(_t, timeKey: string) {
|
|
169
|
-
const time = TIME_PATTERNS[timeKey]
|
|
170
|
-
if (time) {
|
|
171
|
-
const cron = combineWithTime(pattern, time)
|
|
172
|
-
return (handlerFn: ScheduleHandler) => {
|
|
173
|
-
registerScheduleHandler({ type: 'cron', expression: cron, natural: `${prop}.${timeKey}` }, handlerFn)
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
return undefined
|
|
177
|
-
},
|
|
178
|
-
apply(_t, _thisArg, args) {
|
|
179
|
-
registerScheduleHandler({ type: 'cron', expression: pattern, natural: prop }, args[0])
|
|
180
|
-
}
|
|
181
|
-
})
|
|
237
|
+
// Add time accessors with typed handler
|
|
238
|
+
return new Proxy(result, createDayScheduleHandler(pattern, prop))
|
|
182
239
|
}
|
|
183
240
|
|
|
184
241
|
// Check for plural time units (e.g., seconds(5), minutes(30))
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
hours: 'hour',
|
|
189
|
-
days: 'day',
|
|
190
|
-
weeks: 'week',
|
|
191
|
-
}
|
|
192
|
-
if (pluralUnits[prop]) {
|
|
242
|
+
// Using type guard and typed constant for type-safe interval creation
|
|
243
|
+
if (isPluralUnitKey(prop)) {
|
|
244
|
+
const intervalType = PLURAL_UNITS[prop]
|
|
193
245
|
return (value: number) => (handlerFn: ScheduleHandler) => {
|
|
194
|
-
|
|
246
|
+
registerCallback({ type: intervalType, value, natural: `${value} ${prop}` }, handlerFn)
|
|
195
247
|
}
|
|
196
248
|
}
|
|
197
249
|
|
|
198
250
|
return undefined
|
|
199
251
|
},
|
|
200
252
|
|
|
201
|
-
apply(
|
|
253
|
+
apply(
|
|
254
|
+
_target: EveryProxyTarget,
|
|
255
|
+
_thisArg: unknown,
|
|
256
|
+
args: [string, ScheduleHandler]
|
|
257
|
+
): void {
|
|
202
258
|
// Called as every('natural language description', handler)
|
|
203
|
-
const [description, handler] = args
|
|
259
|
+
const [description, handler] = args
|
|
204
260
|
|
|
205
261
|
if (typeof description === 'string' && typeof handler === 'function') {
|
|
206
262
|
// Register with natural language - will be converted to cron at runtime
|
|
207
|
-
|
|
263
|
+
registerCallback({ type: 'natural', description }, handler)
|
|
208
264
|
}
|
|
209
265
|
}
|
|
210
266
|
}
|
|
211
267
|
|
|
212
|
-
|
|
268
|
+
// Create callable target with proper typing
|
|
269
|
+
// The function serves as the Proxy target - actual behavior is in the handler's apply trap
|
|
270
|
+
const target: EveryProxyTarget = function(_description: string, _handler: ScheduleHandler) {}
|
|
271
|
+
return new Proxy(target, everyHandler) as EveryProxy
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Create the `every` proxy using the global schedule registry
|
|
276
|
+
*
|
|
277
|
+
* This is the default implementation that uses registerScheduleHandler
|
|
278
|
+
* for backward compatibility with the standalone `every` export.
|
|
279
|
+
*/
|
|
280
|
+
function createEveryProxy(): EveryProxy {
|
|
281
|
+
return createTypedEveryProxy(registerScheduleHandler)
|
|
213
282
|
}
|
|
214
283
|
|
|
215
284
|
/**
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph algorithms for workflow execution ordering
|
|
3
|
+
*
|
|
4
|
+
* Provides topological sorting and execution level grouping for
|
|
5
|
+
* managing workflow step dependencies.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
topologicalSort,
|
|
10
|
+
topologicalSortKahn,
|
|
11
|
+
topologicalSortDFS,
|
|
12
|
+
getExecutionLevels,
|
|
13
|
+
CycleDetectedError,
|
|
14
|
+
MissingNodeError,
|
|
15
|
+
type SortableNode,
|
|
16
|
+
type ExecutionLevel,
|
|
17
|
+
type TopologicalSortOptions,
|
|
18
|
+
type TopologicalSortResult,
|
|
19
|
+
} from './topological-sort.js'
|