@zintrust/core 0.1.15 → 0.1.16

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 (97) hide show
  1. package/package.json +1 -1
  2. package/src/cli/CLI.d.ts.map +1 -1
  3. package/src/cli/CLI.js +6 -0
  4. package/src/cli/commands/BroadcastWorkCommand.d.ts +10 -0
  5. package/src/cli/commands/BroadcastWorkCommand.d.ts.map +1 -0
  6. package/src/cli/commands/BroadcastWorkCommand.js +16 -0
  7. package/src/cli/commands/NotificationWorkCommand.d.ts +10 -0
  8. package/src/cli/commands/NotificationWorkCommand.d.ts.map +1 -0
  9. package/src/cli/commands/NotificationWorkCommand.js +16 -0
  10. package/src/cli/commands/QueueCommand.d.ts +10 -0
  11. package/src/cli/commands/QueueCommand.d.ts.map +1 -0
  12. package/src/cli/commands/QueueCommand.js +63 -0
  13. package/src/cli/commands/QueueWorkCommandUtils.d.ts +10 -0
  14. package/src/cli/commands/QueueWorkCommandUtils.d.ts.map +1 -0
  15. package/src/cli/commands/QueueWorkCommandUtils.js +43 -0
  16. package/src/cli/commands/createKindWorkCommand.d.ts +9 -0
  17. package/src/cli/commands/createKindWorkCommand.d.ts.map +1 -0
  18. package/src/cli/commands/createKindWorkCommand.js +33 -0
  19. package/src/cli/commands/index.d.ts +3 -0
  20. package/src/cli/commands/index.d.ts.map +1 -1
  21. package/src/cli/commands/index.js +3 -0
  22. package/src/cli/scaffolding/ModelGenerator.d.ts.map +1 -1
  23. package/src/cli/scaffolding/ModelGenerator.js +1 -0
  24. package/src/cli/workers/QueueWorkRunner.d.ts +23 -0
  25. package/src/cli/workers/QueueWorkRunner.d.ts.map +1 -0
  26. package/src/cli/workers/QueueWorkRunner.js +142 -0
  27. package/src/collections/Collection.d.ts +30 -0
  28. package/src/collections/Collection.d.ts.map +1 -0
  29. package/src/collections/Collection.js +146 -0
  30. package/src/collections/index.d.ts +3 -0
  31. package/src/collections/index.d.ts.map +1 -0
  32. package/src/collections/index.js +1 -0
  33. package/src/events/EventDispatcher.d.ts +16 -0
  34. package/src/events/EventDispatcher.d.ts.map +1 -0
  35. package/src/events/EventDispatcher.js +90 -0
  36. package/src/events/index.d.ts +3 -0
  37. package/src/events/index.d.ts.map +1 -0
  38. package/src/events/index.js +1 -0
  39. package/src/features/Queue.js +1 -1
  40. package/src/http/Response.d.ts +2 -2
  41. package/src/http/Response.d.ts.map +1 -1
  42. package/src/index.d.ts +11 -0
  43. package/src/index.d.ts.map +1 -1
  44. package/src/index.js +11 -0
  45. package/src/middleware/CsrfMiddleware.d.ts.map +1 -1
  46. package/src/middleware/CsrfMiddleware.js +20 -25
  47. package/src/middleware/SessionMiddleware.d.ts +8 -0
  48. package/src/middleware/SessionMiddleware.d.ts.map +1 -0
  49. package/src/middleware/SessionMiddleware.js +15 -0
  50. package/src/orm/Model.d.ts +15 -0
  51. package/src/orm/Model.d.ts.map +1 -1
  52. package/src/orm/Model.js +57 -8
  53. package/src/orm/QueryBuilder.d.ts +9 -1
  54. package/src/orm/QueryBuilder.d.ts.map +1 -1
  55. package/src/orm/QueryBuilder.js +54 -2
  56. package/src/scripts/TemplateSync.js +23 -1
  57. package/src/security/PasswordResetTokenBroker.d.ts +39 -0
  58. package/src/security/PasswordResetTokenBroker.d.ts.map +1 -0
  59. package/src/security/PasswordResetTokenBroker.js +131 -0
  60. package/src/session/SessionManager.d.ts +39 -0
  61. package/src/session/SessionManager.d.ts.map +1 -0
  62. package/src/session/SessionManager.js +149 -0
  63. package/src/session/index.d.ts +3 -0
  64. package/src/session/index.d.ts.map +1 -0
  65. package/src/session/index.js +1 -0
  66. package/src/templates/features/Queue.ts.tpl +4 -3
  67. package/src/templates/project/basic/config/FileLogWriter.ts.tpl +4 -3
  68. package/src/templates/project/basic/config/SecretsManager.ts.tpl +1 -1
  69. package/src/templates/project/basic/config/broadcast.ts.tpl +2 -2
  70. package/src/templates/project/basic/config/cache.ts.tpl +2 -2
  71. package/src/templates/project/basic/config/database.ts.tpl +2 -2
  72. package/src/templates/project/basic/config/features.ts.tpl +2 -2
  73. package/src/templates/project/basic/config/logger.ts.tpl +0 -2
  74. package/src/templates/project/basic/config/logging/HttpLogger.ts.tpl +1 -1
  75. package/src/templates/project/basic/config/logging/SlackLogger.ts.tpl +1 -1
  76. package/src/templates/project/basic/config/mail.ts.tpl +2 -2
  77. package/src/templates/project/basic/config/microservices.ts.tpl +1 -1
  78. package/src/templates/project/basic/config/middleware.ts.tpl +6 -9
  79. package/src/templates/project/basic/config/notification.ts.tpl +2 -2
  80. package/src/templates/project/basic/config/security.ts.tpl +1 -2
  81. package/src/templates/project/basic/config/storage.ts.tpl +2 -2
  82. package/src/templates/project/basic/config/type.ts.tpl +2 -2
  83. package/src/tools/broadcast/Broadcast.d.ts +8 -0
  84. package/src/tools/broadcast/Broadcast.d.ts.map +1 -1
  85. package/src/tools/broadcast/Broadcast.js +23 -0
  86. package/src/tools/notification/Notification.d.ts +10 -0
  87. package/src/tools/notification/Notification.d.ts.map +1 -1
  88. package/src/tools/notification/Notification.js +21 -0
  89. package/src/workers/BroadcastWorker.d.ts +22 -0
  90. package/src/workers/BroadcastWorker.d.ts.map +1 -0
  91. package/src/workers/BroadcastWorker.js +24 -0
  92. package/src/workers/NotificationWorker.d.ts +22 -0
  93. package/src/workers/NotificationWorker.d.ts.map +1 -0
  94. package/src/workers/NotificationWorker.js +23 -0
  95. package/src/workers/createQueueWorker.d.ts +24 -0
  96. package/src/workers/createQueueWorker.d.ts.map +1 -0
  97. package/src/workers/createQueueWorker.js +114 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1 @@
