ai-workflows 2.1.3 → 2.3.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.
Files changed (188) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +8 -1
  3. package/README.md +2 -0
  4. package/dist/barrier.d.ts +6 -0
  5. package/dist/barrier.d.ts.map +1 -1
  6. package/dist/barrier.js +45 -7
  7. package/dist/barrier.js.map +1 -1
  8. package/dist/cascade-context.d.ts.map +1 -1
  9. package/dist/cascade-context.js +25 -25
  10. package/dist/cascade-context.js.map +1 -1
  11. package/dist/cascade-executor.d.ts.map +1 -1
  12. package/dist/cascade-executor.js +1 -1
  13. package/dist/cascade-executor.js.map +1 -1
  14. package/dist/context.d.ts.map +1 -1
  15. package/dist/context.js +23 -7
  16. package/dist/context.js.map +1 -1
  17. package/dist/cron-parser.d.ts +65 -0
  18. package/dist/cron-parser.d.ts.map +1 -0
  19. package/dist/cron-parser.js +294 -0
  20. package/dist/cron-parser.js.map +1 -0
  21. package/dist/cron-scheduler.d.ts +117 -0
  22. package/dist/cron-scheduler.d.ts.map +1 -0
  23. package/dist/cron-scheduler.js +176 -0
  24. package/dist/cron-scheduler.js.map +1 -0
  25. package/dist/database-context.d.ts +184 -0
  26. package/dist/database-context.d.ts.map +1 -0
  27. package/dist/database-context.js +428 -0
  28. package/dist/database-context.js.map +1 -0
  29. package/dist/digital-objects-adapter.d.ts +159 -0
  30. package/dist/digital-objects-adapter.d.ts.map +1 -0
  31. package/dist/digital-objects-adapter.js +229 -0
  32. package/dist/digital-objects-adapter.js.map +1 -0
  33. package/dist/durable-execution-cloudflare.d.ts +427 -0
  34. package/dist/durable-execution-cloudflare.d.ts.map +1 -0
  35. package/dist/durable-execution-cloudflare.js +510 -0
  36. package/dist/durable-execution-cloudflare.js.map +1 -0
  37. package/dist/durable-execution.d.ts +482 -0
  38. package/dist/durable-execution.d.ts.map +1 -0
  39. package/dist/durable-execution.js +594 -0
  40. package/dist/durable-execution.js.map +1 -0
  41. package/dist/durable-workflow.d.ts +176 -0
  42. package/dist/durable-workflow.d.ts.map +1 -0
  43. package/dist/durable-workflow.js +552 -0
  44. package/dist/durable-workflow.js.map +1 -0
  45. package/dist/graph/topological-sort.d.ts.map +1 -1
  46. package/dist/graph/topological-sort.js +5 -5
  47. package/dist/graph/topological-sort.js.map +1 -1
  48. package/dist/index.d.ts +4 -0
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +15 -0
  51. package/dist/index.js.map +1 -1
  52. package/dist/logger.d.ts +101 -0
  53. package/dist/logger.d.ts.map +1 -0
  54. package/dist/logger.js +115 -0
  55. package/dist/logger.js.map +1 -0
  56. package/dist/on.d.ts.map +1 -1
  57. package/dist/on.js +3 -3
  58. package/dist/on.js.map +1 -1
  59. package/dist/runtime.d.ts +169 -0
  60. package/dist/runtime.d.ts.map +1 -0
  61. package/dist/runtime.js +275 -0
  62. package/dist/runtime.js.map +1 -0
  63. package/dist/send.d.ts.map +1 -1
  64. package/dist/send.js +4 -3
  65. package/dist/send.js.map +1 -1
  66. package/dist/telemetry.d.ts +150 -0
  67. package/dist/telemetry.d.ts.map +1 -0
  68. package/dist/telemetry.js +388 -0
  69. package/dist/telemetry.js.map +1 -0
  70. package/dist/timer-registry.d.ts +25 -0
  71. package/dist/timer-registry.d.ts.map +1 -1
  72. package/dist/timer-registry.js +42 -8
  73. package/dist/timer-registry.js.map +1 -1
  74. package/dist/types.d.ts +17 -6
  75. package/dist/types.d.ts.map +1 -1
  76. package/dist/types.js +1 -1
  77. package/dist/types.js.map +1 -1
  78. package/dist/worker/durable-step.d.ts +481 -0
  79. package/dist/worker/durable-step.d.ts.map +1 -0
  80. package/dist/worker/durable-step.js +606 -0
  81. package/dist/worker/durable-step.js.map +1 -0
  82. package/dist/worker/index.d.ts +106 -0
  83. package/dist/worker/index.d.ts.map +1 -0
  84. package/dist/worker/index.js +124 -0
  85. package/dist/worker/index.js.map +1 -0
  86. package/dist/worker/state-adapter.d.ts +230 -0
  87. package/dist/worker/state-adapter.d.ts.map +1 -0
  88. package/dist/worker/state-adapter.js +409 -0
  89. package/dist/worker/state-adapter.js.map +1 -0
  90. package/dist/worker/topological-executor.d.ts +282 -0
  91. package/dist/worker/topological-executor.d.ts.map +1 -0
  92. package/dist/worker/topological-executor.js +396 -0
  93. package/dist/worker/topological-executor.js.map +1 -0
  94. package/dist/worker/workflow-builder.d.ts +286 -0
  95. package/dist/worker/workflow-builder.d.ts.map +1 -0
  96. package/dist/worker/workflow-builder.js +565 -0
  97. package/dist/worker/workflow-builder.js.map +1 -0
  98. package/dist/worker.d.ts +800 -0
  99. package/dist/worker.d.ts.map +1 -0
  100. package/dist/worker.js +2428 -0
  101. package/dist/worker.js.map +1 -0
  102. package/dist/workflow-builder.d.ts +287 -0
  103. package/dist/workflow-builder.d.ts.map +1 -0
  104. package/dist/workflow-builder.js +762 -0
  105. package/dist/workflow-builder.js.map +1 -0
  106. package/dist/workflow.d.ts +14 -30
  107. package/dist/workflow.d.ts.map +1 -1
  108. package/dist/workflow.js +132 -292
  109. package/dist/workflow.js.map +1 -1
  110. package/examples/01-ecommerce-order-pipeline.ts +358 -0
  111. package/examples/02-content-moderation-cascade.ts +454 -0
  112. package/examples/03-scheduled-reporting-dependencies.ts +479 -0
  113. package/examples/04-database-persistence.ts +518 -0
  114. package/examples/README.md +173 -0
  115. package/package.json +30 -13
  116. package/src/__tests__/digital-objects-adapter.test.ts +274 -0
  117. package/src/__tests__/durable-workflow.test.ts +297 -0
  118. package/src/barrier.ts +48 -7
  119. package/src/cascade-context.ts +36 -29
  120. package/src/cascade-executor.ts +3 -2
  121. package/src/context.ts +41 -12
  122. package/src/cron-parser.ts +347 -0
  123. package/src/cron-scheduler.ts +239 -0
  124. package/src/database-context.ts +658 -0
  125. package/src/digital-objects-adapter.ts +351 -0
  126. package/src/durable-execution-cloudflare.ts +855 -0
  127. package/src/durable-execution.ts +1042 -0
  128. package/src/durable-workflow.ts +717 -0
  129. package/src/graph/topological-sort.ts +6 -8
  130. package/src/index.ts +69 -0
  131. package/src/logger.ts +148 -0
  132. package/src/on.ts +8 -9
  133. package/src/runtime.ts +436 -0
  134. package/src/send.ts +4 -5
  135. package/src/telemetry.ts +577 -0
  136. package/src/timer-registry.ts +44 -10
  137. package/src/types.ts +32 -17
  138. package/src/worker/durable-step.ts +976 -0
  139. package/src/worker/index.ts +216 -0
  140. package/src/worker/state-adapter.ts +589 -0
  141. package/src/worker/topological-executor.ts +625 -0
  142. package/src/worker/workflow-builder.ts +871 -0
  143. package/src/worker.ts +2906 -0
  144. package/src/workflow-builder.ts +1068 -0
  145. package/src/workflow.ts +188 -351
  146. package/test/barrier-join.test.ts +32 -24
  147. package/test/cascade-executor.test.ts +9 -16
  148. package/test/cron-parser.test.ts +314 -0
  149. package/test/cron-scheduler.test.ts +291 -0
  150. package/test/database-context.test.ts +770 -0
  151. package/test/db-provider-adapter.test.ts +862 -0
  152. package/test/durable-execution-cloudflare.test.ts +606 -0
  153. package/test/durable-execution-in-process.test.ts +286 -0
  154. package/test/durable-execution.test.ts +247 -0
  155. package/test/e2e/workflow-scenarios.e2e.test.ts +1039 -0
  156. package/test/integration.test.ts +442 -0
  157. package/test/rpc-surface.test.ts +946 -0
  158. package/test/runtime.test.ts +262 -0
  159. package/test/schedule-timer-cleanup.test.ts +30 -21
  160. package/test/send-race-conditions.test.ts +30 -40
  161. package/test/worker/durable-cascade.test.ts +1117 -0
  162. package/test/worker/durable-step.test.ts +723 -0
  163. package/test/worker/topological-executor.test.ts +1240 -0
  164. package/test/worker/workflow-builder.test.ts +1067 -0
  165. package/test/worker.test.ts +608 -0
  166. package/test/workflow-builder.test.ts +1670 -0
  167. package/test/workflow-cron.test.ts +256 -0
  168. package/test/workflow-state-adapter.test.ts +923 -0
  169. package/test/workflow.test.ts +25 -22
  170. package/tsconfig.json +3 -1
  171. package/vitest.config.ts +38 -1
  172. package/vitest.workers.config.ts +44 -0
  173. package/wrangler.jsonc +22 -0
  174. package/.turbo/turbo-test.log +0 -169
  175. package/LICENSE +0 -21
  176. package/src/context.js +0 -83
  177. package/src/every.js +0 -267
  178. package/src/index.js +0 -71
  179. package/src/on.js +0 -79
  180. package/src/send.js +0 -111
  181. package/src/types.js +0 -4
  182. package/src/workflow.js +0 -455
  183. package/test/context.test.js +0 -116
  184. package/test/every.test.js +0 -282
  185. package/test/on.test.js +0 -80
  186. package/test/send.test.js +0 -89
  187. package/test/workflow.test.js +0 -224
  188. package/vitest.config.js +0 -7
