@quave/agenda 1.0.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 (216) hide show
  1. package/LICENSE.md +25 -0
  2. package/README.md +380 -0
  3. package/dist/Job.d.ts +190 -0
  4. package/dist/Job.js +689 -0
  5. package/dist/Job.js.map +1 -0
  6. package/dist/JobProcessingQueue.d.ts +47 -0
  7. package/dist/JobProcessingQueue.js +107 -0
  8. package/dist/JobProcessingQueue.js.map +1 -0
  9. package/dist/JobProcessor.d.ts +72 -0
  10. package/dist/JobProcessor.js +512 -0
  11. package/dist/JobProcessor.js.map +1 -0
  12. package/dist/backends/index.d.ts +18 -0
  13. package/dist/backends/index.js +20 -0
  14. package/dist/backends/index.js.map +1 -0
  15. package/dist/cjs/Job.d.ts +190 -0
  16. package/dist/cjs/Job.js +696 -0
  17. package/dist/cjs/Job.js.map +1 -0
  18. package/dist/cjs/JobProcessingQueue.d.ts +47 -0
  19. package/dist/cjs/JobProcessingQueue.js +111 -0
  20. package/dist/cjs/JobProcessingQueue.js.map +1 -0
  21. package/dist/cjs/JobProcessor.d.ts +72 -0
  22. package/dist/cjs/JobProcessor.js +519 -0
  23. package/dist/cjs/JobProcessor.js.map +1 -0
  24. package/dist/cjs/backends/index.d.ts +17 -0
  25. package/dist/cjs/backends/index.js +20 -0
  26. package/dist/cjs/backends/index.js.map +1 -0
  27. package/dist/cjs/decorators/Define.d.ts +33 -0
  28. package/dist/cjs/decorators/Define.js +47 -0
  29. package/dist/cjs/decorators/Define.js.map +1 -0
  30. package/dist/cjs/decorators/Every.d.ts +43 -0
  31. package/dist/cjs/decorators/Every.js +58 -0
  32. package/dist/cjs/decorators/Every.js.map +1 -0
  33. package/dist/cjs/decorators/JobsController.d.ts +43 -0
  34. package/dist/cjs/decorators/JobsController.js +40 -0
  35. package/dist/cjs/decorators/JobsController.js.map +1 -0
  36. package/dist/cjs/decorators/index.d.ts +41 -0
  37. package/dist/cjs/decorators/index.js +57 -0
  38. package/dist/cjs/decorators/index.js.map +1 -0
  39. package/dist/cjs/decorators/metadata.d.ts +50 -0
  40. package/dist/cjs/decorators/metadata.js +41 -0
  41. package/dist/cjs/decorators/metadata.js.map +1 -0
  42. package/dist/cjs/decorators/register.d.ts +52 -0
  43. package/dist/cjs/decorators/register.js +145 -0
  44. package/dist/cjs/decorators/register.js.map +1 -0
  45. package/dist/cjs/index.d.ts +498 -0
  46. package/dist/cjs/index.js +776 -0
  47. package/dist/cjs/index.js.map +1 -0
  48. package/dist/cjs/notifications/BaseNotificationChannel.d.ts +47 -0
  49. package/dist/cjs/notifications/BaseNotificationChannel.js +112 -0
  50. package/dist/cjs/notifications/BaseNotificationChannel.js.map +1 -0
  51. package/dist/cjs/notifications/InMemoryNotificationChannel.d.ts +13 -0
  52. package/dist/cjs/notifications/InMemoryNotificationChannel.js +37 -0
  53. package/dist/cjs/notifications/InMemoryNotificationChannel.js.map +1 -0
  54. package/dist/cjs/notifications/index.d.ts +2 -0
  55. package/dist/cjs/notifications/index.js +8 -0
  56. package/dist/cjs/notifications/index.js.map +1 -0
  57. package/dist/cjs/package.json +1 -0
  58. package/dist/cjs/types/AgendaBackend.d.ts +61 -0
  59. package/dist/cjs/types/AgendaBackend.js +3 -0
  60. package/dist/cjs/types/AgendaBackend.js.map +1 -0
  61. package/dist/cjs/types/AgendaConfig.d.ts +10 -0
  62. package/dist/cjs/types/AgendaConfig.js +3 -0
  63. package/dist/cjs/types/AgendaConfig.js.map +1 -0
  64. package/dist/cjs/types/AgendaStatus.d.ts +32 -0
  65. package/dist/cjs/types/AgendaStatus.js +3 -0
  66. package/dist/cjs/types/AgendaStatus.js.map +1 -0
  67. package/dist/cjs/types/DbOptions.d.ts +4 -0
  68. package/dist/cjs/types/DbOptions.js +3 -0
  69. package/dist/cjs/types/DbOptions.js.map +1 -0
  70. package/dist/cjs/types/DrainOptions.d.ts +37 -0
  71. package/dist/cjs/types/DrainOptions.js +3 -0
  72. package/dist/cjs/types/DrainOptions.js.map +1 -0
  73. package/dist/cjs/types/JobDefinition.d.ts +49 -0
  74. package/dist/cjs/types/JobDefinition.js +3 -0
  75. package/dist/cjs/types/JobDefinition.js.map +1 -0
  76. package/dist/cjs/types/JobLogger.d.ts +111 -0
  77. package/dist/cjs/types/JobLogger.js +3 -0
  78. package/dist/cjs/types/JobLogger.js.map +1 -0
  79. package/dist/cjs/types/JobParameters.d.ts +106 -0
  80. package/dist/cjs/types/JobParameters.js +21 -0
  81. package/dist/cjs/types/JobParameters.js.map +1 -0
  82. package/dist/cjs/types/JobQuery.d.ts +79 -0
  83. package/dist/cjs/types/JobQuery.js +36 -0
  84. package/dist/cjs/types/JobQuery.js.map +1 -0
  85. package/dist/cjs/types/JobRepository.d.ts +101 -0
  86. package/dist/cjs/types/JobRepository.js +3 -0
  87. package/dist/cjs/types/JobRepository.js.map +1 -0
  88. package/dist/cjs/types/NotificationChannel.d.ts +120 -0
  89. package/dist/cjs/types/NotificationChannel.js +3 -0
  90. package/dist/cjs/types/NotificationChannel.js.map +1 -0
  91. package/dist/cjs/utils/backoff.d.ts +152 -0
  92. package/dist/cjs/utils/backoff.js +175 -0
  93. package/dist/cjs/utils/backoff.js.map +1 -0
  94. package/dist/cjs/utils/dateConstraints.d.ts +48 -0
  95. package/dist/cjs/utils/dateConstraints.js +127 -0
  96. package/dist/cjs/utils/dateConstraints.js.map +1 -0
  97. package/dist/cjs/utils/isValidDate.d.ts +1 -0
  98. package/dist/cjs/utils/isValidDate.js +8 -0
  99. package/dist/cjs/utils/isValidDate.js.map +1 -0
  100. package/dist/cjs/utils/nextRunAt.d.ts +10 -0
  101. package/dist/cjs/utils/nextRunAt.js +119 -0
  102. package/dist/cjs/utils/nextRunAt.js.map +1 -0
  103. package/dist/cjs/utils/priority.d.ts +13 -0
  104. package/dist/cjs/utils/priority.js +23 -0
  105. package/dist/cjs/utils/priority.js.map +1 -0
  106. package/dist/cjs/utils/processEvery.d.ts +1 -0
  107. package/dist/cjs/utils/processEvery.js +13 -0
  108. package/dist/cjs/utils/processEvery.js.map +1 -0
  109. package/dist/cjs/utils/stack.d.ts +1 -0
  110. package/dist/cjs/utils/stack.js +21 -0
  111. package/dist/cjs/utils/stack.js.map +1 -0
  112. package/dist/cjs/version.d.ts +9 -0
  113. package/dist/cjs/version.js +13 -0
  114. package/dist/cjs/version.js.map +1 -0
  115. package/dist/decorators/Define.d.ts +33 -0
  116. package/dist/decorators/Define.js +44 -0
  117. package/dist/decorators/Define.js.map +1 -0
  118. package/dist/decorators/Every.d.ts +43 -0
  119. package/dist/decorators/Every.js +55 -0
  120. package/dist/decorators/Every.js.map +1 -0
  121. package/dist/decorators/JobsController.d.ts +43 -0
  122. package/dist/decorators/JobsController.js +37 -0
  123. package/dist/decorators/JobsController.js.map +1 -0
  124. package/dist/decorators/index.d.ts +41 -0
  125. package/dist/decorators/index.js +46 -0
  126. package/dist/decorators/index.js.map +1 -0
  127. package/dist/decorators/metadata.d.ts +50 -0
  128. package/dist/decorators/metadata.js +35 -0
  129. package/dist/decorators/metadata.js.map +1 -0
  130. package/dist/decorators/register.d.ts +52 -0
  131. package/dist/decorators/register.js +139 -0
  132. package/dist/decorators/register.js.map +1 -0
  133. package/dist/index.d.ts +498 -0
  134. package/dist/index.js +744 -0
  135. package/dist/index.js.map +1 -0
  136. package/dist/notifications/BaseNotificationChannel.d.ts +47 -0
  137. package/dist/notifications/BaseNotificationChannel.js +108 -0
  138. package/dist/notifications/BaseNotificationChannel.js.map +1 -0
  139. package/dist/notifications/InMemoryNotificationChannel.d.ts +13 -0
  140. package/dist/notifications/InMemoryNotificationChannel.js +33 -0
  141. package/dist/notifications/InMemoryNotificationChannel.js.map +1 -0
  142. package/dist/notifications/index.d.ts +2 -0
  143. package/dist/notifications/index.js +3 -0
  144. package/dist/notifications/index.js.map +1 -0
  145. package/dist/types/AgendaBackend.d.ts +61 -0
  146. package/dist/types/AgendaBackend.js +2 -0
  147. package/dist/types/AgendaBackend.js.map +1 -0
  148. package/dist/types/AgendaConfig.d.ts +10 -0
  149. package/dist/types/AgendaConfig.js +2 -0
  150. package/dist/types/AgendaConfig.js.map +1 -0
  151. package/dist/types/AgendaStatus.d.ts +32 -0
  152. package/dist/types/AgendaStatus.js +2 -0
  153. package/dist/types/AgendaStatus.js.map +1 -0
  154. package/dist/types/DbOptions.d.ts +4 -0
  155. package/dist/types/DbOptions.js +2 -0
  156. package/dist/types/DbOptions.js.map +1 -0
  157. package/dist/types/DrainOptions.d.ts +37 -0
  158. package/dist/types/DrainOptions.js +2 -0
  159. package/dist/types/DrainOptions.js.map +1 -0
  160. package/dist/types/JobDefinition.d.ts +49 -0
  161. package/dist/types/JobDefinition.js +2 -0
  162. package/dist/types/JobDefinition.js.map +1 -0
  163. package/dist/types/JobLogger.d.ts +111 -0
  164. package/dist/types/JobLogger.js +2 -0
  165. package/dist/types/JobLogger.js.map +1 -0
  166. package/dist/types/JobParameters.d.ts +106 -0
  167. package/dist/types/JobParameters.js +17 -0
  168. package/dist/types/JobParameters.js.map +1 -0
  169. package/dist/types/JobQuery.d.ts +79 -0
  170. package/dist/types/JobQuery.js +33 -0
  171. package/dist/types/JobQuery.js.map +1 -0
  172. package/dist/types/JobRepository.d.ts +101 -0
  173. package/dist/types/JobRepository.js +2 -0
  174. package/dist/types/JobRepository.js.map +1 -0
  175. package/dist/types/NotificationChannel.d.ts +120 -0
  176. package/dist/types/NotificationChannel.js +2 -0
  177. package/dist/types/NotificationChannel.js.map +1 -0
  178. package/dist/utils/backoff.d.ts +152 -0
  179. package/dist/utils/backoff.js +167 -0
  180. package/dist/utils/backoff.js.map +1 -0
  181. package/dist/utils/dateConstraints.d.ts +48 -0
  182. package/dist/utils/dateConstraints.js +117 -0
  183. package/dist/utils/dateConstraints.js.map +1 -0
  184. package/dist/utils/isValidDate.d.ts +1 -0
  185. package/dist/utils/isValidDate.js +5 -0
  186. package/dist/utils/isValidDate.js.map +1 -0
  187. package/dist/utils/nextRunAt.d.ts +10 -0
  188. package/dist/utils/nextRunAt.js +110 -0
  189. package/dist/utils/nextRunAt.js.map +1 -0
  190. package/dist/utils/priority.d.ts +13 -0
  191. package/dist/utils/priority.js +20 -0
  192. package/dist/utils/priority.js.map +1 -0
  193. package/dist/utils/processEvery.d.ts +1 -0
  194. package/dist/utils/processEvery.js +7 -0
  195. package/dist/utils/processEvery.js.map +1 -0
  196. package/dist/utils/stack.d.ts +1 -0
  197. package/dist/utils/stack.js +18 -0
  198. package/dist/utils/stack.js.map +1 -0
  199. package/dist/version.d.ts +9 -0
  200. package/dist/version.js +10 -0
  201. package/dist/version.js.map +1 -0
  202. package/package.json +79 -0
  203. package/test/fixtures/forkHelper.js +40 -0
  204. package/test/fixtures/someJobDefinition.ts +12 -0
  205. package/test/shared/agenda-test-suite.ts +1876 -0
  206. package/test/shared/backoff-test-suite.ts +408 -0
  207. package/test/shared/debounce-test-suite.ts +377 -0
  208. package/test/shared/full-test-suite.ts +161 -0
  209. package/test/shared/index.ts +50 -0
  210. package/test/shared/joblogger-test-suite.ts +305 -0
  211. package/test/shared/jobprocessor-test-suite.ts +266 -0
  212. package/test/shared/notification-channel-test-suite.ts +471 -0
  213. package/test/shared/removeoncomplete-test-suite.ts +228 -0
  214. package/test/shared/repository-test-suite.ts +708 -0
  215. package/test/shared/retry-test-suite.ts +174 -0
  216. package/test/shared/test-utils.ts +100 -0