1
+ export { SessionManager } from './SessionManager.js';
@@ -1,6 +1,7 @@
1
1
  // TEMPLATE_START
2
2
 
3
- import { generateSecureJobId, Logger } from '@zintrust/core';
3
+ import { generateSecureJobId } from '@common/uuid';
4
+ import { Logger } from '@config/logger';
4
5
 
5
6
  export interface QueueJob {
6
7
  id: string;
@@ -19,7 +20,7 @@ export const Queue = Object.freeze({
19
20
  * Add a job to the queue
20
21
  */
21
22
  async add<T>(data: T): Promise<string> {
22
- const id = await generateSecureJobId();
23
+ const id = generateSecureJobId();
23
24
  const job: QueueJob = {
24
25
  id,
25
26
  data,
@@ -43,4 +44,4 @@ export const Queue = Object.freeze({
43
44
  },
44
45
  });
45
46
 
46
- // TEMPLATE_END
47
+ // TEMPLATE_END
@@ -1,14 +1,15 @@
1
1
  /**
2
2
  * FileLogWriter (Node.js only)
3
- * Re-exports core FileLogWriter for optional use
3
+ *
4
+ * Provides best-effort file logging with daily + size-based rotation.
5
+ * This module imports Node built-ins and should be loaded only in Node environments.
4
6
  */
5
7
 
6
8
  import { ensureDirSafe } from '@zintrust/core';
9
+ import { Env } from './env';
7
10
  import * as fs from 'node:fs';
8
11
  import * as path from 'node:path';
9
12
 
10
- import { Env } from './env';
11
-
12
13
  const getCwdSafe = (): string => {
13
14
  try {
14
15
  if (typeof process === 'undefined' || typeof process.cwd !== 'function') return '';
@@ -4,7 +4,7 @@
4
4
  * Supports: AWS Secrets Manager, Parameter Store, Cloudflare KV, Deno env
5
5
  */
6
6
 
7
- import { Logger } from '@zintrust/core';
7
+ import { Logger } from './logger';
8
8
  import type {
9
9
  GetSecretOptions,
10
10
  SecretConfig,
@@ -5,7 +5,7 @@
5
5
  * Driver selection must be dynamic (tests may mutate process.env).
6
6
  */
7
7
 
8
- import { Env } from '@config/env';
8
+ import { Env } from './env';
9
9
  import {
10
10
  BroadcastConfigInput,
11
11
  BroadcastDrivers,
@@ -14,7 +14,7 @@ import {
14
14
  PusherBroadcastDriverConfig,
15
15
  RedisBroadcastDriverConfig,
16
16
  RedisHttpsBroadcastDriverConfig,
17
- } from '@config/type';
17
+ } from './type';
18
18
  import { ErrorFactory } from '@zintrust/core';
19
19
 
20
20
  const normalizeDriverName = (value: string): string => value.trim().toLowerCase();
@@ -4,8 +4,8 @@
4
4
  * Sealed namespace for immutability
5
5
  */
6
6
 
7
- import { Env } from '@config/env';
8
- import { CacheConfigInput, CacheDriverConfig } from '@config/type';
7
+ import { Env } from './env';
8
+ import { CacheConfigInput, CacheDriverConfig } from './type';
9
9
  import { ErrorFactory } from '@zintrust/core';
10
10
 
11
11
  const getCacheDriver = (config: CacheConfigInput, name?: string): CacheDriverConfig => {
@@ -4,8 +4,8 @@
4
4
  * Sealed namespace for immutability
5
5
  */
6
6
 
7
- import { Env } from '@config/env';
8
- import { DatabaseConfigShape, DatabaseConnectionConfig, DatabaseConnections } from '@config/type';
7
+ import { Env } from './env';
8
+ import { DatabaseConfigShape, DatabaseConnectionConfig, DatabaseConnections } from './type';
9
9
  import { ErrorFactory } from '@zintrust/core';
10
10
 
11
11
  const hasOwn = (obj: Record<string, unknown>, key: string): boolean => {
@@ -1,5 +1,5 @@
1
- import { Env } from '@zintrust/core';
2
- import { Logger } from '@zintrust/core';
1
+ import { Env } from './env';
2
+ import { Logger } from './logger';
3
3
 
4
4
  /**
5
5
  * Feature Flags State
@@ -3,8 +3,6 @@
3
3
  * Sealed namespace pattern - all exports through Logger namespace
4
4
  * Replaces console.* calls throughout the codebase
5
5
  */
6
- import { Logger } from '@zintrust/core';
7
-
8
6
  import { appConfig } from './app';
9
7
  import { Env } from './env';
10
8
 
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { delay } from '@zintrust/core';
13
- import { Env } from '@zintrust/core';
13
+ import { Env } from '../env';
14
14
  import { ErrorFactory } from '@zintrust/core';
15
15
  import { HttpClient } from '@zintrust/core';
16
16
 
@@ -9,7 +9,7 @@
9
9
  * - SLACK_LOG_BATCH_WINDOW_MS (default: 5000)
10
10
  */
11
11
 
12
- import { Env } from '@zintrust/core';
12
+ import { Env } from '../env';
13
13
  import { ErrorFactory } from '@zintrust/core';
14
14
  import { HttpClient } from '@zintrust/core';
15
15
 
@@ -4,8 +4,8 @@
4
4
  * Sealed namespace for immutability
5
5
  */
6
6
 
7
- import { Env } from '@config/env';
8
- import type { MailConfigInput, MailDriverConfig } from '@config/type';
7
+ import { Env } from './env';
8
+ import type { MailConfigInput, MailDriverConfig } from './type';
9
9
  import { ErrorFactory } from '@zintrust/core';
10
10
 
11
11
  const isMailDriverConfig = (value: unknown): value is MailDriverConfig => {
@@ -4,7 +4,7 @@
4
4
  * Sealed namespace for immutability
5
5
  */
6
6
 
7
- import { Env } from '@zintrust/core';
7
+ import { Env } from './env';
8
8
 
9
9
  const microservicesConfigObj = {
10
10
  /**
@@ -1,13 +1,10 @@
1
- import {
2
- CsrfMiddleware,
3
- ErrorHandlerMiddleware,
4
- LoggingMiddleware,
5
- RateLimiter,
6
- SecurityMiddleware,
7
- type Middleware,
8
- } from '@zintrust/core';
9
-
10
1
  import { MiddlewareConfigType } from './type';
2
+ import { CsrfMiddleware } from '@zintrust/core';
3
+ import { ErrorHandlerMiddleware } from '@zintrust/core';
4
+ import { LoggingMiddleware } from '@zintrust/core';
5
+ import type { Middleware } from '@zintrust/core';
6
+ import { RateLimiter } from '@zintrust/core';
7
+ import { SecurityMiddleware } from '@zintrust/core';
11
8
 
12
9
  const shared = Object.freeze({
13
10
  log: LoggingMiddleware.create(),
@@ -5,13 +5,13 @@
5
5
  * Driver selection must be dynamic (tests may mutate process.env).
6
6
  */
7
7
 
8
- import { Env } from '@config/env';
8
+ import { Env } from './env';
9
9
  import type {
10
10
  KnownNotificationDriverConfig,
11
11
  NotificationConfigInput,
12
12
  NotificationDrivers,
13
13
  NotificationProviders,
14
- } from '@config/type';
14
+ } from './type';
15
15
  import { ErrorFactory } from '@zintrust/core';
16
16
 
17
17
  const normalizeName = (value: string): string => value.trim().toLowerCase();
@@ -16,10 +16,9 @@
16
16
  * security domains (e.g., different keys for different microservices).
17
17
  */
18
18
 
19
- import { Logger } from '@zintrust/core';
20
-
21
19
  import { appConfig } from './app';
22
20
  import { Env } from './env';
21
+ import { Logger } from './logger';
23
22
  import { ErrorFactory } from '@zintrust/core';
24
23
 
25
24
  /**
@@ -4,8 +4,8 @@
4
4
  * Sealed namespace for immutability
5
5
  */
6
6
 
7
- import { Env } from '@config/env';
8
- import type { StorageConfigRuntime, StorageDriverConfig, StorageDrivers } from '@config/type';
7
+ import { Env } from './env';
8
+ import type { StorageConfigRuntime, StorageDriverConfig, StorageDrivers } from './type';
9
9
  import { ErrorFactory } from '@zintrust/core';
10
10
 
11
11
  const hasOwn = <T extends object>(obj: T, key: PropertyKey): key is keyof T => {
@@ -1,5 +1,5 @@
1
- import { Env } from '@config/env';
2
- import type { Middleware as MiddlewareFn } from '@middleware/MiddlewareStack';
1
+ import { Env } from './env';
2
+ import type { Middleware as MiddlewareFn } from '@zintrust/core';
3
3
 
4
4
  export type Environment =
5
5
  | 'development'
@@ -3,6 +3,14 @@ type Broadcaster = Readonly<{
3
3
  }>;
4
4
  export declare const Broadcast: Readonly<{
5
5
  send(channel: string, event: string, data: unknown): Promise<unknown>;
6
+ broadcastNow(channel: string, event: string, data: unknown): Promise<unknown>;
7
+ BroadcastLater(channel: string, event: string, data: unknown, options?: {
8
+ queueName?: string;
9
+ timestamp?: number;
10
+ }): Promise<string>;
11
+ queue(queueName: string): Readonly<{
12
+ BroadcastLater: (channel: string, event: string, data: unknown, options?: {}) => Promise<string>;
13
+ }>;
6
14
  broadcaster(name?: string): Broadcaster;
7
15
  }>;
8
16
  export default Broadcast;
@@ -1 +1 @@
1
- {"version":3,"file":"Broadcast.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/Broadcast.ts"],"names":[],"mappings":"AAQA,KAAK,WAAW,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3E,CAAC,CAAC;AAyDH,eAAO,MAAM,SAAS;kBACA,MAAM,SAAS,MAAM,QAAQ,OAAO;uBAKrC,MAAM,GAAG,WAAW;EAQvC,CAAC;AAEH,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"Broadcast.d.ts","sourceRoot":"","sources":["../../../../src/tools/broadcast/Broadcast.ts"],"names":[],"mappings":"AAQA,KAAK,WAAW,GAAG,QAAQ,CAAC;IAC1B,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3E,CAAC,CAAC;AAyDH,eAAO,MAAM,SAAS;kBACA,MAAM,SAAS,MAAM,QAAQ,OAAO;0BAM5B,MAAM,SAAS,MAAM,QAAQ,OAAO;4BAMrD,MAAM,SACR,MAAM,QACP,OAAO,YACJ;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE;qBAepC,MAAM;kCAEa,MAAM,SAAS,MAAM,QAAQ,OAAO;;uBAKrD,MAAM,GAAG,WAAW;EAQvC,CAAC;AAEH,eAAe,SAAS,CAAC"}
@@ -49,6 +49,29 @@ export const Broadcast = Object.freeze({
49
49
  const config = await resolveBroadcasterConfig();
50
50
  return sendWithConfig(config, channel, event, data);
51
51
  },
52
+ // Alias for send() - explicit intent for immediate broadcast
53
+ async broadcastNow(channel, event, data) {
54
+ return this.send(channel, event, data);
55
+ },
56
+ // Queue broadcast for async processing
57
+ async BroadcastLater(channel, event, data, options = {}) {
58
+ const { queueName = 'broadcasts', timestamp = Date.now() } = options;
59
+ const { Queue } = await import('../queue/Queue.js');
60
+ const messageId = await Queue.enqueue(queueName, {
61
+ type: 'broadcast',
62
+ channel,
63
+ event,
64
+ data,
65
+ timestamp,
66
+ attempts: 0,
67
+ });
68
+ return messageId;
69
+ },
70
+ queue(queueName) {
71
+ return Object.freeze({
72
+ BroadcastLater: async (channel, event, data, options = {}) => Broadcast.BroadcastLater(channel, event, data, { ...options, queueName }),
73
+ });
74
+ },
52
75
  broadcaster(name) {
53
76
  return Object.freeze({
54
77
  send: async (channel, event, data) => {
@@ -5,6 +5,16 @@
5
5
  */
6
6
  export declare const Notification: Readonly<{
7
7
  send: (recipient: string, message: string, options?: Record<string, unknown>) => Promise<unknown>;
8
+ NotifyNow: (recipient: string, message: string, options?: Record<string, unknown>) => Promise<unknown>;
9
+ NotifyLater(recipient: string, message: string, notifyOptions?: Record<string, unknown>, queueOptions?: {
10
+ queueName?: string;
11
+ timestamp?: number;
12
+ }): Promise<string>;
13
+ queue(queueName: string): Readonly<{
14
+ NotifyLater: (recipient: string, message: string, notifyOptions?: Record<string, unknown>, queueOptions?: {
15
+ timestamp?: number;
16
+ }) => Promise<string>;
17
+ }>;
8
18
  channel: (name: string) => Readonly<{
9
19
  send: (recipient: string, message: string, options?: Record<string, unknown>) => Promise<unknown>;
10
20
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"Notification.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Notification.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,eAAO,MAAM,YAAY;;oBAEP,MAAM;0BAEM,MAAM,WAAW,MAAM,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;EAItF,CAAC;AAEH,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"Notification.d.ts","sourceRoot":"","sources":["../../../../src/tools/notification/Notification.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,eAAO,MAAM,YAAY;;;2BAQV,MAAM,WACR,MAAM,kBACA,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACxB;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GACvD,OAAO,CAAC,MAAM,CAAC;qBAcD,MAAM;iCAGN,MAAM,WACR,MAAM,kBACA,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,iBACxB;YAAE,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE;;oBAM1B,MAAM;0BAEM,MAAM,WAAW,MAAM,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;EAItF,CAAC;AAEH,eAAe,YAAY,CAAC"}
@@ -6,6 +6,27 @@
6
6
  import { NotificationService } from './Service.js';
7
7
  export const Notification = Object.freeze({
8
8
  send: NotificationService.send,
9
+ // Alias for send() - explicit intent for immediate notification
10
+ NotifyNow: NotificationService.send,
11
+ // Queue notification for async processing
12
+ async NotifyLater(recipient, message, notifyOptions = {}, queueOptions = {}) {
13
+ const { queueName = 'notifications', timestamp = Date.now() } = queueOptions;
14
+ const { Queue } = await import('../queue/Queue.js');
15
+ const messageId = await Queue.enqueue(queueName, {
16
+ type: 'notification',
17
+ recipient,
18
+ message,
19
+ options: notifyOptions,
20
+ timestamp,
21
+ attempts: 0,
22
+ });
23
+ return messageId;
24
+ },
25
+ queue(queueName) {
26
+ return Object.freeze({
27
+ NotifyLater: async (recipient, message, notifyOptions = {}, queueOptions = {}) => Notification.NotifyLater(recipient, message, notifyOptions, { ...queueOptions, queueName }),
28
+ });
29
+ },
9
30
  channel: (name) => Object.freeze({
10
31
  send: async (recipient, message, options) => NotificationService.sendVia(name, recipient, message, options),
11
32
  }),
@@ -0,0 +1,22 @@
1
+ /**
2
+ * BroadcastWorker - Processes queued broadcasts
3
+ *
4
+ * This worker dequeues broadcast messages and sends them using the Broadcast service.
5
+ * Use with Queue.dequeue() in a background process or cron job.
6
+ */
7
+ export declare const BroadcastWorker: Readonly<{
8
+ processOne: (queueName?: string, driverName?: string) => Promise<boolean>;
9
+ processAll: (queueName?: string, driverName?: string) => Promise<number>;
10
+ runOnce: (opts?: {
11
+ queueName?: string;
12
+ driverName?: string;
13
+ maxItems?: number;
14
+ }) => Promise<number>;
15
+ startWorker: (opts?: {
16
+ queueName?: string;
17
+ driverName?: string;
18
+ signal?: AbortSignal;
19
+ }) => Promise<number>;
20
+ }>;
21
+ export default BroadcastWorker;
22
+ //# sourceMappingURL=BroadcastWorker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BroadcastWorker.d.ts","sourceRoot":"","sources":["../../../src/workers/BroadcastWorker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,eAAO,MAAM,eAAe;0BAbrB,CAAC,oBAAoB,CAAC;0BAGf,CAAC,oBAAoB,CAAC;kBACnB,CAAC;iBAAiB,CAAC;kBAE3B,CAAC;gBACC,CAAA;;sBAGE,CAAC;iBAGP,CAAA;kBAAwB,CAAC;cAC3B,CAAC;;EAaJ,CAAC;AAEH,eAAe,eAAe,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * BroadcastWorker - Processes queued broadcasts
3
+ *
4
+ * This worker dequeues broadcast messages and sends them using the Broadcast service.
5
+ * Use with Queue.dequeue() in a background process or cron job.
6
+ */
7
+ import { createQueueWorker } from '../workers/createQueueWorker.js';
8
+ import { Broadcast } from '../tools/broadcast/Broadcast.js';
9
+ export const BroadcastWorker = Object.freeze({
10
+ ...createQueueWorker({
11
+ kindLabel: 'broadcast',
12
+ defaultQueueName: 'broadcasts',
13
+ maxAttempts: 3,
14
+ getLogFields: (payload) => ({
15
+ channel: payload.channel,
16
+ event: payload.event,
17
+ queuedAt: payload.timestamp,
18
+ }),
19
+ handle: async (payload) => {
20
+ await Broadcast.send(payload.channel, payload.event, payload.data);
21
+ },
22
+ }),
23
+ });
24
+ export default BroadcastWorker;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * NotificationWorker - Processes queued notifications
3
+ *
4
+ * This worker dequeues notification messages and sends them using the Notification service.
5
+ * Use with Queue.dequeue() in a background process or cron job.
6
+ */
7
+ export declare const NotificationWorker: Readonly<{
8
+ processOne: (queueName?: string, driverName?: string) => Promise<boolean>;
9
+ processAll: (queueName?: string, driverName?: string) => Promise<number>;
10
+ runOnce: (opts?: {
11
+ queueName?: string;
12
+ driverName?: string;
13
+ maxItems?: number;
14
+ }) => Promise<number>;
15
+ startWorker: (opts?: {
16
+ queueName?: string;
17
+ driverName?: string;
18
+ signal?: AbortSignal;
19
+ }) => Promise<number>;
20
+ }>;
21
+ export default NotificationWorker;
22
+ //# sourceMappingURL=NotificationWorker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NotificationWorker.d.ts","sourceRoot":"","sources":["../../../src/workers/NotificationWorker.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,eAAO,MAAM,kBAAkB;0BAdyD,CAAC,oBACzE,CAAC;0BAGf,CAAC,oBAAoB,CAAC;kBACnB,CAAC;iBAAkB,CAAA;kBAAwB,CAAC;gBAEtC,CAAC;;sBAGV,CAAC;iBAAiB,CAAC;kBACZ,CAAC;cAGL,CAAC;;EAaJ,CAAC;AAEH,eAAe,kBAAkB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * NotificationWorker - Processes queued notifications
3
+ *
4
+ * This worker dequeues notification messages and sends them using the Notification service.
5
+ * Use with Queue.dequeue() in a background process or cron job.
6
+ */
7
+ import { createQueueWorker } from '../workers/createQueueWorker.js';
8
+ import { Notification } from '../tools/notification/Notification.js';
9
+ export const NotificationWorker = Object.freeze({
10
+ ...createQueueWorker({
11
+ kindLabel: 'notification',
12
+ defaultQueueName: 'notifications',
13
+ maxAttempts: 3,
14
+ getLogFields: (payload) => ({
15
+ recipient: payload.recipient,
16
+ queuedAt: payload.timestamp,
17
+ }),
18
+ handle: async (payload) => {
19
+ await Notification.send(payload.recipient, payload.message, payload.options);
20
+ },
21
+ }),
22
+ });
23
+ export default NotificationWorker;
@@ -0,0 +1,24 @@
1
+ type QueueWorker = {
2
+ processOne: (queueName?: string, driverName?: string) => Promise<boolean>;
3
+ processAll: (queueName?: string, driverName?: string) => Promise<number>;
4
+ runOnce: (opts?: {
5
+ queueName?: string;
6
+ driverName?: string;
7
+ maxItems?: number;
8
+ }) => Promise<number>;
9
+ startWorker: (opts?: {
10
+ queueName?: string;
11
+ driverName?: string;
12
+ signal?: AbortSignal;
13
+ }) => Promise<number>;
14
+ };
15
+ export type CreateQueueWorkerOptions<TPayload> = {
16
+ kindLabel: string;
17
+ defaultQueueName: string;
18
+ maxAttempts: number;
19
+ getLogFields: (payload: TPayload) => Record<string, unknown>;
20
+ handle: (payload: TPayload) => Promise<void>;
21
+ };
22
+ export declare function createQueueWorker<TPayload>(options: CreateQueueWorkerOptions<TPayload>): QueueWorker;
23
+ export {};
24
+ //# sourceMappingURL=createQueueWorker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createQueueWorker.d.ts","sourceRoot":"","sources":["../../../src/workers/createQueueWorker.ts"],"names":[],"mappings":"AAGA,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1E,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACtB,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,WAAW,CAAC;KACtB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,wBAAwB,CAAC,QAAQ,IAAI;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7D,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9C,CAAC;AA4IF,wBAAgB,iBAAiB,CAAC,QAAQ,EACxC,OAAO,EAAE,wBAAwB,CAAC,QAAQ,CAAC,GAC1C,WAAW,CAOb"}
@@ -0,0 +1,114 @@
1
+ import { Logger } from '../config/logger.js';
2
+ import { Queue } from '../tools/queue/Queue.js';
3
+ const buildBaseLogFields = (message, getLogFields) => {
4
+ return {
5
+ messageId: message.id,
6
+ ...getLogFields(message.payload),
7
+ };
8
+ };
9
+ const createProcessOne = (options) => {
10
+ return async (queueName = options.defaultQueueName, driverName) => {
11
+ const message = await Queue.dequeue(queueName, driverName);
12
+ if (!message)
13
+ return false;
14
+ const baseLogFields = buildBaseLogFields(message, options.getLogFields);
15
+ // Check for delayed execution
16
+ const payload = message.payload;
17
+ const rawTimestamp = 'timestamp' in payload ? payload['timestamp'] : 0;
18
+ const timestamp = typeof rawTimestamp === 'number' ? rawTimestamp : 0;
19
+ if (timestamp > Date.now()) {
20
+ Logger.info(`${options.kindLabel} not due yet, re-queueing`, {
21
+ ...baseLogFields,
22
+ dueAt: new Date(timestamp).toISOString(),
23
+ });
24
+ // Re-queue original payload
25
+ await Queue.enqueue(queueName, message.payload, driverName);
26
+ await Queue.ack(queueName, message.id, driverName);
27
+ return false;
28
+ }
29
+ try {
30
+ Logger.info(`Processing queued ${options.kindLabel}`, baseLogFields);
31
+ await options.handle(message.payload);
32
+ await Queue.ack(queueName, message.id, driverName);
33
+ Logger.info(`${options.kindLabel} processed successfully`, baseLogFields);
34
+ return true;
35
+ }
36
+ catch (error) {
37
+ const attempts = message.attempts ?? 0;
38
+ Logger.error(`Failed to process ${options.kindLabel}`, {
39
+ ...baseLogFields,
40
+ error,
41
+ attempts,
42
+ });
43
+ if (attempts < options.maxAttempts) {
44
+ await Queue.enqueue(queueName, message.payload, driverName);
45
+ Logger.info(`${options.kindLabel} re-queued for retry`, {
46
+ ...baseLogFields,
47
+ attempts: attempts + 1,
48
+ });
49
+ }
50
+ await Queue.ack(queueName, message.id, driverName);
51
+ return false;
52
+ }
53
+ };
54
+ };
55
+ const createProcessAll = (defaultQueueName, processOne) => {
56
+ return async (queueName = defaultQueueName, driverName) => {
57
+ let processed = 0;
58
+ let hasMore = true;
59
+ while (hasMore) {
60
+ // eslint-disable-next-line no-await-in-loop
61
+ hasMore = await processOne(queueName, driverName);
62
+ if (hasMore)
63
+ processed++;
64
+ }
65
+ return processed;
66
+ };
67
+ };
68
+ const createRunOnce = (defaultQueueName, processOne) => {
69
+ return async (opts = {}) => {
70
+ const { queueName = defaultQueueName, driverName, maxItems } = opts;
71
+ let processed = 0;
72
+ if (maxItems === undefined) {
73
+ while (true) {
74
+ // eslint-disable-next-line no-await-in-loop
75
+ const didProcess = await processOne(queueName, driverName);
76
+ if (!didProcess)
77
+ break;
78
+ processed++;
79
+ }
80
+ return processed;
81
+ }
82
+ for (let i = 0; i < maxItems; i++) {
83
+ // eslint-disable-next-line no-await-in-loop
84
+ const didProcess = await processOne(queueName, driverName);
85
+ if (!didProcess)
86
+ break;
87
+ processed++;
88
+ }
89
+ return processed;
90
+ };
91
+ };
92
+ const createStartWorker = (kindLabel, defaultQueueName, processOne) => {
93
+ return async (opts = {}) => {
94
+ const { queueName = defaultQueueName, driverName, signal } = opts;
95
+ Logger.info(`Starting ${kindLabel} worker (drain-until-empty)`, { queueName });
96
+ let processedCount = 0;
97
+ while (signal?.aborted !== true) {
98
+ // eslint-disable-next-line no-await-in-loop
99
+ const didProcess = await processOne(queueName, driverName);
100
+ if (!didProcess)
101
+ break;
102
+ processedCount++;
103
+ }
104
+ Logger.info(`${kindLabel} worker finished (queue drained)`, { queueName, processedCount });
105
+ return processedCount;
106
+ };
107
+ };
108
+ export function createQueueWorker(options) {
109
+ const processOne = createProcessOne(options);
110
+ const processAll = createProcessAll(options.defaultQueueName, processOne);
111
+ const runOnce = createRunOnce(options.defaultQueueName, processOne);
112
+ const startWorker = createStartWorker(options.kindLabel, options.defaultQueueName, processOne);
113
+ return Object.freeze({ processOne, processAll, runOnce, startWorker });
114
+ }