@@ -0,0 +1,256 @@
1
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'
2
+ import { Workflow } from '../src/workflow.js'
3
+ import { clearEventHandlers } from '../src/on.js'
4
+ import { clearScheduleHandlers, setCronConverter } from '../src/every.js'
5
+ import { stopAllCronJobs } from '../src/cron-scheduler.js'
6
+
7
+ describe('Workflow cron scheduling', () => {
8
+ beforeEach(() => {
9
+ clearEventHandlers()
10
+ clearScheduleHandlers()
11
+ stopAllCronJobs()
12
+ vi.useFakeTimers()
13
+ })
14
+
15
+ afterEach(() => {
16
+ stopAllCronJobs()
17
+ vi.useRealTimers()
18
+ })
19
+
20
+ describe('$.every with cron patterns', () => {
21
+ it('should execute cron schedule at correct time', async () => {
22
+ const handler = vi.fn()
23
+
24
+ // Set to Monday 8:55am
25
+ vi.setSystemTime(new Date('2024-01-15T08:55:00'))
26
+
27
+ const workflow = Workflow(($) => {
28
+ // Every hour at minute 0 (cron: 0 * * * *)
29
+ $.every.hour(handler)
30
+ })
31
+
32
+ await workflow.start()
33
+
34
+ // Advance 5 minutes to 9:00am (next hour boundary)
35
+ await vi.advanceTimersByTimeAsync(5 * 60 * 1000)
36
+
37
+ expect(handler).toHaveBeenCalledTimes(1)
38
+
39
+ // Advance another hour to 10:00am
40
+ await vi.advanceTimersByTimeAsync(60 * 60 * 1000)
41
+ expect(handler).toHaveBeenCalledTimes(2)
42
+
43
+ await workflow.stop()
44
+ })
45
+
46
+ it('should execute day-specific schedule ($.every.Monday)', async () => {
47
+ const handler = vi.fn()
48
+
49
+ // Set to Sunday 11pm
50
+ vi.setSystemTime(new Date('2024-01-14T23:00:00'))
51
+
52
+ const workflow = Workflow(($) => {
53
+ // Every Monday at midnight (cron: 0 0 * * 1)
54
+ $.every.Monday(handler)
55
+ })
56
+
57
+ await workflow.start()
58
+
59
+ // Advance 1 hour to Monday midnight
60
+ await vi.advanceTimersByTimeAsync(60 * 60 * 1000)
61
+
62
+ expect(handler).toHaveBeenCalledTimes(1)
63
+
64
+ await workflow.stop()
65
+ })
66
+
67
+ it('should execute day+time schedule ($.every.Monday.at9am)', async () => {
68
+ const handler = vi.fn()
69
+
70
+ // Set to Monday 8:30am
71
+ vi.setSystemTime(new Date('2024-01-15T08:30:00'))
72
+
73
+ const workflow = Workflow(($) => {
74
+ // Every Monday at 9am (cron: 0 9 * * 1)
75
+ $.every.Monday.at9am(handler)
76
+ })
77
+
78
+ await workflow.start()
79
+
80
+ // Advance 30 minutes to 9:00am
81
+ await vi.advanceTimersByTimeAsync(30 * 60 * 1000)
82
+
83
+ expect(handler).toHaveBeenCalledTimes(1)
84
+
85
+ await workflow.stop()
86
+ })
87
+
88
+ it('should handle weekday schedule', async () => {
89
+ const handler = vi.fn()
90
+
91
+ // Set to Monday 8:55am
92
+ vi.setSystemTime(new Date('2024-01-15T08:55:00'))
93
+
94
+ const workflow = Workflow(($) => {
95
+ $.every.weekday.at9am(handler)
96
+ })
97
+
98
+ await workflow.start()
99
+
100
+ // Advance 5 minutes to 9am
101
+ await vi.advanceTimersByTimeAsync(5 * 60 * 1000)
102
+
103
+ expect(handler).toHaveBeenCalledTimes(1)
104
+
105
+ await workflow.stop()
106
+ })
107
+
108
+ it('should stop cron jobs on workflow stop', async () => {
109
+ const handler = vi.fn()
110
+
111
+ vi.setSystemTime(new Date('2024-01-15T08:55:00'))
112
+
113
+ const workflow = Workflow(($) => {
114
+ $.every.hour(handler)
115
+ })
116
+
117
+ await workflow.start()
118
+
119
+ // Advance to next hour
120
+ await vi.advanceTimersByTimeAsync(5 * 60 * 1000)
121
+ expect(handler).toHaveBeenCalledTimes(1)
122
+
123
+ // Stop workflow
124
+ await workflow.stop()
125
+
126
+ // Advance another hour - should NOT call handler
127
+ await vi.advanceTimersByTimeAsync(60 * 60 * 1000)
128
+ expect(handler).toHaveBeenCalledTimes(1) // Still 1
129
+ })
130
+
131
+ it('should handle multiple cron schedules', async () => {
132
+ const hourlyHandler = vi.fn()
133
+ const dailyHandler = vi.fn()
134
+
135
+ // Set to 8:55am
136
+ vi.setSystemTime(new Date('2024-01-15T08:55:00'))
137
+
138
+ const workflow = Workflow(($) => {
139
+ $.every.hour(hourlyHandler)
140
+ $.every.day(dailyHandler)
141
+ })
142
+
143
+ await workflow.start()
144
+
145
+ // Advance to 9:00am (hourly triggers)
146
+ await vi.advanceTimersByTimeAsync(5 * 60 * 1000)
147
+ expect(hourlyHandler).toHaveBeenCalledTimes(1)
148
+ expect(dailyHandler).toHaveBeenCalledTimes(0)
149
+
150
+ await workflow.stop()
151
+ })
152
+
153
+ it('should track schedule execution in history', async () => {
154
+ vi.setSystemTime(new Date('2024-01-15T08:55:00'))
155
+
156
+ const workflow = Workflow(($) => {
157
+ $.every.hour(async ($) => {
158
+ $.log('Hourly task')
159
+ })
160
+ })
161
+
162
+ await workflow.start()
163
+
164
+ // Advance to 9:00am
165
+ await vi.advanceTimersByTimeAsync(5 * 60 * 1000)
166
+
167
+ // Check history has schedule entry
168
+ const history = workflow.state.history
169
+ const scheduleEntries = history.filter((h) => h.type === 'schedule')
170
+ expect(scheduleEntries.length).toBeGreaterThanOrEqual(1)
171
+
172
+ await workflow.stop()
173
+ })
174
+ })
175
+
176
+ describe('$.every with natural language', () => {
177
+ it('should convert natural language to cron and execute', async () => {
178
+ const handler = vi.fn()
179
+
180
+ // Set up AI converter
181
+ setCronConverter(async (desc) => {
182
+ if (desc === 'every weekday morning') {
183
+ return '0 9 * * 1-5'
184
+ }
185
+ throw new Error(`Unknown: ${desc}`)
186
+ })
187
+
188
+ // Set to Monday 8:55am
189
+ vi.setSystemTime(new Date('2024-01-15T08:55:00'))
190
+
191
+ const workflow = Workflow(($) => {
192
+ $.every('every weekday morning', handler)
193
+ })
194
+
195
+ await workflow.start()
196
+
197
+ // Wait for async natural language parsing
198
+ await vi.advanceTimersByTimeAsync(100)
199
+
200
+ // Advance to 9:00am
201
+ await vi.advanceTimersByTimeAsync(5 * 60 * 1000)
202
+
203
+ expect(handler).toHaveBeenCalledTimes(1)
204
+
205
+ await workflow.stop()
206
+ })
207
+ })
208
+
209
+ describe('mixed schedules (interval + cron)', () => {
210
+ it('should support both interval and cron schedules', async () => {
211
+ const intervalHandler = vi.fn()
212
+ const cronHandler = vi.fn()
213
+
214
+ vi.setSystemTime(new Date('2024-01-15T08:55:00'))
215
+
216
+ const workflow = Workflow(($) => {
217
+ // Interval-based: every 30 seconds
218
+ $.every.seconds(30)(intervalHandler)
219
+ // Cron-based: every hour
220
+ $.every.hour(cronHandler)
221
+ })
222
+
223
+ await workflow.start()
224
+
225
+ // Advance 30 seconds - interval triggers
226
+ await vi.advanceTimersByTimeAsync(30 * 1000)
227
+ expect(intervalHandler).toHaveBeenCalledTimes(1)
228
+ expect(cronHandler).toHaveBeenCalledTimes(0)
229
+
230
+ // Advance to next hour
231
+ await vi.advanceTimersByTimeAsync(5 * 60 * 1000 - 30 * 1000)
232
+ expect(cronHandler).toHaveBeenCalledTimes(1)
233
+
234
+ await workflow.stop()
235
+ })
236
+ })
237
+
238
+ describe('timer count', () => {
239
+ it('should include cron jobs in timer count', async () => {
240
+ const workflow = Workflow(($) => {
241
+ $.every.seconds(10)(() => {})
242
+ $.every.hour(() => {})
243
+ $.every.Monday.at9am(() => {})
244
+ })
245
+
246
+ await workflow.start()
247
+
248
+ // Should have 3 schedules (1 interval + 2 cron)
249
+ expect(workflow.timerCount).toBe(3)
250
+
251
+ await workflow.stop()
252
+
253
+ expect(workflow.timerCount).toBe(0)
254
+ })
255
+ })
256
+ })