@monque/tsed 0.1.0 → 1.1.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.
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Collect job metadata utility
3
+ *
4
+ * Collects all job metadata from a class decorated with @JobController.
5
+ * Used by MonqueModule to discover and register all jobs.
6
+ */
7
+ import { Store } from '@tsed/core';
8
+
9
+ import { MONQUE } from '@/constants';
10
+ import type { CronDecoratorOptions, JobDecoratorOptions, JobStore } from '@/decorators';
11
+
12
+ import { buildJobName } from './build-job-name.js';
13
+
14
+ /**
15
+ * Collected job registration info ready for Monque.register()
16
+ */
17
+ export interface CollectedJobMetadata {
18
+ /**
19
+ * Full job name (with namespace prefix if applicable)
20
+ */
21
+ fullName: string;
22
+
23
+ /**
24
+ * Method name on the controller class
25
+ */
26
+ method: string;
27
+
28
+ /**
29
+ * Job options to pass to Monque.register()
30
+ */
31
+ opts: JobDecoratorOptions | CronDecoratorOptions;
32
+
33
+ /**
34
+ * Whether this is a cron job
35
+ */
36
+ isCron: boolean;
37
+
38
+ /**
39
+ * Cron pattern (only for cron jobs)
40
+ */
41
+ cronPattern?: string;
42
+ }
43
+
44
+ /**
45
+ * Collect all job metadata from a class.
46
+ *
47
+ * @param target - The class constructor (decorated with @JobController)
48
+ * @returns Array of collected job metadata ready for registration
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const metadata = collectJobMetadata(EmailJobs);
53
+ * // Returns:
54
+ * // [
55
+ * // { fullName: "email.send", method: "sendEmail", opts: {}, isCron: false },
56
+ * // { fullName: "email.daily-digest", method: "sendDailyDigest", opts: {}, isCron: true, cronPattern: "0 9 * * *" }
57
+ * // ]
58
+ * ```
59
+ */
60
+ export function collectJobMetadata(
61
+ target: new (...args: unknown[]) => unknown,
62
+ ): CollectedJobMetadata[] {
63
+ const store = Store.from(target);
64
+ const jobStore = store.get<JobStore>(MONQUE);
65
+
66
+ if (!jobStore) {
67
+ return [];
68
+ }
69
+
70
+ const results: CollectedJobMetadata[] = [];
71
+ const namespace = jobStore.namespace;
72
+
73
+ // Collect regular jobs
74
+ for (const job of jobStore.jobs) {
75
+ results.push({
76
+ fullName: buildJobName(namespace, job.name),
77
+ method: job.method,
78
+ opts: job.opts,
79
+ isCron: false,
80
+ });
81
+ }
82
+
83
+ // Collect cron jobs
84
+ for (const cron of jobStore.cronJobs) {
85
+ results.push({
86
+ fullName: buildJobName(namespace, cron.name),
87
+ method: cron.method,
88
+ opts: cron.opts,
89
+ isCron: true,
90
+ cronPattern: cron.pattern,
91
+ });
92
+ }
93
+
94
+ return results;
95
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Generate a unique token for a job controller.
3
+ *
4
+ * Used internally by Ts.ED DI to identify job controller providers.
5
+ * The token is based on the class name for debugging purposes.
6
+ *
7
+ * @param target - The class constructor
8
+ * @returns A Symbol token unique to this job controller
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * @JobController("email")
13
+ * class EmailJobs {}
14
+ *
15
+ * const token = getJobToken(EmailJobs);
16
+ * // Symbol("monque:job:EmailJobs")
17
+ * ```
18
+ */
19
+ import { MonqueError } from '@monque/core';
20
+
21
+ export function getJobToken(target: new (...args: unknown[]) => unknown): symbol {
22
+ const name = target.name?.trim();
23
+
24
+ if (!name) {
25
+ throw new MonqueError('Job class must have a non-empty name');
26
+ }
27
+
28
+ return Symbol.for(`monque:job:${name}`);
29
+ }
@@ -1,9 +1,9 @@
1
1
  export { buildJobName } from './build-job-name.js';
2
2
  export {
3
- type CollectedWorkerMetadata,
4
- collectWorkerMetadata,
5
- } from './collect-worker-metadata.js';
6
- export { getWorkerToken } from './get-worker-token.js';
3
+ type CollectedJobMetadata,
4
+ collectJobMetadata,
5
+ } from './collect-job-metadata.js';
6
+ export { getJobToken } from './get-job-token.js';
7
7
  export {
8
8
  isMongooseConnection,
9
9
  isMongooseService,
@@ -4,6 +4,7 @@
4
4
  * Multi-strategy database resolution for flexible MongoDB connection handling.
5
5
  */
6
6
 
7
+ import { ConnectionError } from '@monque/core';
7
8
  import type { TokenProvider } from '@tsed/di';
8
9
  import type { Db } from 'mongodb';
9
10
 
@@ -66,7 +67,7 @@ export async function resolveDatabase(
66
67
  // Strategy 3: DI token resolution
67
68
  if (config.dbToken) {
68
69
  if (!injectorFn) {
69
- throw new Error(
70
+ throw new ConnectionError(
70
71
  'MonqueTsedConfig.dbToken requires an injector function to resolve the database',
71
72
  );
72
73
  }
@@ -74,7 +75,7 @@ export async function resolveDatabase(
74
75
  const resolved = injectorFn(config.dbToken);
75
76
 
76
77
  if (!resolved) {
77
- throw new Error(
78
+ throw new ConnectionError(
78
79
  `Could not resolve database from token: ${String(config.dbToken)}. ` +
79
80
  'Make sure the provider is registered in the DI container.',
80
81
  );
@@ -87,7 +88,7 @@ export async function resolveDatabase(
87
88
  const connection = resolved.get(connectionId);
88
89
 
89
90
  if (!connection) {
90
- throw new Error(
91
+ throw new ConnectionError(
91
92
  `MongooseService resolved from token "${String(config.dbToken)}" returned no connection for ID "${connectionId}". ` +
92
93
  'Ensure the connection ID is correct and the connection is established.',
93
94
  );
@@ -106,7 +107,7 @@ export async function resolveDatabase(
106
107
 
107
108
  // Default: Assume it is a native Db instance
108
109
  if (typeof resolved !== 'object' || resolved === null || !('collection' in resolved)) {
109
- throw new Error(
110
+ throw new ConnectionError(
110
111
  `Resolved value from token "${String(config.dbToken)}" does not appear to be a valid MongoDB Db instance.`,
111
112
  );
112
113
  }
@@ -115,5 +116,5 @@ export async function resolveDatabase(
115
116
  }
116
117
 
117
118
  // No strategy provided
118
- throw new Error("MonqueTsedConfig requires 'db', 'dbFactory', or 'dbToken' to be set");
119
+ throw new ConnectionError("MonqueTsedConfig requires 'db', 'dbFactory', or 'dbToken' to be set");
119
120
  }
@@ -1,95 +0,0 @@
1
- /**
2
- * Collect worker metadata utility
3
- *
4
- * Collects all worker metadata from a class decorated with @WorkerController.
5
- * Used by MonqueModule to discover and register all workers.
6
- */
7
- import { Store } from '@tsed/core';
8
-
9
- import { MONQUE } from '@/constants';
10
- import type { CronDecoratorOptions, WorkerDecoratorOptions, WorkerStore } from '@/decorators';
11
-
12
- import { buildJobName } from './build-job-name.js';
13
-
14
- /**
15
- * Collected worker registration info ready for Monque.register()
16
- */
17
- export interface CollectedWorkerMetadata {
18
- /**
19
- * Full job name (with namespace prefix if applicable)
20
- */
21
- fullName: string;
22
-
23
- /**
24
- * Method name on the controller class
25
- */
26
- method: string;
27
-
28
- /**
29
- * Worker options to pass to Monque.register()
30
- */
31
- opts: WorkerDecoratorOptions | CronDecoratorOptions;
32
-
33
- /**
34
- * Whether this is a cron job
35
- */
36
- isCron: boolean;
37
-
38
- /**
39
- * Cron pattern (only for cron jobs)
40
- */
41
- cronPattern?: string;
42
- }
43
-
44
- /**
45
- * Collect all worker metadata from a class.
46
- *
47
- * @param target - The class constructor (decorated with @WorkerController)
48
- * @returns Array of collected worker metadata ready for registration
49
- *
50
- * @example
51
- * ```typescript
52
- * const metadata = collectWorkerMetadata(EmailWorkers);
53
- * // Returns:
54
- * // [
55
- * // { fullName: "email.send", method: "sendEmail", opts: {}, isCron: false },
56
- * // { fullName: "email.daily-digest", method: "sendDailyDigest", opts: {}, isCron: true, cronPattern: "0 9 * * *" }
57
- * // ]
58
- * ```
59
- */
60
- export function collectWorkerMetadata(
61
- target: new (...args: unknown[]) => unknown,
62
- ): CollectedWorkerMetadata[] {
63
- const store = Store.from(target);
64
- const workerStore = store.get<WorkerStore>(MONQUE);
65
-
66
- if (!workerStore) {
67
- return [];
68
- }
69
-
70
- const results: CollectedWorkerMetadata[] = [];
71
- const namespace = workerStore.namespace;
72
-
73
- // Collect regular workers
74
- for (const worker of workerStore.workers) {
75
- results.push({
76
- fullName: buildJobName(namespace, worker.name),
77
- method: worker.method,
78
- opts: worker.opts,
79
- isCron: false,
80
- });
81
- }
82
-
83
- // Collect cron jobs
84
- for (const cron of workerStore.cronJobs) {
85
- results.push({
86
- fullName: buildJobName(namespace, cron.name),
87
- method: cron.method,
88
- opts: cron.opts,
89
- isCron: true,
90
- cronPattern: cron.pattern,
91
- });
92
- }
93
-
94
- return results;
95
- }
@@ -1,27 +0,0 @@
1
- /**
2
- * Generate a unique token for a worker controller.
3
- *
4
- * Used internally by Ts.ED DI to identify worker controller providers.
5
- * The token is based on the class name for debugging purposes.
6
- *
7
- * @param target - The class constructor
8
- * @returns A Symbol token unique to this worker controller
9
- *
10
- * @example
11
- * ```typescript
12
- * @WorkerController("email")
13
- * class EmailWorkers {}
14
- *
15
- * const token = getWorkerToken(EmailWorkers);
16
- * // Symbol("monque:worker:EmailWorkers")
17
- * ```
18
- */
19
- export function getWorkerToken(target: new (...args: unknown[]) => unknown): symbol {
20
- const name = target.name?.trim();
21
-
22
- if (!name) {
23
- throw new Error('Worker class must have a non-empty name');
24
- }
25
-
26
- return Symbol.for(`monque:worker:${name}`);
27
- }