ai-workflows 2.1.1 → 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 (211) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -1
  3. package/README.md +305 -184
  4. package/dist/barrier.d.ts +159 -0
  5. package/dist/barrier.d.ts.map +1 -0
  6. package/dist/barrier.js +377 -0
  7. package/dist/barrier.js.map +1 -0
  8. package/dist/cascade-context.d.ts +149 -0
  9. package/dist/cascade-context.d.ts.map +1 -0
  10. package/dist/cascade-context.js +324 -0
  11. package/dist/cascade-context.js.map +1 -0
  12. package/dist/cascade-executor.d.ts +196 -0
  13. package/dist/cascade-executor.d.ts.map +1 -0
  14. package/dist/cascade-executor.js +384 -0
  15. package/dist/cascade-executor.js.map +1 -0
  16. package/dist/context.d.ts.map +1 -1
  17. package/dist/context.js +27 -8
  18. package/dist/context.js.map +1 -1
  19. package/dist/cron-parser.d.ts +65 -0
  20. package/dist/cron-parser.d.ts.map +1 -0
  21. package/dist/cron-parser.js +294 -0
  22. package/dist/cron-parser.js.map +1 -0
  23. package/dist/cron-scheduler.d.ts +117 -0
  24. package/dist/cron-scheduler.d.ts.map +1 -0
  25. package/dist/cron-scheduler.js +176 -0
  26. package/dist/cron-scheduler.js.map +1 -0
  27. package/dist/database-context.d.ts +184 -0
  28. package/dist/database-context.d.ts.map +1 -0
  29. package/dist/database-context.js +428 -0
  30. package/dist/database-context.js.map +1 -0
  31. package/dist/dependency-graph.d.ts +157 -0
  32. package/dist/dependency-graph.d.ts.map +1 -0
  33. package/dist/dependency-graph.js +382 -0
  34. package/dist/dependency-graph.js.map +1 -0
  35. package/dist/digital-objects-adapter.d.ts +159 -0
  36. package/dist/digital-objects-adapter.d.ts.map +1 -0
  37. package/dist/digital-objects-adapter.js +229 -0
  38. package/dist/digital-objects-adapter.js.map +1 -0
  39. package/dist/durable-execution-cloudflare.d.ts +427 -0
  40. package/dist/durable-execution-cloudflare.d.ts.map +1 -0
  41. package/dist/durable-execution-cloudflare.js +510 -0
  42. package/dist/durable-execution-cloudflare.js.map +1 -0
  43. package/dist/durable-execution.d.ts +482 -0
  44. package/dist/durable-execution.d.ts.map +1 -0
  45. package/dist/durable-execution.js +594 -0
  46. package/dist/durable-execution.js.map +1 -0
  47. package/dist/durable-workflow.d.ts +176 -0
  48. package/dist/durable-workflow.d.ts.map +1 -0
  49. package/dist/durable-workflow.js +552 -0
  50. package/dist/durable-workflow.js.map +1 -0
  51. package/dist/every.d.ts +31 -2
  52. package/dist/every.d.ts.map +1 -1
  53. package/dist/every.js +63 -32
  54. package/dist/every.js.map +1 -1
  55. package/dist/graph/index.d.ts +8 -0
  56. package/dist/graph/index.d.ts.map +1 -0
  57. package/dist/graph/index.js +8 -0
  58. package/dist/graph/index.js.map +1 -0
  59. package/dist/graph/topological-sort.d.ts +121 -0
  60. package/dist/graph/topological-sort.d.ts.map +1 -0
  61. package/dist/graph/topological-sort.js +292 -0
  62. package/dist/graph/topological-sort.js.map +1 -0
  63. package/dist/index.d.ts +10 -1
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +25 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/logger.d.ts +101 -0
  68. package/dist/logger.d.ts.map +1 -0
  69. package/dist/logger.js +115 -0
  70. package/dist/logger.js.map +1 -0
  71. package/dist/on.d.ts +35 -10
  72. package/dist/on.d.ts.map +1 -1
  73. package/dist/on.js +53 -19
  74. package/dist/on.js.map +1 -1
  75. package/dist/runtime.d.ts +169 -0
  76. package/dist/runtime.d.ts.map +1 -0
  77. package/dist/runtime.js +275 -0
  78. package/dist/runtime.js.map +1 -0
  79. package/dist/send.d.ts.map +1 -1
  80. package/dist/send.js +4 -3
  81. package/dist/send.js.map +1 -1
  82. package/dist/telemetry.d.ts +150 -0
  83. package/dist/telemetry.d.ts.map +1 -0
  84. package/dist/telemetry.js +388 -0
  85. package/dist/telemetry.js.map +1 -0
  86. package/dist/timer-registry.d.ts +77 -0
  87. package/dist/timer-registry.d.ts.map +1 -0
  88. package/dist/timer-registry.js +154 -0
  89. package/dist/timer-registry.js.map +1 -0
  90. package/dist/types.d.ts +105 -6
  91. package/dist/types.d.ts.map +1 -1
  92. package/dist/types.js +17 -1
  93. package/dist/types.js.map +1 -1
  94. package/dist/worker/durable-step.d.ts +481 -0
  95. package/dist/worker/durable-step.d.ts.map +1 -0
  96. package/dist/worker/durable-step.js +606 -0
  97. package/dist/worker/durable-step.js.map +1 -0
  98. package/dist/worker/index.d.ts +106 -0
  99. package/dist/worker/index.d.ts.map +1 -0
  100. package/dist/worker/index.js +124 -0
  101. package/dist/worker/index.js.map +1 -0
  102. package/dist/worker/state-adapter.d.ts +230 -0
  103. package/dist/worker/state-adapter.d.ts.map +1 -0
  104. package/dist/worker/state-adapter.js +409 -0
  105. package/dist/worker/state-adapter.js.map +1 -0
  106. package/dist/worker/topological-executor.d.ts +282 -0
  107. package/dist/worker/topological-executor.d.ts.map +1 -0
  108. package/dist/worker/topological-executor.js +396 -0
  109. package/dist/worker/topological-executor.js.map +1 -0
  110. package/dist/worker/workflow-builder.d.ts +286 -0
  111. package/dist/worker/workflow-builder.d.ts.map +1 -0
  112. package/dist/worker/workflow-builder.js +565 -0
  113. package/dist/worker/workflow-builder.js.map +1 -0
  114. package/dist/worker.d.ts +800 -0
  115. package/dist/worker.d.ts.map +1 -0
  116. package/dist/worker.js +2428 -0
  117. package/dist/worker.js.map +1 -0
  118. package/dist/workflow-builder.d.ts +287 -0
  119. package/dist/workflow-builder.d.ts.map +1 -0
  120. package/dist/workflow-builder.js +762 -0
  121. package/dist/workflow-builder.js.map +1 -0
  122. package/dist/workflow.d.ts +14 -30
  123. package/dist/workflow.d.ts.map +1 -1
  124. package/dist/workflow.js +136 -292
  125. package/dist/workflow.js.map +1 -1
  126. package/examples/01-ecommerce-order-pipeline.ts +358 -0
  127. package/examples/02-content-moderation-cascade.ts +454 -0
  128. package/examples/03-scheduled-reporting-dependencies.ts +479 -0
  129. package/examples/04-database-persistence.ts +518 -0
  130. package/examples/README.md +173 -0
  131. package/package.json +21 -4
  132. package/src/__tests__/digital-objects-adapter.test.ts +274 -0
  133. package/src/__tests__/durable-workflow.test.ts +297 -0
  134. package/src/barrier.ts +507 -0
  135. package/src/cascade-context.ts +495 -0
  136. package/src/cascade-executor.ts +588 -0
  137. package/src/context.ts +51 -17
  138. package/src/cron-parser.ts +347 -0
  139. package/src/cron-scheduler.ts +239 -0
  140. package/src/database-context.ts +658 -0
  141. package/src/dependency-graph.ts +518 -0
  142. package/src/digital-objects-adapter.ts +351 -0
  143. package/src/durable-execution-cloudflare.ts +855 -0
  144. package/src/durable-execution.ts +1042 -0
  145. package/src/durable-workflow.ts +717 -0
  146. package/src/every.ts +104 -35
  147. package/src/graph/index.ts +19 -0
  148. package/src/graph/topological-sort.ts +412 -0
  149. package/src/index.ts +147 -0
  150. package/src/logger.ts +148 -0
  151. package/src/on.ts +81 -26
  152. package/src/runtime.ts +436 -0
  153. package/src/send.ts +4 -5
  154. package/src/telemetry.ts +577 -0
  155. package/src/timer-registry.ts +179 -0
  156. package/src/types.ts +146 -10
  157. package/src/worker/durable-step.ts +976 -0
  158. package/src/worker/index.ts +216 -0
  159. package/src/worker/state-adapter.ts +589 -0
  160. package/src/worker/topological-executor.ts +625 -0
  161. package/src/worker/workflow-builder.ts +871 -0
  162. package/src/worker.ts +2906 -0
  163. package/src/workflow-builder.ts +1068 -0
  164. package/src/workflow.ts +199 -355
  165. package/test/barrier-join.test.ts +442 -0
  166. package/test/barrier-unhandled-rejections.test.ts +359 -0
  167. package/test/cascade-context.test.ts +390 -0
  168. package/test/cascade-executor.test.ts +852 -0
  169. package/test/cron-parser.test.ts +314 -0
  170. package/test/cron-scheduler.test.ts +291 -0
  171. package/test/database-context.test.ts +770 -0
  172. package/test/db-provider-adapter.test.ts +862 -0
  173. package/test/dependency-graph.test.ts +512 -0
  174. package/test/durable-execution-cloudflare.test.ts +606 -0
  175. package/test/durable-execution-in-process.test.ts +286 -0
  176. package/test/durable-execution.test.ts +247 -0
  177. package/test/e2e/workflow-scenarios.e2e.test.ts +1039 -0
  178. package/test/graph/topological-sort.test.ts +586 -0
  179. package/test/integration.test.ts +442 -0
  180. package/test/rpc-surface.test.ts +946 -0
  181. package/test/runtime.test.ts +262 -0
  182. package/test/schedule-timer-cleanup.test.ts +353 -0
  183. package/test/send-race-conditions.test.ts +400 -0
  184. package/test/type-safety-every.test.ts +303 -0
  185. package/test/worker/durable-cascade.test.ts +1117 -0
  186. package/test/worker/durable-step.test.ts +723 -0
  187. package/test/worker/topological-executor.test.ts +1240 -0
  188. package/test/worker/workflow-builder.test.ts +1067 -0
  189. package/test/worker.test.ts +608 -0
  190. package/test/workflow-builder.test.ts +1670 -0
  191. package/test/workflow-cron.test.ts +256 -0
  192. package/test/workflow-state-adapter.test.ts +923 -0
  193. package/test/workflow.test.ts +25 -22
  194. package/tsconfig.json +3 -1
  195. package/vitest.config.ts +38 -1
  196. package/vitest.workers.config.ts +44 -0
  197. package/wrangler.jsonc +22 -0
  198. package/.turbo/turbo-test.log +0 -7
  199. package/src/context.js +0 -83
  200. package/src/every.js +0 -267
  201. package/src/index.js +0 -71
  202. package/src/on.js +0 -79
  203. package/src/send.js +0 -111
  204. package/src/types.js +0 -4
  205. package/src/workflow.js +0 -455
  206. package/test/context.test.js +0 -116
  207. package/test/every.test.js +0 -282
  208. package/test/on.test.js +0 -80
  209. package/test/send.test.js +0 -89
  210. package/test/workflow.test.js +0 -224
  211. package/vitest.config.js +0 -7
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AASvC;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAsB;IAC1D,MAAM,aAAa,GAAkB;QACnC,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,EAAE;KACZ,CAAA;IAED,MAAM,UAAU,GAAG,CAAC,KAA8C,EAAE,EAAE;QACpE,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC;YACzB,GAAG,KAAK;YACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,yFAAyF;IACzF,MAAM,WAAW,GAAG,IAAI,KAAK,CAAC,EAAa,EAAE;QAC3C,GAAG;YACD,OAAO,IAAI,KAAK,CACd,EAAE,EACF;gBACE,GAAG;oBACD,OAAO,GAAG,EAAE,GAAE,CAAC,CAAA;gBACjB,CAAC;aACF,CACF,CAAA;QACH,CAAC;KACF,CAAC,CAAA;IAEF,4FAA4F;IAC5F,MAAM,cAAc,GAAG,IAAI,KAAK;IAC9B,6DAA6D;IAC7D,CAAC,CAAC,YAAoB,EAAE,QAAyB,EAAE,EAAE,GAAE,CAAC,CAAqB,EAC7E;QACE,GAAG;YACD,OAAO,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;QACvB,CAAC;QACD,KAAK,KAAI,CAAC;KACX,CACY,CAAA;IAEf,OAAO;QACL,KAAK,CAAC,KAAa,EAAE,IAAa;YAChC,mCAAmC;YACnC,IAAI,CAAC;gBACH,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;gBAC3D,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YAC5C,CAAC;YAAC,MAAM,CAAC;gBACP,0BAA0B;YAC5B,CAAC;QACH,CAAC;QAED,IAAI,CAAc,KAAa,EAAE,IAAO;YACtC,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAA;YACnC,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;YAChD,iEAAiE;YACjE,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,GAAI,IAAe,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBAC7E,SAAS,EAAE,CAAC,KAAK,CAAC,mCAAmC,KAAK,GAAG,EAAE,GAAG,CAAC,CAAA;YACrE,CAAC,CAAC,CAAA;YACF,OAAO,OAAO,CAAA;QAChB,CAAC;QAED,KAAK,CAAC,EAAE,CAAqC,MAAc,EAAE,KAAY;YACvE,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAA;QACvD,CAAC;QAED,KAAK,CAAC,GAAG,CAAqC,MAAc,EAAE,KAAY;YACxE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;QACxD,CAAC;QAED,EAAE,EAAE,WAAW;QACf,KAAK,EAAE,cAAc;QAErB,KAAK,EAAE,aAAa,CAAC,OAAO;QAE5B,QAAQ;YACN,yCAAyC;YACzC,OAAO;gBACL,GAAG,CAAC,aAAa,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,CAAC;gBAC9E,OAAO,EAAE,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE;gBACrC,OAAO,EAAE,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC;aACpC,CAAA;QACH,CAAC;QAED,GAAG,CAAc,GAAW,EAAE,KAAQ;YACpC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACpC,CAAC;QAED,GAAG,CAAc,GAAW;YAC1B,OAAO,aAAa,CAAC,OAAO,CAAC,GAAG,CAAkB,CAAA;QACpD,CAAC;QAED,GAAG,CAAC,OAAe,EAAE,IAAc;YACjC,UAAU,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAA;YACpE,SAAS,EAAE,CAAC,GAAG,CAAC,cAAc,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAA;QACtD,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB;IAGnC,MAAM,aAAa,GAA4C,EAAE,CAAA;IAEjE,MAAM,GAAG,GAAG,qBAAqB,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,KAAa,EAAE,IAAa;YACrC,aAAa,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrC,CAAC;KACF,CAAC,CAAA;IAEF,OAAO;QACL,GAAG,GAAG;QACN,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,aAAa,CAAC;KAC3C,CAAA;AACH,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Cron Expression Parser
3
+ *
4
+ * Parses standard 5-field cron expressions:
5
+ * minute hour day-of-month month day-of-week
6
+ *
7
+ * Also supports optional 6-field expressions with seconds:
8
+ * second minute hour day-of-month month day-of-week
9
+ *
10
+ * Supported syntax:
11
+ * - Numbers: 0, 5, 15
12
+ * - Ranges: 1-5, 9-17
13
+ * - Lists: 1,3,5, Mon,Wed,Fri
14
+ * - Steps: star/5, 0-30/5
15
+ * - Wildcards: star (asterisk)
16
+ * - Day names: Mon, Tue, Wed, Thu, Fri, Sat, Sun
17
+ * - Month names: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
18
+ */
19
+ /**
20
+ * Parsed cron expression
21
+ */
22
+ export interface ParsedCron {
23
+ /** Seconds (0-59) - optional, defaults to [0] */
24
+ seconds: number[];
25
+ /** Minutes (0-59) */
26
+ minutes: number[];
27
+ /** Hours (0-23) */
28
+ hours: number[];
29
+ /** Days of month (1-31) */
30
+ daysOfMonth: number[];
31
+ /** Months (1-12) */
32
+ months: number[];
33
+ /** Days of week (0-6, Sunday = 0) */
34
+ daysOfWeek: number[];
35
+ /** Whether day of month is a wildcard */
36
+ dayOfMonthWildcard: boolean;
37
+ /** Whether day of week is a wildcard */
38
+ dayOfWeekWildcard: boolean;
39
+ }
40
+ /**
41
+ * Parse a cron expression
42
+ *
43
+ * @param expression - Cron expression (5 or 6 fields)
44
+ * @returns ParsedCron object
45
+ * @throws Error if expression is invalid
46
+ */
47
+ export declare function parseCron(expression: string): ParsedCron;
48
+ /**
49
+ * Check if a date matches a parsed cron expression
50
+ */
51
+ export declare function matchesCron(date: Date, cron: ParsedCron): boolean;
52
+ /**
53
+ * Find the next date that matches a cron expression
54
+ *
55
+ * @param cron - Parsed cron expression
56
+ * @param from - Start date (defaults to now)
57
+ * @param maxIterations - Maximum iterations to prevent infinite loops
58
+ * @returns Next matching Date or null if not found within iterations
59
+ */
60
+ export declare function getNextCronDate(cron: ParsedCron, from?: Date, maxIterations?: number): Date | null;
61
+ /**
62
+ * Calculate milliseconds until the next cron occurrence
63
+ */
64
+ export declare function getNextCronMs(cron: ParsedCron, from?: Date): number | null;
65
+ //# sourceMappingURL=cron-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-parser.d.ts","sourceRoot":"","sources":["../src/cron-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,qBAAqB;IACrB,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,mBAAmB;IACnB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,2BAA2B;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,oBAAoB;IACpB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,qCAAqC;IACrC,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,yCAAyC;IACzC,kBAAkB,EAAE,OAAO,CAAA;IAC3B,wCAAwC;IACxC,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAwGD;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,CA4BxD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAkCjE;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,IAAiB,EACvB,aAAa,GAAE,MAAsB,GACpC,IAAI,GAAG,IAAI,CA8Fb;AAcD;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,GAAE,IAAiB,GAAG,MAAM,GAAG,IAAI,CAItF"}
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Cron Expression Parser
3
+ *
4
+ * Parses standard 5-field cron expressions:
5
+ * minute hour day-of-month month day-of-week
6
+ *
7
+ * Also supports optional 6-field expressions with seconds:
8
+ * second minute hour day-of-month month day-of-week
9
+ *
10
+ * Supported syntax:
11
+ * - Numbers: 0, 5, 15
12
+ * - Ranges: 1-5, 9-17
13
+ * - Lists: 1,3,5, Mon,Wed,Fri
14
+ * - Steps: star/5, 0-30/5
15
+ * - Wildcards: star (asterisk)
16
+ * - Day names: Mon, Tue, Wed, Thu, Fri, Sat, Sun
17
+ * - Month names: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
18
+ */
19
+ /**
20
+ * Day name to number mapping (Sunday = 0)
21
+ */
22
+ const DAY_NAMES = {
23
+ sun: 0,
24
+ mon: 1,
25
+ tue: 2,
26
+ wed: 3,
27
+ thu: 4,
28
+ fri: 5,
29
+ sat: 6,
30
+ };
31
+ /**
32
+ * Month name to number mapping (January = 1)
33
+ */
34
+ const MONTH_NAMES = {
35
+ jan: 1,
36
+ feb: 2,
37
+ mar: 3,
38
+ apr: 4,
39
+ may: 5,
40
+ jun: 6,
41
+ jul: 7,
42
+ aug: 8,
43
+ sep: 9,
44
+ oct: 10,
45
+ nov: 11,
46
+ dec: 12,
47
+ };
48
+ /**
49
+ * Parse a single cron field value
50
+ */
51
+ function parseFieldValue(value, min, max, names) {
52
+ // Check for named value (e.g., Mon, Jan)
53
+ if (names) {
54
+ const lower = value.toLowerCase();
55
+ if (lower in names) {
56
+ return names[lower];
57
+ }
58
+ }
59
+ const num = parseInt(value, 10);
60
+ if (isNaN(num) || num < min || num > max) {
61
+ throw new Error(`Invalid cron field value: ${value} (expected ${min}-${max})`);
62
+ }
63
+ return num;
64
+ }
65
+ /**
66
+ * Parse a single cron field
67
+ * Examples: "0", "*", "1-5", "* /15" (no space), "1,3,5"
68
+ */
69
+ function parseField(field, min, max, names) {
70
+ const values = new Set();
71
+ // Split by comma for lists
72
+ const parts = field.split(',');
73
+ for (const part of parts) {
74
+ // Check for step (e.g., */5 or 0-30/5)
75
+ const stepMatch = part.match(/^(.+)\/(\d+)$/);
76
+ const step = stepMatch ? parseInt(stepMatch[2], 10) : 1;
77
+ const range = stepMatch ? stepMatch[1] : part;
78
+ let start;
79
+ let end;
80
+ if (range === '*') {
81
+ start = min;
82
+ end = max;
83
+ }
84
+ else if (range.includes('-')) {
85
+ // Range (e.g., 1-5)
86
+ const [rangeStart, rangeEnd] = range.split('-');
87
+ start = parseFieldValue(rangeStart, min, max, names);
88
+ end = parseFieldValue(rangeEnd, min, max, names);
89
+ }
90
+ else {
91
+ // Single value
92
+ start = parseFieldValue(range, min, max, names);
93
+ end = start;
94
+ }
95
+ // Generate values with step
96
+ for (let i = start; i <= end; i += step) {
97
+ values.add(i);
98
+ }
99
+ }
100
+ return Array.from(values).sort((a, b) => a - b);
101
+ }
102
+ /**
103
+ * Parse a cron expression
104
+ *
105
+ * @param expression - Cron expression (5 or 6 fields)
106
+ * @returns ParsedCron object
107
+ * @throws Error if expression is invalid
108
+ */
109
+ export function parseCron(expression) {
110
+ const fields = expression.trim().split(/\s+/);
111
+ if (fields.length < 5 || fields.length > 6) {
112
+ throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${fields.length}`);
113
+ }
114
+ // Determine if we have seconds field
115
+ const hasSeconds = fields.length === 6;
116
+ const offset = hasSeconds ? 0 : -1;
117
+ const secondsField = hasSeconds ? fields[0] : '0';
118
+ const minutesField = fields[offset + 1];
119
+ const hoursField = fields[offset + 2];
120
+ const daysOfMonthField = fields[offset + 3];
121
+ const monthsField = fields[offset + 4];
122
+ const daysOfWeekField = fields[offset + 5];
123
+ return {
124
+ seconds: parseField(secondsField, 0, 59),
125
+ minutes: parseField(minutesField, 0, 59),
126
+ hours: parseField(hoursField, 0, 23),
127
+ daysOfMonth: parseField(daysOfMonthField, 1, 31),
128
+ months: parseField(monthsField, 1, 12, MONTH_NAMES),
129
+ daysOfWeek: parseField(daysOfWeekField, 0, 6, DAY_NAMES),
130
+ dayOfMonthWildcard: daysOfMonthField === '*',
131
+ dayOfWeekWildcard: daysOfWeekField === '*',
132
+ };
133
+ }
134
+ /**
135
+ * Check if a date matches a parsed cron expression
136
+ */
137
+ export function matchesCron(date, cron) {
138
+ const second = date.getSeconds();
139
+ const minute = date.getMinutes();
140
+ const hour = date.getHours();
141
+ const dayOfMonth = date.getDate();
142
+ const month = date.getMonth() + 1; // JavaScript months are 0-indexed
143
+ const dayOfWeek = date.getDay();
144
+ // Check basic fields
145
+ if (!cron.seconds.includes(second))
146
+ return false;
147
+ if (!cron.minutes.includes(minute))
148
+ return false;
149
+ if (!cron.hours.includes(hour))
150
+ return false;
151
+ if (!cron.months.includes(month))
152
+ return false;
153
+ // Handle day matching (special cron semantics)
154
+ // If both day-of-month and day-of-week are specified (not wildcards),
155
+ // either one matching is sufficient (OR logic)
156
+ // If only one is specified, that one must match
157
+ const domMatches = cron.daysOfMonth.includes(dayOfMonth);
158
+ const dowMatches = cron.daysOfWeek.includes(dayOfWeek);
159
+ if (cron.dayOfMonthWildcard && cron.dayOfWeekWildcard) {
160
+ // Both wildcards - any day matches
161
+ return true;
162
+ }
163
+ else if (cron.dayOfMonthWildcard) {
164
+ // Only day-of-week specified
165
+ return dowMatches;
166
+ }
167
+ else if (cron.dayOfWeekWildcard) {
168
+ // Only day-of-month specified
169
+ return domMatches;
170
+ }
171
+ else {
172
+ // Both specified - OR logic (standard cron behavior)
173
+ return domMatches || dowMatches;
174
+ }
175
+ }
176
+ /**
177
+ * Find the next date that matches a cron expression
178
+ *
179
+ * @param cron - Parsed cron expression
180
+ * @param from - Start date (defaults to now)
181
+ * @param maxIterations - Maximum iterations to prevent infinite loops
182
+ * @returns Next matching Date or null if not found within iterations
183
+ */
184
+ export function getNextCronDate(cron, from = new Date(), maxIterations = 366 * 24 * 60 // ~1 year of minutes
185
+ ) {
186
+ // Start from the next second
187
+ const next = new Date(from.getTime());
188
+ next.setMilliseconds(0);
189
+ next.setSeconds(next.getSeconds() + 1);
190
+ let iterations = 0;
191
+ while (iterations < maxIterations) {
192
+ iterations++;
193
+ // Check if current time matches
194
+ if (matchesCron(next, cron)) {
195
+ return next;
196
+ }
197
+ // Advance to next possible match
198
+ // Start by advancing the smallest unit that doesn't match
199
+ // Check seconds
200
+ if (!cron.seconds.includes(next.getSeconds())) {
201
+ const nextSecond = findNextValue(next.getSeconds(), cron.seconds);
202
+ if (nextSecond !== null) {
203
+ next.setSeconds(nextSecond);
204
+ }
205
+ else {
206
+ // Roll over to next minute
207
+ next.setSeconds(cron.seconds[0]);
208
+ next.setMinutes(next.getMinutes() + 1);
209
+ }
210
+ continue;
211
+ }
212
+ // Check minutes
213
+ if (!cron.minutes.includes(next.getMinutes())) {
214
+ const nextMinute = findNextValue(next.getMinutes(), cron.minutes);
215
+ if (nextMinute !== null) {
216
+ next.setMinutes(nextMinute);
217
+ next.setSeconds(cron.seconds[0]);
218
+ }
219
+ else {
220
+ // Roll over to next hour
221
+ next.setMinutes(cron.minutes[0]);
222
+ next.setSeconds(cron.seconds[0]);
223
+ next.setHours(next.getHours() + 1);
224
+ }
225
+ continue;
226
+ }
227
+ // Check hours
228
+ if (!cron.hours.includes(next.getHours())) {
229
+ const nextHour = findNextValue(next.getHours(), cron.hours);
230
+ if (nextHour !== null) {
231
+ next.setHours(nextHour);
232
+ next.setMinutes(cron.minutes[0]);
233
+ next.setSeconds(cron.seconds[0]);
234
+ }
235
+ else {
236
+ // Roll over to next day
237
+ next.setHours(cron.hours[0]);
238
+ next.setMinutes(cron.minutes[0]);
239
+ next.setSeconds(cron.seconds[0]);
240
+ next.setDate(next.getDate() + 1);
241
+ }
242
+ continue;
243
+ }
244
+ // Check month
245
+ if (!cron.months.includes(next.getMonth() + 1)) {
246
+ const nextMonth = findNextValue(next.getMonth() + 1, cron.months);
247
+ if (nextMonth !== null) {
248
+ next.setMonth(nextMonth - 1);
249
+ next.setDate(1);
250
+ next.setHours(cron.hours[0]);
251
+ next.setMinutes(cron.minutes[0]);
252
+ next.setSeconds(cron.seconds[0]);
253
+ }
254
+ else {
255
+ // Roll over to next year
256
+ next.setFullYear(next.getFullYear() + 1);
257
+ next.setMonth(cron.months[0] - 1);
258
+ next.setDate(1);
259
+ next.setHours(cron.hours[0]);
260
+ next.setMinutes(cron.minutes[0]);
261
+ next.setSeconds(cron.seconds[0]);
262
+ }
263
+ continue;
264
+ }
265
+ // Day checks are complex due to OR semantics
266
+ // Just advance by one day and re-check
267
+ next.setDate(next.getDate() + 1);
268
+ next.setHours(cron.hours[0]);
269
+ next.setMinutes(cron.minutes[0]);
270
+ next.setSeconds(cron.seconds[0]);
271
+ }
272
+ return null;
273
+ }
274
+ /**
275
+ * Find the next value in a sorted array that is greater than the current value
276
+ */
277
+ function findNextValue(current, values) {
278
+ for (const value of values) {
279
+ if (value > current) {
280
+ return value;
281
+ }
282
+ }
283
+ return null;
284
+ }
285
+ /**
286
+ * Calculate milliseconds until the next cron occurrence
287
+ */
288
+ export function getNextCronMs(cron, from = new Date()) {
289
+ const next = getNextCronDate(cron, from);
290
+ if (!next)
291
+ return null;
292
+ return next.getTime() - from.getTime();
293
+ }
294
+ //# sourceMappingURL=cron-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-parser.js","sourceRoot":"","sources":["../src/cron-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Cron Scheduler
3
+ *
4
+ * Provides scheduling functionality for cron expressions using accurate
5
+ * time-based scheduling rather than polling.
6
+ *
7
+ * Uses a self-adjusting timer approach:
8
+ * 1. Calculate time until next cron occurrence
9
+ * 2. Set a timeout for that duration
10
+ * 3. Execute handler and schedule next occurrence
11
+ *
12
+ * This is more accurate and efficient than setInterval polling.
13
+ */
14
+ import { type ParsedCron } from './cron-parser.js';
15
+ /**
16
+ * Scheduled job handle
17
+ */
18
+ export interface CronJob {
19
+ /** Unique job ID */
20
+ id: string;
21
+ /** Original cron expression */
22
+ expression: string;
23
+ /** Parsed cron data */
24
+ cron: ParsedCron;
25
+ /** Handler function */
26
+ handler: () => void | Promise<void>;
27
+ /** Current timer reference */
28
+ timer: NodeJS.Timeout | null;
29
+ /** Next scheduled run time */
30
+ nextRun: Date | null;
31
+ /** Whether the job is running */
32
+ running: boolean;
33
+ /** Whether the job is stopped */
34
+ stopped: boolean;
35
+ /** Error handler */
36
+ onError?: (error: Error) => void;
37
+ }
38
+ /**
39
+ * Create a cron job
40
+ *
41
+ * @param expression - Cron expression (5 or 6 fields)
42
+ * @param handler - Function to execute on each occurrence
43
+ * @param options - Optional configuration
44
+ * @returns CronJob handle for managing the job
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * // Run every hour at minute 0
49
+ * const job = createCronJob('0 * * * *', () => {
50
+ * console.log('Hourly task')
51
+ * })
52
+ *
53
+ * // Run Monday at 9am
54
+ * const monday9am = createCronJob('0 9 * * 1', async () => {
55
+ * await sendReport()
56
+ * })
57
+ *
58
+ * // Stop the job
59
+ * job.stop()
60
+ * ```
61
+ */
62
+ export declare function createCronJob(expression: string, handler: () => void | Promise<void>, options?: {
63
+ id?: string;
64
+ onError?: (error: Error) => void;
65
+ startImmediately?: boolean;
66
+ }): CronJob;
67
+ /**
68
+ * Stop a cron job
69
+ */
70
+ export declare function stopCronJob(job: CronJob): void;
71
+ /**
72
+ * Start a stopped cron job
73
+ */
74
+ export declare function startCronJob(job: CronJob): void;
75
+ /**
76
+ * Get all active cron jobs
77
+ */
78
+ export declare function getActiveCronJobs(): CronJob[];
79
+ /**
80
+ * Stop all active cron jobs
81
+ */
82
+ export declare function stopAllCronJobs(): void;
83
+ /**
84
+ * Get the count of active cron jobs
85
+ */
86
+ export declare function getActiveCronJobCount(): number;
87
+ /**
88
+ * Cron job registry object for external access
89
+ */
90
+ export declare const cronJobRegistry: {
91
+ create: typeof createCronJob;
92
+ stop: typeof stopCronJob;
93
+ start: typeof startCronJob;
94
+ getActive: typeof getActiveCronJobs;
95
+ getActiveCount: typeof getActiveCronJobCount;
96
+ stopAll: typeof stopAllCronJobs;
97
+ };
98
+ /**
99
+ * Schedule type for cron-based intervals
100
+ * Used to convert schedule intervals to cron jobs
101
+ */
102
+ export interface CronScheduleOptions {
103
+ /** Unique identifier for the schedule */
104
+ id?: string;
105
+ /** Error handler */
106
+ onError?: (error: Error) => void;
107
+ }
108
+ /**
109
+ * Create a schedule from a cron expression or well-known pattern
110
+ *
111
+ * @param expression - Cron expression or known pattern name
112
+ * @param handler - Function to execute
113
+ * @param options - Optional configuration
114
+ * @returns CronJob handle
115
+ */
116
+ export declare function schedule(expression: string, handler: () => void | Promise<void>, options?: CronScheduleOptions): CronJob;
117
+ //# sourceMappingURL=cron-scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-scheduler.d.ts","sourceRoot":"","sources":["../src/cron-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG9E;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,oBAAoB;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,uBAAuB;IACvB,IAAI,EAAE,UAAU,CAAA;IAChB,uBAAuB;IACvB,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnC,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;IAC5B,8BAA8B;IAC9B,OAAO,EAAE,IAAI,GAAG,IAAI,CAAA;IACpB,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAA;IAChB,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC;AAYD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACnC,OAAO,GAAE;IACP,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CACtB,GACL,OAAO,CAwBT;AA6CD;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAQ9C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAI/C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,EAAE,CAE7C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAItC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;CAO3B,CAAA;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,oBAAoB;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACnC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAMT"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Cron Scheduler
3
+ *
4
+ * Provides scheduling functionality for cron expressions using accurate
5
+ * time-based scheduling rather than polling.
6
+ *
7
+ * Uses a self-adjusting timer approach:
8
+ * 1. Calculate time until next cron occurrence
9
+ * 2. Set a timeout for that duration
10
+ * 3. Execute handler and schedule next occurrence
11
+ *
12
+ * This is more accurate and efficient than setInterval polling.
13
+ */
14
+ import { parseCron, getNextCronDate } from './cron-parser.js';
15
+ import { getLogger } from './logger.js';
16
+ /**
17
+ * Job counter for unique IDs
18
+ */
19
+ let jobCounter = 0;
20
+ /**
21
+ * Active cron jobs
22
+ */
23
+ const activeJobs = new Map();
24
+ /**
25
+ * Create a cron job
26
+ *
27
+ * @param expression - Cron expression (5 or 6 fields)
28
+ * @param handler - Function to execute on each occurrence
29
+ * @param options - Optional configuration
30
+ * @returns CronJob handle for managing the job
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * // Run every hour at minute 0
35
+ * const job = createCronJob('0 * * * *', () => {
36
+ * console.log('Hourly task')
37
+ * })
38
+ *
39
+ * // Run Monday at 9am
40
+ * const monday9am = createCronJob('0 9 * * 1', async () => {
41
+ * await sendReport()
42
+ * })
43
+ *
44
+ * // Stop the job
45
+ * job.stop()
46
+ * ```
47
+ */
48
+ export function createCronJob(expression, handler, options = {}) {
49
+ const cron = parseCron(expression);
50
+ const id = options.id ?? `cron-job-${++jobCounter}`;
51
+ const job = {
52
+ id,
53
+ expression,
54
+ cron,
55
+ handler,
56
+ timer: null,
57
+ nextRun: null,
58
+ running: false,
59
+ stopped: false,
60
+ ...(options.onError !== undefined && { onError: options.onError }),
61
+ };
62
+ activeJobs.set(id, job);
63
+ // Start immediately by default
64
+ if (options.startImmediately !== false) {
65
+ scheduleNext(job);
66
+ }
67
+ return job;
68
+ }
69
+ /**
70
+ * Schedule the next execution of a cron job
71
+ */
72
+ function scheduleNext(job) {
73
+ if (job.stopped)
74
+ return;
75
+ const now = new Date();
76
+ const nextRun = getNextCronDate(job.cron, now);
77
+ if (!nextRun) {
78
+ getLogger().warn(`[cron] Could not calculate next run for job ${job.id}`);
79
+ return;
80
+ }
81
+ job.nextRun = nextRun;
82
+ const delay = nextRun.getTime() - now.getTime();
83
+ // Clear any existing timer
84
+ if (job.timer) {
85
+ clearTimeout(job.timer);
86
+ }
87
+ // Schedule next execution
88
+ job.timer = setTimeout(async () => {
89
+ if (job.stopped)
90
+ return;
91
+ job.running = true;
92
+ try {
93
+ await job.handler();
94
+ }
95
+ catch (error) {
96
+ if (job.onError) {
97
+ job.onError(error instanceof Error ? error : new Error(String(error)));
98
+ }
99
+ else {
100
+ getLogger().error(`[cron] Error in job ${job.id}:`, error);
101
+ }
102
+ }
103
+ finally {
104
+ job.running = false;
105
+ // Schedule next occurrence
106
+ scheduleNext(job);
107
+ }
108
+ }, delay);
109
+ }
110
+ /**
111
+ * Stop a cron job
112
+ */
113
+ export function stopCronJob(job) {
114
+ job.stopped = true;
115
+ if (job.timer) {
116
+ clearTimeout(job.timer);
117
+ job.timer = null;
118
+ }
119
+ job.nextRun = null;
120
+ activeJobs.delete(job.id);
121
+ }
122
+ /**
123
+ * Start a stopped cron job
124
+ */
125
+ export function startCronJob(job) {
126
+ job.stopped = false;
127
+ scheduleNext(job);
128
+ activeJobs.set(job.id, job);
129
+ }
130
+ /**
131
+ * Get all active cron jobs
132
+ */
133
+ export function getActiveCronJobs() {
134
+ return Array.from(activeJobs.values());
135
+ }
136
+ /**
137
+ * Stop all active cron jobs
138
+ */
139
+ export function stopAllCronJobs() {
140
+ for (const job of activeJobs.values()) {
141
+ stopCronJob(job);
142
+ }
143
+ }
144
+ /**
145
+ * Get the count of active cron jobs
146
+ */
147
+ export function getActiveCronJobCount() {
148
+ return activeJobs.size;
149
+ }
150
+ /**
151
+ * Cron job registry object for external access
152
+ */
153
+ export const cronJobRegistry = {
154
+ create: createCronJob,
155
+ stop: stopCronJob,
156
+ start: startCronJob,
157
+ getActive: getActiveCronJobs,
158
+ getActiveCount: getActiveCronJobCount,
159
+ stopAll: stopAllCronJobs,
160
+ };
161
+ /**
162
+ * Create a schedule from a cron expression or well-known pattern
163
+ *
164
+ * @param expression - Cron expression or known pattern name
165
+ * @param handler - Function to execute
166
+ * @param options - Optional configuration
167
+ * @returns CronJob handle
168
+ */
169
+ export function schedule(expression, handler, options = {}) {
170
+ return createCronJob(expression, handler, {
171
+ ...(options.id !== undefined && { id: options.id }),
172
+ ...(options.onError !== undefined && { onError: options.onError }),
173
+ startImmediately: true,
174
+ });
175
+ }
176
+ //# sourceMappingURL=cron-scheduler.js.map