@@ -0,0 +1,33 @@
1
+ import { type DefineOptions } from './metadata.js';
2
+ export type { DefineOptions };
3
+ /**
4
+ * Method decorator that defines a job handler.
5
+ *
6
+ * Jobs decorated with @Define must be scheduled programmatically using
7
+ * `agenda.now()`, `agenda.schedule()`, or `agenda.every()`.
8
+ *
9
+ * @param options - Configuration options for the job definition
10
+ * @returns Method decorator
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { JobsController, Define, Job } from 'agenda';
15
+ *
16
+ * @JobsController()
17
+ * class EmailJobs {
18
+ * @Define({
19
+ * name: 'sendWelcome',
20
+ * concurrency: 5,
21
+ * priority: 'high'
22
+ * })
23
+ * async sendWelcomeEmail(job: Job<{ userId: string; template: string }>) {
24
+ * const { userId, template } = job.attrs.data;
25
+ * await this.emailService.send(userId, template);
26
+ * }
27
+ * }
28
+ *
29
+ * // Later, schedule the job:
30
+ * await agenda.now('sendWelcome', { userId: '123', template: 'welcome' });
31
+ * ```
32
+ */
33
+ export declare function Define(options?: DefineOptions): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,44 @@
1
+ import { getOrCreateControllerMetadata } from './metadata.js';
2
+ /**
3
+ * Method decorator that defines a job handler.
4
+ *
5
+ * Jobs decorated with @Define must be scheduled programmatically using
6
+ * `agenda.now()`, `agenda.schedule()`, or `agenda.every()`.
7
+ *
8
+ * @param options - Configuration options for the job definition
9
+ * @returns Method decorator
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { JobsController, Define, Job } from 'agenda';
14
+ *
15
+ * @JobsController()
16
+ * class EmailJobs {
17
+ * @Define({
18
+ * name: 'sendWelcome',
19
+ * concurrency: 5,
20
+ * priority: 'high'
21
+ * })
22
+ * async sendWelcomeEmail(job: Job<{ userId: string; template: string }>) {
23
+ * const { userId, template } = job.attrs.data;
24
+ * await this.emailService.send(userId, template);
25
+ * }
26
+ * }
27
+ *
28
+ * // Later, schedule the job:
29
+ * await agenda.now('sendWelcome', { userId: '123', template: 'welcome' });
30
+ * ```
31
+ */
32
+ export function Define(options = {}) {
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Standard decorator signature requires any for target
34
+ return function (target, propertyKey, descriptor) {
35
+ const metadata = getOrCreateControllerMetadata(target.constructor);
36
+ metadata.jobs.set(propertyKey, {
37
+ type: 'define',
38
+ methodName: propertyKey,
39
+ options
40
+ });
41
+ return descriptor;
42
+ };
43
+ }
44
+ //# sourceMappingURL=Define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Define.js","sourceRoot":"","sources":["../../src/decorators/Define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAsB,MAAM,eAAe,CAAC;AAIlF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,MAAM,CAAC,UAAyB,EAAE;IACjD,sHAAsH;IACtH,OAAO,UAAU,MAAW,EAAE,WAAmB,EAAE,UAA8B;QAChF,MAAM,QAAQ,GAAG,6BAA6B,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEnE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;YAC9B,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,WAAW;YACvB,OAAO;SACP,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACnB,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { type EveryOptions } from './metadata.js';
2
+ export type { EveryOptions };
3
+ /**
4
+ * Method decorator that defines a recurring job.
5
+ *
6
+ * Jobs decorated with @Every are automatically scheduled when registered
7
+ * with the Agenda instance. They will run at the specified interval.
8
+ *
9
+ * @param interval - The interval at which the job should run.
10
+ * Can be a cron expression, human-readable string, or milliseconds.
11
+ * @param options - Configuration options for the job
12
+ * @returns Method decorator
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { JobsController, Every, Job } from 'agenda';
17
+ *
18
+ * @JobsController({ namespace: 'maintenance' })
19
+ * class MaintenanceJobs {
20
+ * // Run every 5 minutes
21
+ * @Every('5 minutes')
22
+ * async healthCheck(job: Job) {
23
+ * await this.checkSystemHealth();
24
+ * }
25
+ *
26
+ * // Run daily at midnight using cron
27
+ * @Every('0 0 * * *', {
28
+ * name: 'dailyCleanup',
29
+ * timezone: 'America/New_York'
30
+ * })
31
+ * async cleanupOldData(job: Job) {
32
+ * await this.deleteOldRecords();
33
+ * }
34
+ *
35
+ * // Run every hour with high priority
36
+ * @Every('1 hour', { priority: 'high', concurrency: 1 })
37
+ * async generateReport(job: Job) {
38
+ * await this.createHourlyReport();
39
+ * }
40
+ * }
41
+ * ```
42
+ */
43
+ export declare function Every(interval: string | number, options?: EveryOptions): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,55 @@
1
+ import { getOrCreateControllerMetadata } from './metadata.js';
2
+ /**
3
+ * Method decorator that defines a recurring job.
4
+ *
5
+ * Jobs decorated with @Every are automatically scheduled when registered
6
+ * with the Agenda instance. They will run at the specified interval.
7
+ *
8
+ * @param interval - The interval at which the job should run.
9
+ * Can be a cron expression, human-readable string, or milliseconds.
10
+ * @param options - Configuration options for the job
11
+ * @returns Method decorator
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { JobsController, Every, Job } from 'agenda';
16
+ *
17
+ * @JobsController({ namespace: 'maintenance' })
18
+ * class MaintenanceJobs {
19
+ * // Run every 5 minutes
20
+ * @Every('5 minutes')
21
+ * async healthCheck(job: Job) {
22
+ * await this.checkSystemHealth();
23
+ * }
24
+ *
25
+ * // Run daily at midnight using cron
26
+ * @Every('0 0 * * *', {
27
+ * name: 'dailyCleanup',
28
+ * timezone: 'America/New_York'
29
+ * })
30
+ * async cleanupOldData(job: Job) {
31
+ * await this.deleteOldRecords();
32
+ * }
33
+ *
34
+ * // Run every hour with high priority
35
+ * @Every('1 hour', { priority: 'high', concurrency: 1 })
36
+ * async generateReport(job: Job) {
37
+ * await this.createHourlyReport();
38
+ * }
39
+ * }
40
+ * ```
41
+ */
42
+ export function Every(interval, options = {}) {
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Standard decorator signature requires any for target
44
+ return function (target, propertyKey, descriptor) {
45
+ const metadata = getOrCreateControllerMetadata(target.constructor);
46
+ metadata.jobs.set(propertyKey, {
47
+ type: 'every',
48
+ methodName: propertyKey,
49
+ interval,
50
+ options
51
+ });
52
+ return descriptor;
53
+ };
54
+ }
55
+ //# sourceMappingURL=Every.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Every.js","sourceRoot":"","sources":["../../src/decorators/Every.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAqB,MAAM,eAAe,CAAC;AAIjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,KAAK,CAAC,QAAyB,EAAE,UAAwB,EAAE;IAC1E,sHAAsH;IACtH,OAAO,UAAU,MAAW,EAAE,WAAmB,EAAE,UAA8B;QAChF,MAAM,QAAQ,GAAG,6BAA6B,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAEnE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;YAC9B,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,WAAW;YACvB,QAAQ;YACR,OAAO;SACP,CAAC,CAAC;QAEH,OAAO,UAAU,CAAC;IACnB,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Options for the @JobsController decorator
3
+ */
4
+ export interface JobsControllerOptions {
5
+ /**
6
+ * Namespace prefix for all jobs in this class.
7
+ * Job names will be formatted as "namespace.jobName"
8
+ * @example
9
+ * ```typescript
10
+ * @JobsController({ namespace: 'email' })
11
+ * class EmailJobs {
12
+ * @Define()
13
+ * async sendWelcome(job: Job) {} // registered as "email.sendWelcome"
14
+ * }
15
+ * ```
16
+ */
17
+ namespace?: string;
18
+ }
19
+ /**
20
+ * Class decorator that marks a class as containing job handlers.
21
+ *
22
+ * @param options - Configuration options for the jobs controller
23
+ * @returns Class decorator
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { JobsController, Define, Every } from 'agenda';
28
+ *
29
+ * @JobsController({ namespace: 'notifications' })
30
+ * class NotificationJobs {
31
+ * @Define()
32
+ * async sendPush(job: Job<{ userId: string }>) {
33
+ * // Handle push notification
34
+ * }
35
+ *
36
+ * @Every('5 minutes')
37
+ * async checkPending(job: Job) {
38
+ * // Check for pending notifications
39
+ * }
40
+ * }
41
+ * ```
42
+ */
43
+ export declare function JobsController(options?: JobsControllerOptions): <T extends new (...args: any[]) => any>(target: T) => T;
@@ -0,0 +1,37 @@
1
+ import { getOrCreateControllerMetadata, setControllerMetadata } from './metadata.js';
2
+ /**
3
+ * Class decorator that marks a class as containing job handlers.
4
+ *
5
+ * @param options - Configuration options for the jobs controller
6
+ * @returns Class decorator
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { JobsController, Define, Every } from 'agenda';
11
+ *
12
+ * @JobsController({ namespace: 'notifications' })
13
+ * class NotificationJobs {
14
+ * @Define()
15
+ * async sendPush(job: Job<{ userId: string }>) {
16
+ * // Handle push notification
17
+ * }
18
+ *
19
+ * @Every('5 minutes')
20
+ * async checkPending(job: Job) {
21
+ * // Check for pending notifications
22
+ * }
23
+ * }
24
+ * ```
25
+ */
26
+ export function JobsController(options = {}) {
27
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Standard class decorator signature requires any
28
+ return function (target) {
29
+ const metadata = getOrCreateControllerMetadata(target);
30
+ setControllerMetadata(target, {
31
+ ...metadata,
32
+ namespace: options.namespace
33
+ });
34
+ return target;
35
+ };
36
+ }
37
+ //# sourceMappingURL=JobsController.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobsController.js","sourceRoot":"","sources":["../../src/decorators/JobsController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAqBrF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,cAAc,CAAC,UAAiC,EAAE;IACjE,iHAAiH;IACjH,OAAO,UAAiD,MAAS;QAChE,MAAM,QAAQ,GAAG,6BAA6B,CAAC,MAAM,CAAC,CAAC;QACvD,qBAAqB,CAAC,MAAM,EAAE;YAC7B,GAAG,QAAQ;YACX,SAAS,EAAE,OAAO,CAAC,SAAS;SAC5B,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IACf,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Agenda Decorators
3
+ *
4
+ * TypeScript decorators for defining job handlers in a declarative way.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { Agenda, JobsController, Define, Every, registerJobs, Job } from 'agenda';
9
+ * import { MongoBackend } from '@quave/agenda-mongodb';
10
+ *
11
+ * @JobsController({ namespace: 'email' })
12
+ * class EmailJobs {
13
+ * @Define({ concurrency: 5 })
14
+ * async sendWelcome(job: Job<{ userId: string }>) {
15
+ * // Send welcome email
16
+ * }
17
+ *
18
+ * @Every('1 hour')
19
+ * async cleanupBounced(job: Job) {
20
+ * // Cleanup bounced emails
21
+ * }
22
+ * }
23
+ *
24
+ * const agenda = new Agenda({
25
+ * backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
26
+ * });
27
+ *
28
+ * registerJobs(agenda, [new EmailJobs()]);
29
+ * await agenda.start();
30
+ *
31
+ * // Schedule a job
32
+ * await agenda.now('email.sendWelcome', { userId: '123' });
33
+ * ```
34
+ *
35
+ * @module decorators
36
+ */
37
+ export { JobsController, type JobsControllerOptions } from './JobsController.js';
38
+ export { Define, type DefineOptions } from './Define.js';
39
+ export { Every, type EveryOptions } from './Every.js';
40
+ export { registerJobs, getRegisteredJobsInfo, JobsRegistrationError } from './register.js';
41
+ export { getControllerMetadata, isJobsController, type ControllerMetadata, type JobMetadata, type ScheduleOptions } from './metadata.js';
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Agenda Decorators
3
+ *
4
+ * TypeScript decorators for defining job handlers in a declarative way.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { Agenda, JobsController, Define, Every, registerJobs, Job } from 'agenda';
9
+ * import { MongoBackend } from '@quave/agenda-mongodb';
10
+ *
11
+ * @JobsController({ namespace: 'email' })
12
+ * class EmailJobs {
13
+ * @Define({ concurrency: 5 })
14
+ * async sendWelcome(job: Job<{ userId: string }>) {
15
+ * // Send welcome email
16
+ * }
17
+ *
18
+ * @Every('1 hour')
19
+ * async cleanupBounced(job: Job) {
20
+ * // Cleanup bounced emails
21
+ * }
22
+ * }
23
+ *
24
+ * const agenda = new Agenda({
25
+ * backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
26
+ * });
27
+ *
28
+ * registerJobs(agenda, [new EmailJobs()]);
29
+ * await agenda.start();
30
+ *
31
+ * // Schedule a job
32
+ * await agenda.now('email.sendWelcome', { userId: '123' });
33
+ * ```
34
+ *
35
+ * @module decorators
36
+ */
37
+ // Class decorator
38
+ export { JobsController } from './JobsController.js';
39
+ // Method decorators
40
+ export { Define } from './Define.js';
41
+ export { Every } from './Every.js';
42
+ // Registration utilities
43
+ export { registerJobs, getRegisteredJobsInfo, JobsRegistrationError } from './register.js';
44
+ // Metadata utilities (for advanced use cases)
45
+ export { getControllerMetadata, isJobsController } from './metadata.js';
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAA8B,MAAM,qBAAqB,CAAC;AAEjF,oBAAoB;AACpB,OAAO,EAAE,MAAM,EAAsB,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,KAAK,EAAqB,MAAM,YAAY,CAAC;AAEtD,yBAAyB;AACzB,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE3F,8CAA8C;AAC9C,OAAO,EACN,qBAAqB,EACrB,gBAAgB,EAIhB,MAAM,eAAe,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { JobPriority } from '../utils/priority.js';
2
+ /**
3
+ * Metadata storage for job decorators
4
+ * Uses a WeakMap to avoid memory leaks and doesn't require reflect-metadata
5
+ */
6
+ export interface DefineOptions {
7
+ name?: string;
8
+ concurrency?: number;
9
+ lockLifetime?: number;
10
+ lockLimit?: number;
11
+ priority?: JobPriority;
12
+ }
13
+ export interface EveryOptions extends DefineOptions {
14
+ timezone?: string;
15
+ skipImmediate?: boolean;
16
+ }
17
+ export interface ScheduleOptions extends DefineOptions {
18
+ when?: string | Date;
19
+ }
20
+ export interface JobMetadata {
21
+ type: 'define' | 'every' | 'schedule';
22
+ methodName: string;
23
+ options: DefineOptions | EveryOptions | ScheduleOptions;
24
+ interval?: string | number;
25
+ }
26
+ export interface ControllerMetadata {
27
+ namespace?: string;
28
+ jobs: Map<string, JobMetadata>;
29
+ }
30
+ /**
31
+ * Type for class constructors used in decorator metadata
32
+ */
33
+ type Constructor = abstract new (...args: any[]) => any;
34
+ /**
35
+ * Get or create controller metadata for a class
36
+ */
37
+ export declare function getOrCreateControllerMetadata(target: Constructor): ControllerMetadata;
38
+ /**
39
+ * Get controller metadata for a class
40
+ */
41
+ export declare function getControllerMetadata(target: Constructor): ControllerMetadata | undefined;
42
+ /**
43
+ * Set controller metadata for a class
44
+ */
45
+ export declare function setControllerMetadata(target: Constructor, metadata: ControllerMetadata): void;
46
+ /**
47
+ * Check if a class is decorated with @JobsController
48
+ */
49
+ export declare function isJobsController(target: Constructor): boolean;
50
+ export {};
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Registry for storing job controller metadata
3
+ * Uses WeakMap to allow garbage collection of unused classes
4
+ */
5
+ const controllerRegistry = new WeakMap();
6
+ /**
7
+ * Get or create controller metadata for a class
8
+ */
9
+ export function getOrCreateControllerMetadata(target) {
10
+ let metadata = controllerRegistry.get(target);
11
+ if (!metadata) {
12
+ metadata = { jobs: new Map() };
13
+ controllerRegistry.set(target, metadata);
14
+ }
15
+ return metadata;
16
+ }
17
+ /**
18
+ * Get controller metadata for a class
19
+ */
20
+ export function getControllerMetadata(target) {
21
+ return controllerRegistry.get(target);
22
+ }
23
+ /**
24
+ * Set controller metadata for a class
25
+ */
26
+ export function setControllerMetadata(target, metadata) {
27
+ controllerRegistry.set(target, metadata);
28
+ }
29
+ /**
30
+ * Check if a class is decorated with @JobsController
31
+ */
32
+ export function isJobsController(target) {
33
+ return controllerRegistry.has(target);
34
+ }
35
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/decorators/metadata.ts"],"names":[],"mappings":"AA0CA;;;GAGG;AACH,MAAM,kBAAkB,GAAG,IAAI,OAAO,EAAmC,CAAC;AAE1E;;GAEG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAmB;IAChE,IAAI,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,QAAQ,GAAG,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;QAC/B,kBAAkB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAmB;IACxD,OAAO,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAmB,EAAE,QAA4B;IACtF,kBAAkB,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAmB;IACnD,OAAO,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { Agenda } from '../index.js';
2
+ import { type JobMetadata } from './metadata.js';
3
+ /**
4
+ * Error thrown when attempting to register an invalid jobs controller
5
+ */
6
+ export declare class JobsRegistrationError extends Error {
7
+ constructor(message: string);
8
+ }
9
+ /**
10
+ * Register job handlers from decorated class instances with an Agenda instance.
11
+ *
12
+ * This function reads the metadata from classes decorated with `@JobsController`
13
+ * and registers their methods as job handlers.
14
+ *
15
+ * @param agenda - The Agenda instance to register jobs with
16
+ * @param instances - Array of instantiated job controller classes
17
+ * @throws {JobsRegistrationError} If a class is not decorated with @JobsController
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { Agenda, registerJobs } from 'agenda';
22
+ * import { MongoBackend } from '@quave/agenda-mongodb';
23
+ * import { EmailJobs } from './jobs/email';
24
+ * import { ReportJobs } from './jobs/reports';
25
+ *
26
+ * const agenda = new Agenda({
27
+ * backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
28
+ * });
29
+ *
30
+ * // Create instances (can inject dependencies via constructor)
31
+ * const emailJobs = new EmailJobs(emailService);
32
+ * const reportJobs = new ReportJobs(reportService);
33
+ *
34
+ * // Register all job handlers
35
+ * registerJobs(agenda, [emailJobs, reportJobs]);
36
+ *
37
+ * await agenda.start();
38
+ * ```
39
+ */
40
+ export declare function registerJobs(agenda: Agenda, instances: object[]): void;
41
+ /**
42
+ * Get information about registered jobs from decorated classes.
43
+ * Useful for debugging and introspection.
44
+ *
45
+ * @param instances - Array of job controller instances
46
+ * @returns Array of job registration info
47
+ */
48
+ export declare function getRegisteredJobsInfo(instances: object[]): Array<{
49
+ className: string;
50
+ namespace?: string;
51
+ jobs: JobMetadata[];
52
+ }>;
@@ -0,0 +1,139 @@
1
+ import { getControllerMetadata, isJobsController } from './metadata.js';
2
+ /**
3
+ * Error thrown when attempting to register an invalid jobs controller
4
+ */
5
+ export class JobsRegistrationError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = 'JobsRegistrationError';
9
+ }
10
+ }
11
+ /**
12
+ * Register job handlers from decorated class instances with an Agenda instance.
13
+ *
14
+ * This function reads the metadata from classes decorated with `@JobsController`
15
+ * and registers their methods as job handlers.
16
+ *
17
+ * @param agenda - The Agenda instance to register jobs with
18
+ * @param instances - Array of instantiated job controller classes
19
+ * @throws {JobsRegistrationError} If a class is not decorated with @JobsController
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * import { Agenda, registerJobs } from 'agenda';
24
+ * import { MongoBackend } from '@quave/agenda-mongodb';
25
+ * import { EmailJobs } from './jobs/email';
26
+ * import { ReportJobs } from './jobs/reports';
27
+ *
28
+ * const agenda = new Agenda({
29
+ * backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
30
+ * });
31
+ *
32
+ * // Create instances (can inject dependencies via constructor)
33
+ * const emailJobs = new EmailJobs(emailService);
34
+ * const reportJobs = new ReportJobs(reportService);
35
+ *
36
+ * // Register all job handlers
37
+ * registerJobs(agenda, [emailJobs, reportJobs]);
38
+ *
39
+ * await agenda.start();
40
+ * ```
41
+ */
42
+ export function registerJobs(agenda, instances) {
43
+ const pendingEveryJobs = [];
44
+ for (const instance of instances) {
45
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- instance.constructor is typed as Function
46
+ const constructor = instance.constructor;
47
+ // Validate that the class is decorated
48
+ if (!isJobsController(constructor)) {
49
+ throw new JobsRegistrationError(`Class "${constructor.name}" is not decorated with @JobsController. ` +
50
+ 'Make sure to add @JobsController() decorator to your class.');
51
+ }
52
+ const metadata = getControllerMetadata(constructor);
53
+ if (!metadata) {
54
+ continue;
55
+ }
56
+ registerJobsFromMetadata(agenda, instance, metadata, pendingEveryJobs);
57
+ }
58
+ // Schedule @Every jobs after agenda starts
59
+ if (pendingEveryJobs.length > 0) {
60
+ scheduleEveryJobsOnReady(agenda, pendingEveryJobs);
61
+ }
62
+ }
63
+ /**
64
+ * Register jobs from a single controller's metadata
65
+ */
66
+ function registerJobsFromMetadata(agenda, instance, metadata, pendingEveryJobs) {
67
+ const namespace = metadata.namespace;
68
+ for (const [methodName, jobMeta] of metadata.jobs) {
69
+ const jobName = buildJobName(namespace, jobMeta.options.name || methodName);
70
+ // Bind the method to the instance
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Dynamic method access requires any
72
+ const handler = instance[methodName].bind(instance);
73
+ // Create an async wrapper that matches Agenda's expected signature
74
+ const wrappedHandler = async (job) => {
75
+ await handler(job);
76
+ };
77
+ // Register the job definition with Agenda
78
+ agenda.define(jobName, wrappedHandler, {
79
+ concurrency: jobMeta.options.concurrency,
80
+ lockLifetime: jobMeta.options.lockLifetime,
81
+ lockLimit: jobMeta.options.lockLimit,
82
+ priority: jobMeta.options.priority
83
+ });
84
+ // Queue @Every jobs for scheduling after start
85
+ if (jobMeta.type === 'every' && jobMeta.interval !== undefined) {
86
+ pendingEveryJobs.push({
87
+ jobName,
88
+ interval: jobMeta.interval,
89
+ options: jobMeta.options
90
+ });
91
+ }
92
+ }
93
+ }
94
+ /**
95
+ * Build the full job name with optional namespace prefix
96
+ */
97
+ function buildJobName(namespace, name) {
98
+ return namespace ? `${namespace}.${name}` : name;
99
+ }
100
+ /**
101
+ * Schedule @Every jobs when Agenda emits the 'ready' event
102
+ */
103
+ function scheduleEveryJobsOnReady(agenda, pendingJobs) {
104
+ const scheduleJobs = async () => {
105
+ for (const pending of pendingJobs) {
106
+ await agenda.every(pending.interval, pending.jobName, undefined, {
107
+ timezone: pending.options.timezone,
108
+ skipImmediate: pending.options.skipImmediate
109
+ });
110
+ }
111
+ };
112
+ // The ready promise settles once whether the backend already connected
113
+ // or connects later, unlike a 'ready' listener which misses past events.
114
+ agenda.ready
115
+ .then(() => scheduleJobs())
116
+ .catch(err => {
117
+ agenda.emit('error', err);
118
+ });
119
+ }
120
+ /**
121
+ * Get information about registered jobs from decorated classes.
122
+ * Useful for debugging and introspection.
123
+ *
124
+ * @param instances - Array of job controller instances
125
+ * @returns Array of job registration info
126
+ */
127
+ export function getRegisteredJobsInfo(instances) {
128
+ return instances.map(instance => {
129
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- instance.constructor is typed as Function
130
+ const constructor = instance.constructor;
131
+ const metadata = getControllerMetadata(constructor);
132
+ return {
133
+ className: constructor.name,
134
+ namespace: metadata?.namespace,
135
+ jobs: metadata ? Array.from(metadata.jobs.values()) : []
136
+ };
137
+ });
138
+ }
139
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../src/decorators/register.ts"],"names":[],"mappings":"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"}