@scpxl/nodejs-framework 1.0.43 → 1.0.45

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.
@@ -84,13 +84,13 @@ class EventManager {
84
84
  this.eventHandlers.set(event.name, handler.bind(controllerInstance));
85
85
  }
86
86
  const registeredEvents = Array.from(this.eventHandlers.keys());
87
- this.log("Registered Events", {
87
+ this.log("Registered events", {
88
88
  Events: registeredEvents.length ? registeredEvents : "None"
89
89
  });
90
90
  if (this.options.debug?.printEvents) {
91
91
  this.logger.custom({
92
92
  level: "event",
93
- message: `Registered Events:
93
+ message: `Registered events:
94
94
  ${registeredEvents.map((e) => `- ${e}`).join("\n")}`
95
95
  });
96
96
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/event/manager.ts"],
4
- "sourcesContent": ["// event-manager.ts\nimport { Logger } from '../logger/index.js';\nimport { File, Helper, Loader } from '../util/index.js';\nimport type {\n EventDefinition,\n EventHandler,\n EventManagerConstructorParams,\n EventManagerOptions,\n} from './manager.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { EventControllerType } from './controller/base.interface.js';\n\nexport default class EventManager {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n private options: EventManagerOptions;\n private events: EventDefinition[];\n private redisInstance: RedisInstance;\n // private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance | null;\n\n private eventHandlers: Map<string, EventHandler>;\n\n constructor(params: EventManagerConstructorParams) {\n const defaultOptions: Partial<EventManagerOptions> = {\n log: {\n startUp: true,\n },\n debug: {\n printEvents: false,\n },\n };\n\n this.options = Helper.defaultsDeep(params.options, defaultOptions);\n\n this.applicationConfig = params.applicationConfig;\n this.events = params.events;\n this.redisInstance = params.redisInstance;\n // this.queueManager = params.queueManager;\n this.databaseInstance = params.databaseInstance;\n\n this.eventHandlers = new Map();\n }\n\n public async load(): Promise<void> {\n // Check if controllers directory exists\n const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory);\n\n if (!controllersDirectoryExists) {\n return;\n }\n\n // Load controllers\n const controllers = await Loader.loadModulesInDirectory({\n directory: this.options.controllersDirectory,\n extensions: ['.ts', '.js'],\n });\n\n // Load event handlers\n for (const event of this.events) {\n let ControllerClass: EventControllerType;\n let controllerName: string;\n\n if (event.controller) {\n ControllerClass = event.controller;\n controllerName = ControllerClass.name;\n } else if (event.controllerName) {\n ControllerClass = controllers[event.controllerName] as EventControllerType;\n controllerName = event.controllerName;\n } else {\n throw new Error('Event controller not specified');\n }\n\n if (typeof ControllerClass !== 'function') {\n const controllerPath = `${this.options.controllersDirectory}/${event.controllerName}.ts`;\n this.logger.warn({\n message: 'Event controller not found',\n meta: {\n Controller: event.controllerName,\n Path: controllerPath,\n Event: event.name,\n },\n });\n continue;\n }\n\n // Initialize controller instance\n const controllerInstance = new ControllerClass({\n applicationConfig: this.applicationConfig,\n redisInstance: this.redisInstance,\n // queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n\n const handler = controllerInstance[event.handlerName as keyof typeof controllerInstance];\n\n if (!handler || typeof handler !== 'function') {\n this.logger.warn({\n message: 'Event handler not found',\n meta: {\n Controller: controllerName,\n Handler: event.handlerName,\n Event: event.name,\n },\n });\n continue;\n }\n\n // Store the handler\n this.eventHandlers.set(event.name, (handler as EventHandler).bind(controllerInstance));\n }\n\n // Log the list of registered events\n const registeredEvents = Array.from(this.eventHandlers.keys());\n\n this.log('Registered Events', {\n Events: registeredEvents.length ? registeredEvents : 'None',\n });\n\n if (this.options.debug?.printEvents) {\n this.logger.custom({\n level: 'event',\n message: `Registered Events:\\n${registeredEvents.map(e => `- ${e}`).join('\\n')}`,\n });\n }\n }\n\n public async run<TPayload = unknown>({ name, data }: { name: string; data: TPayload }): Promise<void> {\n try {\n const handler = this.eventHandlers.get(name);\n\n if (!handler) {\n const availableEvents = Array.from(this.eventHandlers.keys()).join(', ');\n\n this.logger.warn({\n message: 'Event handler not found for event',\n meta: {\n Event: name,\n AvailableEvents: availableEvents,\n },\n });\n\n throw new Error(`Event handler not found for event '${name}'. Available events are: ${availableEvents}`);\n }\n\n await handler(data);\n\n this.log('Event executed', { Event: name });\n } catch (error) {\n this.logger.error({ error });\n }\n }\n\n /**\n * Log event message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'event', message, meta });\n }\n}\n"],
4
+ "sourcesContent": ["// event-manager.ts\nimport { Logger } from '../logger/index.js';\nimport { File, Helper, Loader } from '../util/index.js';\nimport type {\n EventDefinition,\n EventHandler,\n EventManagerConstructorParams,\n EventManagerOptions,\n} from './manager.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { EventControllerType } from './controller/base.interface.js';\n\nexport default class EventManager {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n private options: EventManagerOptions;\n private events: EventDefinition[];\n private redisInstance: RedisInstance;\n // private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance | null;\n\n private eventHandlers: Map<string, EventHandler>;\n\n constructor(params: EventManagerConstructorParams) {\n const defaultOptions: Partial<EventManagerOptions> = {\n log: {\n startUp: true,\n },\n debug: {\n printEvents: false,\n },\n };\n\n this.options = Helper.defaultsDeep(params.options, defaultOptions);\n\n this.applicationConfig = params.applicationConfig;\n this.events = params.events;\n this.redisInstance = params.redisInstance;\n // this.queueManager = params.queueManager;\n this.databaseInstance = params.databaseInstance;\n\n this.eventHandlers = new Map();\n }\n\n public async load(): Promise<void> {\n // Check if controllers directory exists\n const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory);\n\n if (!controllersDirectoryExists) {\n return;\n }\n\n // Load controllers\n const controllers = await Loader.loadModulesInDirectory({\n directory: this.options.controllersDirectory,\n extensions: ['.ts', '.js'],\n });\n\n // Load event handlers\n for (const event of this.events) {\n let ControllerClass: EventControllerType;\n let controllerName: string;\n\n if (event.controller) {\n ControllerClass = event.controller;\n controllerName = ControllerClass.name;\n } else if (event.controllerName) {\n ControllerClass = controllers[event.controllerName] as EventControllerType;\n controllerName = event.controllerName;\n } else {\n throw new Error('Event controller not specified');\n }\n\n if (typeof ControllerClass !== 'function') {\n const controllerPath = `${this.options.controllersDirectory}/${event.controllerName}.ts`;\n this.logger.warn({\n message: 'Event controller not found',\n meta: {\n Controller: event.controllerName,\n Path: controllerPath,\n Event: event.name,\n },\n });\n continue;\n }\n\n // Initialize controller instance\n const controllerInstance = new ControllerClass({\n applicationConfig: this.applicationConfig,\n redisInstance: this.redisInstance,\n // queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n\n const handler = controllerInstance[event.handlerName as keyof typeof controllerInstance];\n\n if (!handler || typeof handler !== 'function') {\n this.logger.warn({\n message: 'Event handler not found',\n meta: {\n Controller: controllerName,\n Handler: event.handlerName,\n Event: event.name,\n },\n });\n continue;\n }\n\n // Store the handler\n this.eventHandlers.set(event.name, (handler as EventHandler).bind(controllerInstance));\n }\n\n // Log the list of registered events\n const registeredEvents = Array.from(this.eventHandlers.keys());\n\n this.log('Registered events', {\n Events: registeredEvents.length ? registeredEvents : 'None',\n });\n\n if (this.options.debug?.printEvents) {\n this.logger.custom({\n level: 'event',\n message: `Registered events:\\n${registeredEvents.map(e => `- ${e}`).join('\\n')}`,\n });\n }\n }\n\n public async run<TPayload = unknown>({ name, data }: { name: string; data: TPayload }): Promise<void> {\n try {\n const handler = this.eventHandlers.get(name);\n\n if (!handler) {\n const availableEvents = Array.from(this.eventHandlers.keys()).join(', ');\n\n this.logger.warn({\n message: 'Event handler not found for event',\n meta: {\n Event: name,\n AvailableEvents: availableEvents,\n },\n });\n\n throw new Error(`Event handler not found for event '${name}'. Available events are: ${availableEvents}`);\n }\n\n await handler(data);\n\n this.log('Event executed', { Event: name });\n } catch (error) {\n this.logger.error({ error });\n }\n }\n\n /**\n * Log event message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'event', message, meta });\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,16 @@
1
1
  import type { QueueJob } from './job.interface.js';
2
+ import type { QueueOptions, WorkerOptions } from 'bullmq';
3
+ /** Runtime settings applied to the BullMQ Worker for this queue */
4
+ export interface QueueRuntimeSettings {
5
+ /** Max number of concurrently processed jobs across all job types */
6
+ concurrency?: WorkerOptions['concurrency'];
7
+ /** Milliseconds a job's lock is held before considered stalled */
8
+ lockDuration?: WorkerOptions['lockDuration'];
9
+ /** Milliseconds between stall checks */
10
+ stalledInterval?: WorkerOptions['stalledInterval'];
11
+ /** Number of stall detections before failing the job */
12
+ maxStalledCount?: WorkerOptions['maxStalledCount'];
13
+ }
2
14
  export interface QueueItem {
3
15
  /** Queue name */
4
16
  name: string;
@@ -6,5 +18,16 @@ export interface QueueItem {
6
18
  isExternal?: boolean;
7
19
  /** Queue jobs */
8
20
  jobs: QueueJob[];
21
+ /**
22
+ * Runtime processing settings for this queue's worker
23
+ * (maps to BullMQ WorkerOptions). These override global defaults if provided.
24
+ */
25
+ settings?: QueueRuntimeSettings;
26
+ /**
27
+ * Default BullMQ job options applied when jobs are added to this queue.
28
+ * Framework sets sensible defaults (removeOnComplete/removeOnFail) which can
29
+ * be overridden or extended here.
30
+ */
31
+ defaultJobOptions?: QueueOptions['defaultJobOptions'];
9
32
  }
10
33
  //# sourceMappingURL=index.interface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.interface.d.ts","sourceRoot":"","sources":["../../src/queue/index.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,MAAM,WAAW,SAAS;IACxB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IAEb,gCAAgC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,iBAAiB;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB"}
1
+ {"version":3,"file":"index.interface.d.ts","sourceRoot":"","sources":["../../src/queue/index.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE1D,mEAAmE;AACnE,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,WAAW,CAAC,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAC3C,kEAAkE;IAClE,YAAY,CAAC,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IAC7C,wCAAwC;IACxC,eAAe,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;IACnD,wDAAwD;IACxD,eAAe,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,SAAS;IACxB,iBAAiB;IACjB,IAAI,EAAE,MAAM,CAAC;IAEb,gCAAgC;IAChC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,iBAAiB;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;IAEjB;;;OAGG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAEhC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,YAAY,CAAC,mBAAmB,CAAC,CAAC;CACvD"}
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/queue/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAgD,MAAM,QAAQ,CAAC;AAEhF,OAAO,KAAK,EAAE,6BAA6B,EAAuB,MAAM,wBAAwB,CAAC;AAOjG,OAAO,KAAK,EAAY,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAElF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,OAAO,CAAC,MAAM,CAAyB;IAEvC,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO,CAAC,OAAO,CAAsB;IAErC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,YAAY,CAAC,CAAe;IAEpC,OAAO,CAAC,MAAM,CAAiC;IAE/C,OAAO,CAAC,aAAa,CAAyC;gBAElD,EACV,iBAAiB,EACjB,OAAO,EACP,MAAM,EAAE,OAAO,EACf,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,EAAE,6BAA6B;IAgBnB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;QAAE,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC/E,OAAO,CAAC,aAAa;IA+DrB,OAAO,CAAC,qBAAqB;IA0C7B,OAAO,CAAC,YAAY,CAElB;IAEF,OAAO,CAAC,cAAc,CAIpB;IAEF,OAAO,CAAC,eAAe,CAKrB;IAEF,OAAO,CAAC,cAAc,CAEpB;IAEK,aAAa,GAClB,QAAQ,SAAS,eAAe,GAAG,eAAe,EAClD,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,OAAO,GAAG,OAAO,EACjB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,2BAIC;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;KACzC,KAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC,CA0B7E;IAEF,OAAO,CAAC,eAAe,CAqDrB;IAEW,qBAAqB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IA6B3D;;OAEG;IACI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlE"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/queue/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAgD,MAAM,QAAQ,CAAC;AAEhF,OAAO,KAAK,EAAE,6BAA6B,EAAuB,MAAM,wBAAwB,CAAC;AAOjG,OAAO,KAAK,EAAY,YAAY,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAElF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAItD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC5E,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,OAAO,CAAC,MAAM,CAAyB;IAEvC,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO,CAAC,OAAO,CAAsB;IAErC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,YAAY,CAAC,CAAe;IAEpC,OAAO,CAAC,MAAM,CAAiC;IAE/C,OAAO,CAAC,aAAa,CAAyC;gBAElD,EACV,iBAAiB,EACjB,OAAO,EACP,MAAM,EAAE,OAAO,EACf,aAAa,EACb,gBAAgB,EAChB,YAAY,GACb,EAAE,6BAA6B;IAgBnB,cAAc,CAAC,EAAE,MAAM,EAAE,EAAE;QAAE,MAAM,EAAE,SAAS,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC/E,OAAO,CAAC,aAAa;IAsErB,OAAO,CAAC,qBAAqB;IA0C7B,OAAO,CAAC,YAAY,CAElB;IAEF,OAAO,CAAC,cAAc,CAIpB;IAEF,OAAO,CAAC,eAAe,CAKrB;IAEF,OAAO,CAAC,cAAc,CAEpB;IAEK,aAAa,GAClB,QAAQ,SAAS,eAAe,GAAG,eAAe,EAClD,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnE,OAAO,GAAG,OAAO,EACjB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,2BAIC;QACD,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;KACzC,KAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC,CA0B7E;IAEF,OAAO,CAAC,eAAe,CAqDrB;IAEW,qBAAqB,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IA6B3D;;OAEG;IACI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlE"}
@@ -78,7 +78,8 @@ class QueueManager {
78
78
  connection: this.redisInstance.client,
79
79
  defaultJobOptions: {
80
80
  removeOnComplete: true,
81
- removeOnFail: true
81
+ removeOnFail: true,
82
+ ...queue.defaultJobOptions ?? {}
82
83
  }
83
84
  };
84
85
  const queueInstance = new Queue(queue.name, queueOptions);
@@ -89,7 +90,8 @@ class QueueManager {
89
90
  if (!queue.isExternal) {
90
91
  const workerOptions = {
91
92
  connection: this.redisInstance.client,
92
- autorun: true
93
+ autorun: true,
94
+ ...queue.settings ?? {}
93
95
  };
94
96
  new QueueWorker({
95
97
  applicationConfig: this.applicationConfig,
@@ -102,7 +104,10 @@ class QueueManager {
102
104
  }
103
105
  this.queues.set(queue.name, queueInstance);
104
106
  if (this.applicationConfig.queue.log?.queueRegistered) {
105
- this.log("Registered queue", { Name: queue.name });
107
+ this.log("Registered queue", {
108
+ Name: queue.name,
109
+ Settings: queue.settings ? JSON.stringify(queue.settings) : "default"
110
+ });
106
111
  }
107
112
  this.registerJobProcessors({
108
113
  queue,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/queue/manager.ts"],
4
- "sourcesContent": ["import { type Job, Queue, type QueueOptions, type WorkerOptions } from 'bullmq';\nimport path from 'path';\nimport type { QueueManagerConstructorParams, QueueManagerOptions } from './manager.interface.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport { Logger } from '../logger/index.js';\nimport QueueWorker from './worker.js';\nimport type BaseProcessor from './processor/base.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport type { QueueJob, QueueJobData, QueueJobPayload } from './job.interface.js';\nimport type { ProcessorConstructor } from './processor/processor.interface.js';\nimport type { QueueItem } from './index.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\n\nexport interface JobSummary {\n id: string;\n name: string;\n queueName: string;\n state: 'active' | 'waiting' | 'completed' | 'failed' | 'delayed' | 'paused';\n attemptsMade: number;\n failedReason?: string;\n}\n\nexport default class QueueManager {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: QueueManagerOptions;\n\n private redisInstance: RedisInstance;\n private databaseInstance: DatabaseInstance | null;\n private eventManager?: EventManager;\n\n private queues: Map<string, Queue> = new Map();\n\n private jobProcessors: Map<string, BaseProcessor> = new Map();\n\n constructor({\n applicationConfig,\n options,\n queues: _queues,\n redisInstance,\n databaseInstance,\n eventManager,\n }: QueueManagerConstructorParams) {\n // Merge options with defaults if provided\n if (options) {\n this.options = options;\n } else {\n // This shouldn't happen, but handle the edge case\n this.options = { processorsDirectory: '' };\n }\n\n this.applicationConfig = applicationConfig;\n\n this.redisInstance = redisInstance;\n this.databaseInstance = databaseInstance;\n this.eventManager = eventManager;\n }\n\n public async registerQueues({ queues }: { queues: QueueItem[] }): Promise<void> {\n if (!queues) {\n return;\n }\n\n // Check if processors directory exists\n const processorsDirectoryExists = await File.pathExists(this.options.processorsDirectory);\n\n if (!processorsDirectoryExists) {\n return;\n }\n\n try {\n const jobProcessorClasses = await Loader.loadModulesInDirectory<ProcessorConstructor>({\n directory: this.options.processorsDirectory,\n extensions: ['.ts', '.js'],\n });\n\n for (const queue of queues) {\n this.registerQueue({ queue, jobProcessorClasses });\n }\n\n if (this.applicationConfig.queue.log?.queuesRegistered) {\n this.log('Registered queue', {\n 'Queue Count': queues.length,\n 'Job Count': this.jobProcessors.size,\n });\n }\n } catch (error) {\n Logger.error({ error });\n }\n }\n\n private registerQueue({\n queue,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!queue.jobs) {\n Logger.warn({\n message: 'No jobs found for queue, skip register',\n meta: {\n Name: queue.name,\n },\n });\n\n return;\n }\n\n const queueOptions: QueueOptions = {\n connection: this.redisInstance.client,\n defaultJobOptions: {\n removeOnComplete: true,\n removeOnFail: true,\n },\n };\n\n const queueInstance = new Queue(queue.name, queueOptions);\n\n queueInstance.on('error', this.onQueueError);\n queueInstance.on('waiting', this.onQueueWaiting);\n queueInstance.on('progress', this.onQueueProgress);\n queueInstance.on('removed', this.onQueueRemoved);\n\n if (!queue.isExternal) {\n const workerOptions: WorkerOptions = {\n connection: this.redisInstance.client,\n autorun: true,\n };\n\n new QueueWorker({\n applicationConfig: this.applicationConfig,\n queueManager: this,\n name: queue.name,\n processor: this.workerProcessor,\n options: workerOptions,\n redisInstance: this.redisInstance,\n });\n }\n\n this.queues.set(queue.name, queueInstance);\n\n if (this.applicationConfig.queue.log?.queueRegistered) {\n this.log('Registered queue', { Name: queue.name });\n }\n\n // Register job processors\n this.registerJobProcessors({\n queue,\n jobs: queue.jobs,\n jobProcessorClasses,\n });\n }\n\n private registerJobProcessors({\n queue,\n jobs,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobs: QueueJob[];\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!jobs) {\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n for (const job of jobs) {\n if (!queue.isExternal) {\n const ProcessorClass = jobProcessorClasses[job.id];\n\n if (!ProcessorClass) {\n const jobPath = path.join(this.options.processorsDirectory, `${job.id}.${scriptFileExtension}`);\n\n throw new Error(`Processor class not found (Job ID: ${job.id} | Path: ${jobPath})`);\n }\n\n const processorInstance = new ProcessorClass(\n this,\n this.applicationConfig,\n this.redisInstance,\n this.databaseInstance,\n this.eventManager,\n );\n\n this.jobProcessors.set(job.id, processorInstance);\n }\n\n if (this.applicationConfig.queue.log?.jobRegistered) {\n this.log('Job registered', { ID: job.id });\n }\n }\n }\n\n private onQueueError = (error: Error): void => {\n Logger.error({ error });\n };\n\n private onQueueWaiting = (job: Job): void => {\n if (this.applicationConfig.queue.log?.queueWaiting) {\n this.log('Waiting...', { Queue: job.queueName, Job: job.id });\n }\n };\n\n private onQueueProgress = (jobId: string, progress: unknown): void => {\n this.log('Progress update', {\n 'Job ID': jobId,\n Progress: progress,\n });\n };\n\n private onQueueRemoved = (jobId: string): void => {\n this.log('Removed queue', { Job: jobId });\n };\n\n public addJobToQueue = async <\n TPayload extends QueueJobPayload = QueueJobPayload,\n TMetadata extends Record<string, unknown> = Record<string, unknown>,\n TResult = unknown,\n TName extends string = string,\n >({\n queueId,\n jobId,\n data,\n }: {\n queueId: string;\n jobId: TName;\n data: QueueJobData<TPayload, TMetadata>;\n }): Promise<Job<QueueJobData<TPayload, TMetadata>, TResult, TName> | undefined> => {\n const queue = this.queues.get(queueId);\n\n if (!queue) {\n this.log('Queue not found', { 'Queue ID': queueId });\n\n return;\n }\n\n const job = (await queue.add(jobId, data)) as Job<QueueJobData<TPayload, TMetadata>, TResult, TName>;\n\n const dataStr = JSON.stringify(data);\n\n const maxLogDataStrLength = 50;\n const truncatedLogDataStr =\n dataStr.length > maxLogDataStrLength ? `${dataStr.substring(0, maxLogDataStrLength)}...` : dataStr;\n\n if (this.applicationConfig.queue.log?.jobAdded) {\n this.log('Job added', {\n Queue: queueId,\n 'Job ID': jobId,\n Data: truncatedLogDataStr,\n });\n }\n\n return job;\n };\n\n private workerProcessor = async (job: Job): Promise<unknown> => {\n if (!job) {\n return;\n }\n\n const startTime = Time.now();\n\n // Add start time to job data\n if (typeof job.updateData === 'function') {\n try {\n await job.updateData({ ...job.data, startTime });\n } catch (error) {\n Logger.warn({\n message: 'Failed to persist job metadata before processing',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: error instanceof Error ? error.message : String(error),\n },\n });\n }\n }\n\n this.log('Worker processing...', {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n });\n\n const processor = this.jobProcessors.get(job.name);\n\n if (!processor) {\n throw new Error(`No processor registered for job (Name: ${job.name})`);\n }\n\n try {\n const jobResult = await processor.process({ job });\n\n return jobResult;\n } catch (error) {\n Logger.warn({\n message: 'Queue worker processing error',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: (error as Error).message,\n },\n });\n\n Logger.error({ error });\n }\n };\n\n public async listAllJobsWithStatus(): Promise<JobSummary[]> {\n const jobsSummary: JobSummary[] = [];\n\n for (const [queueName, queue] of this.queues) {\n const jobStates = ['active', 'waiting', 'completed', 'failed', 'delayed', 'paused'] as const;\n\n const jobsDetailsPromises = jobStates.map(async state => {\n const jobs = await queue.getJobs([state]);\n return jobs.map(\n (job): JobSummary => ({\n id: job.id ?? 'unknown',\n name: job.name ?? 'unknown',\n queueName,\n state,\n attemptsMade: job.attemptsMade,\n failedReason: job.failedReason,\n }),\n );\n });\n\n const results = await Promise.all(jobsDetailsPromises);\n const flattenedResults = results.flat();\n\n jobsSummary.push(...flattenedResults);\n }\n\n return jobsSummary;\n }\n\n /**\n * Log queue message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'queue', message, meta });\n }\n}\n"],
5
- "mappings": ";;AAAA,SAAmB,aAAoD;AACvE,OAAO,UAAU;AAIjB,SAAS,cAAc;AACvB,OAAO,iBAAiB;AAExB,SAAS,MAAM,QAAQ,QAAQ,YAAY;AAgB3C,MAAO,aAA2B;AAAA,EAxBlC,OAwBkC;AAAA;AAAA;AAAA,EACxB,SAAwB;AAAA,EAExB;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,SAA6B,oBAAI,IAAI;AAAA,EAErC,gBAA4C,oBAAI,IAAI;AAAA,EAE5D,YAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAkC;AAEhC,QAAI,SAAS;AACX,WAAK,UAAU;AAAA,IACjB,OAAO;AAEL,WAAK,UAAU,EAAE,qBAAqB,GAAG;AAAA,IAC3C;AAEA,SAAK,oBAAoB;AAEzB,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AACxB,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,MAAa,eAAe,EAAE,OAAO,GAA2C;AAC9E,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAGA,UAAM,4BAA4B,MAAM,KAAK,WAAW,KAAK,QAAQ,mBAAmB;AAExF,QAAI,CAAC,2BAA2B;AAC9B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,sBAAsB,MAAM,OAAO,uBAA6C;AAAA,QACpF,WAAW,KAAK,QAAQ;AAAA,QACxB,YAAY,CAAC,OAAO,KAAK;AAAA,MAC3B,CAAC;AAED,iBAAW,SAAS,QAAQ;AAC1B,aAAK,cAAc,EAAE,OAAO,oBAAoB,CAAC;AAAA,MACnD;AAEA,UAAI,KAAK,kBAAkB,MAAM,KAAK,kBAAkB;AACtD,aAAK,IAAI,oBAAoB;AAAA,UAC3B,eAAe,OAAO;AAAA,UACtB,aAAa,KAAK,cAAc;AAAA,QAClC,CAAC;AAAA,MACH;AAAA,IACF,SAAS,OAAO;AACd,aAAO,MAAM,EAAE,MAAM,CAAC;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,cAAc;AAAA,IACpB;AAAA,IACA;AAAA,EACF,GAGS;AACP,QAAI,CAAC,MAAM,MAAM;AACf,aAAO,KAAK;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,MAAM,MAAM;AAAA,QACd;AAAA,MACF,CAAC;AAED;AAAA,IACF;AAEA,UAAM,eAA6B;AAAA,MACjC,YAAY,KAAK,cAAc;AAAA,MAC/B,mBAAmB;AAAA,QACjB,kBAAkB;AAAA,QAClB,cAAc;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,gBAAgB,IAAI,MAAM,MAAM,MAAM,YAAY;AAExD,kBAAc,GAAG,SAAS,KAAK,YAAY;AAC3C,kBAAc,GAAG,WAAW,KAAK,cAAc;AAC/C,kBAAc,GAAG,YAAY,KAAK,eAAe;AACjD,kBAAc,GAAG,WAAW,KAAK,cAAc;AAE/C,QAAI,CAAC,MAAM,YAAY;AACrB,YAAM,gBAA+B;AAAA,QACnC,YAAY,KAAK,cAAc;AAAA,QAC/B,SAAS;AAAA,MACX;AAEA,UAAI,YAAY;AAAA,QACd,mBAAmB,KAAK;AAAA,QACxB,cAAc;AAAA,QACd,MAAM,MAAM;AAAA,QACZ,WAAW,KAAK;AAAA,QAChB,SAAS;AAAA,QACT,eAAe,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AAEA,SAAK,OAAO,IAAI,MAAM,MAAM,aAAa;AAEzC,QAAI,KAAK,kBAAkB,MAAM,KAAK,iBAAiB;AACrD,WAAK,IAAI,oBAAoB,EAAE,MAAM,MAAM,KAAK,CAAC;AAAA,IACnD;AAGA,SAAK,sBAAsB;AAAA,MACzB;AAAA,MACA,MAAM,MAAM;AAAA,MACZ;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,sBAAsB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIS;AACP,QAAI,CAAC,MAAM;AACT;AAAA,IACF;AAEA,UAAM,sBAAsB,OAAO,uBAAuB;AAE1D,eAAW,OAAO,MAAM;AACtB,UAAI,CAAC,MAAM,YAAY;AACrB,cAAM,iBAAiB,oBAAoB,IAAI,EAAE;AAEjD,YAAI,CAAC,gBAAgB;AACnB,gBAAM,UAAU,KAAK,KAAK,KAAK,QAAQ,qBAAqB,GAAG,IAAI,EAAE,IAAI,mBAAmB,EAAE;AAE9F,gBAAM,IAAI,MAAM,sCAAsC,IAAI,EAAE,YAAY,OAAO,GAAG;AAAA,QACpF;AAEA,cAAM,oBAAoB,IAAI;AAAA,UAC5B;AAAA,UACA,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,QACP;AAEA,aAAK,cAAc,IAAI,IAAI,IAAI,iBAAiB;AAAA,MAClD;AAEA,UAAI,KAAK,kBAAkB,MAAM,KAAK,eAAe;AACnD,aAAK,IAAI,kBAAkB,EAAE,IAAI,IAAI,GAAG,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,eAAe,wBAAC,UAAuB;AAC7C,WAAO,MAAM,EAAE,MAAM,CAAC;AAAA,EACxB,GAFuB;AAAA,EAIf,iBAAiB,wBAAC,QAAmB;AAC3C,QAAI,KAAK,kBAAkB,MAAM,KAAK,cAAc;AAClD,WAAK,IAAI,cAAc,EAAE,OAAO,IAAI,WAAW,KAAK,IAAI,GAAG,CAAC;AAAA,IAC9D;AAAA,EACF,GAJyB;AAAA,EAMjB,kBAAkB,wBAAC,OAAe,aAA4B;AACpE,SAAK,IAAI,mBAAmB;AAAA,MAC1B,UAAU;AAAA,MACV,UAAU;AAAA,IACZ,CAAC;AAAA,EACH,GAL0B;AAAA,EAOlB,iBAAiB,wBAAC,UAAwB;AAChD,SAAK,IAAI,iBAAiB,EAAE,KAAK,MAAM,CAAC;AAAA,EAC1C,GAFyB;AAAA,EAIlB,gBAAgB,8BAKrB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,MAImF;AACjF,UAAM,QAAQ,KAAK,OAAO,IAAI,OAAO;AAErC,QAAI,CAAC,OAAO;AACV,WAAK,IAAI,mBAAmB,EAAE,YAAY,QAAQ,CAAC;AAEnD;AAAA,IACF;AAEA,UAAM,MAAO,MAAM,MAAM,IAAI,OAAO,IAAI;AAExC,UAAM,UAAU,KAAK,UAAU,IAAI;AAEnC,UAAM,sBAAsB;AAC5B,UAAM,sBACJ,QAAQ,SAAS,sBAAsB,GAAG,QAAQ,UAAU,GAAG,mBAAmB,CAAC,QAAQ;AAE7F,QAAI,KAAK,kBAAkB,MAAM,KAAK,UAAU;AAC9C,WAAK,IAAI,aAAa;AAAA,QACpB,OAAO;AAAA,QACP,UAAU;AAAA,QACV,MAAM;AAAA,MACR,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,GAvCuB;AAAA,EAyCf,kBAAkB,8BAAO,QAA+B;AAC9D,QAAI,CAAC,KAAK;AACR;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,IAAI;AAG3B,QAAI,OAAO,IAAI,eAAe,YAAY;AACxC,UAAI;AACF,cAAM,IAAI,WAAW,EAAE,GAAG,IAAI,MAAM,UAAU,CAAC;AAAA,MACjD,SAAS,OAAO;AACd,eAAO,KAAK;AAAA,UACV,SAAS;AAAA,UACT,MAAM;AAAA,YACJ,OAAO,IAAI;AAAA,YACX,YAAY,IAAI;AAAA,YAChB,UAAU,IAAI;AAAA,YACd,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,UAC9D;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,SAAK,IAAI,wBAAwB;AAAA,MAC/B,OAAO,IAAI;AAAA,MACX,YAAY,IAAI;AAAA,MAChB,UAAU,IAAI;AAAA,IAChB,CAAC;AAED,UAAM,YAAY,KAAK,cAAc,IAAI,IAAI,IAAI;AAEjD,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,0CAA0C,IAAI,IAAI,GAAG;AAAA,IACvE;AAEA,QAAI;AACF,YAAM,YAAY,MAAM,UAAU,QAAQ,EAAE,IAAI,CAAC;AAEjD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,aAAO,KAAK;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,OAAO,IAAI;AAAA,UACX,YAAY,IAAI;AAAA,UAChB,UAAU,IAAI;AAAA,UACd,OAAQ,MAAgB;AAAA,QAC1B;AAAA,MACF,CAAC;AAED,aAAO,MAAM,EAAE,MAAM,CAAC;AAAA,IACxB;AAAA,EACF,GArD0B;AAAA,EAuD1B,MAAa,wBAA+C;AAC1D,UAAM,cAA4B,CAAC;AAEnC,eAAW,CAAC,WAAW,KAAK,KAAK,KAAK,QAAQ;AAC5C,YAAM,YAAY,CAAC,UAAU,WAAW,aAAa,UAAU,WAAW,QAAQ;AAElF,YAAM,sBAAsB,UAAU,IAAI,OAAM,UAAS;AACvD,cAAM,OAAO,MAAM,MAAM,QAAQ,CAAC,KAAK,CAAC;AACxC,eAAO,KAAK;AAAA,UACV,CAAC,SAAqB;AAAA,YACpB,IAAI,IAAI,MAAM;AAAA,YACd,MAAM,IAAI,QAAQ;AAAA,YAClB;AAAA,YACA;AAAA,YACA,cAAc,IAAI;AAAA,YAClB,cAAc,IAAI;AAAA,UACpB;AAAA,QACF;AAAA,MACF,CAAC;AAED,YAAM,UAAU,MAAM,QAAQ,IAAI,mBAAmB;AACrD,YAAM,mBAAmB,QAAQ,KAAK;AAEtC,kBAAY,KAAK,GAAG,gBAAgB;AAAA,IACtC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKO,IAAI,SAAiB,MAAsC;AAChE,SAAK,OAAO,OAAO,EAAE,OAAO,SAAS,SAAS,KAAK,CAAC;AAAA,EACtD;AACF;",
4
+ "sourcesContent": ["import { type Job, Queue, type QueueOptions, type WorkerOptions } from 'bullmq';\nimport path from 'path';\nimport type { QueueManagerConstructorParams, QueueManagerOptions } from './manager.interface.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport { Logger } from '../logger/index.js';\nimport QueueWorker from './worker.js';\nimport type BaseProcessor from './processor/base.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport type { QueueJob, QueueJobData, QueueJobPayload } from './job.interface.js';\nimport type { ProcessorConstructor } from './processor/processor.interface.js';\nimport type { QueueItem } from './index.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\n\nexport interface JobSummary {\n id: string;\n name: string;\n queueName: string;\n state: 'active' | 'waiting' | 'completed' | 'failed' | 'delayed' | 'paused';\n attemptsMade: number;\n failedReason?: string;\n}\n\nexport default class QueueManager {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: QueueManagerOptions;\n\n private redisInstance: RedisInstance;\n private databaseInstance: DatabaseInstance | null;\n private eventManager?: EventManager;\n\n private queues: Map<string, Queue> = new Map();\n\n private jobProcessors: Map<string, BaseProcessor> = new Map();\n\n constructor({\n applicationConfig,\n options,\n queues: _queues,\n redisInstance,\n databaseInstance,\n eventManager,\n }: QueueManagerConstructorParams) {\n // Merge options with defaults if provided\n if (options) {\n this.options = options;\n } else {\n // This shouldn't happen, but handle the edge case\n this.options = { processorsDirectory: '' };\n }\n\n this.applicationConfig = applicationConfig;\n\n this.redisInstance = redisInstance;\n this.databaseInstance = databaseInstance;\n this.eventManager = eventManager;\n }\n\n public async registerQueues({ queues }: { queues: QueueItem[] }): Promise<void> {\n if (!queues) {\n return;\n }\n\n // Check if processors directory exists\n const processorsDirectoryExists = await File.pathExists(this.options.processorsDirectory);\n\n if (!processorsDirectoryExists) {\n return;\n }\n\n try {\n const jobProcessorClasses = await Loader.loadModulesInDirectory<ProcessorConstructor>({\n directory: this.options.processorsDirectory,\n extensions: ['.ts', '.js'],\n });\n\n for (const queue of queues) {\n this.registerQueue({ queue, jobProcessorClasses });\n }\n\n if (this.applicationConfig.queue.log?.queuesRegistered) {\n this.log('Registered queue', {\n 'Queue Count': queues.length,\n 'Job Count': this.jobProcessors.size,\n });\n }\n } catch (error) {\n Logger.error({ error });\n }\n }\n\n private registerQueue({\n queue,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!queue.jobs) {\n Logger.warn({\n message: 'No jobs found for queue, skip register',\n meta: {\n Name: queue.name,\n },\n });\n\n return;\n }\n\n // Merge framework defaults with queue-specific default job options\n const queueOptions: QueueOptions = {\n connection: this.redisInstance.client,\n defaultJobOptions: {\n removeOnComplete: true,\n removeOnFail: true,\n ...(queue.defaultJobOptions ?? {}),\n },\n };\n\n const queueInstance = new Queue(queue.name, queueOptions);\n\n queueInstance.on('error', this.onQueueError);\n queueInstance.on('waiting', this.onQueueWaiting);\n queueInstance.on('progress', this.onQueueProgress);\n queueInstance.on('removed', this.onQueueRemoved);\n\n if (!queue.isExternal) {\n // Build worker options, applying per-queue runtime settings\n const workerOptions: WorkerOptions = {\n connection: this.redisInstance.client,\n autorun: true,\n ...(queue.settings ?? {}),\n };\n\n new QueueWorker({\n applicationConfig: this.applicationConfig,\n queueManager: this,\n name: queue.name,\n processor: this.workerProcessor,\n options: workerOptions,\n redisInstance: this.redisInstance,\n });\n }\n\n this.queues.set(queue.name, queueInstance);\n\n if (this.applicationConfig.queue.log?.queueRegistered) {\n this.log('Registered queue', {\n Name: queue.name,\n Settings: queue.settings ? JSON.stringify(queue.settings) : 'default',\n });\n }\n\n // Register job processors\n this.registerJobProcessors({\n queue,\n jobs: queue.jobs,\n jobProcessorClasses,\n });\n }\n\n private registerJobProcessors({\n queue,\n jobs,\n jobProcessorClasses,\n }: {\n queue: QueueItem;\n jobs: QueueJob[];\n jobProcessorClasses: Record<string, ProcessorConstructor>;\n }): void {\n if (!jobs) {\n return;\n }\n\n const scriptFileExtension = Helper.getScriptFileExtension();\n\n for (const job of jobs) {\n if (!queue.isExternal) {\n const ProcessorClass = jobProcessorClasses[job.id];\n\n if (!ProcessorClass) {\n const jobPath = path.join(this.options.processorsDirectory, `${job.id}.${scriptFileExtension}`);\n\n throw new Error(`Processor class not found (Job ID: ${job.id} | Path: ${jobPath})`);\n }\n\n const processorInstance = new ProcessorClass(\n this,\n this.applicationConfig,\n this.redisInstance,\n this.databaseInstance,\n this.eventManager,\n );\n\n this.jobProcessors.set(job.id, processorInstance);\n }\n\n if (this.applicationConfig.queue.log?.jobRegistered) {\n this.log('Job registered', { ID: job.id });\n }\n }\n }\n\n private onQueueError = (error: Error): void => {\n Logger.error({ error });\n };\n\n private onQueueWaiting = (job: Job): void => {\n if (this.applicationConfig.queue.log?.queueWaiting) {\n this.log('Waiting...', { Queue: job.queueName, Job: job.id });\n }\n };\n\n private onQueueProgress = (jobId: string, progress: unknown): void => {\n this.log('Progress update', {\n 'Job ID': jobId,\n Progress: progress,\n });\n };\n\n private onQueueRemoved = (jobId: string): void => {\n this.log('Removed queue', { Job: jobId });\n };\n\n public addJobToQueue = async <\n TPayload extends QueueJobPayload = QueueJobPayload,\n TMetadata extends Record<string, unknown> = Record<string, unknown>,\n TResult = unknown,\n TName extends string = string,\n >({\n queueId,\n jobId,\n data,\n }: {\n queueId: string;\n jobId: TName;\n data: QueueJobData<TPayload, TMetadata>;\n }): Promise<Job<QueueJobData<TPayload, TMetadata>, TResult, TName> | undefined> => {\n const queue = this.queues.get(queueId);\n\n if (!queue) {\n this.log('Queue not found', { 'Queue ID': queueId });\n\n return;\n }\n\n const job = (await queue.add(jobId, data)) as Job<QueueJobData<TPayload, TMetadata>, TResult, TName>;\n\n const dataStr = JSON.stringify(data);\n\n const maxLogDataStrLength = 50;\n const truncatedLogDataStr =\n dataStr.length > maxLogDataStrLength ? `${dataStr.substring(0, maxLogDataStrLength)}...` : dataStr;\n\n if (this.applicationConfig.queue.log?.jobAdded) {\n this.log('Job added', {\n Queue: queueId,\n 'Job ID': jobId,\n Data: truncatedLogDataStr,\n });\n }\n\n return job;\n };\n\n private workerProcessor = async (job: Job): Promise<unknown> => {\n if (!job) {\n return;\n }\n\n const startTime = Time.now();\n\n // Add start time to job data\n if (typeof job.updateData === 'function') {\n try {\n await job.updateData({ ...job.data, startTime });\n } catch (error) {\n Logger.warn({\n message: 'Failed to persist job metadata before processing',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: error instanceof Error ? error.message : String(error),\n },\n });\n }\n }\n\n this.log('Worker processing...', {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n });\n\n const processor = this.jobProcessors.get(job.name);\n\n if (!processor) {\n throw new Error(`No processor registered for job (Name: ${job.name})`);\n }\n\n try {\n const jobResult = await processor.process({ job });\n\n return jobResult;\n } catch (error) {\n Logger.warn({\n message: 'Queue worker processing error',\n meta: {\n Queue: job.queueName,\n 'Job Name': job.name,\n 'Job ID': job.id,\n Error: (error as Error).message,\n },\n });\n\n Logger.error({ error });\n }\n };\n\n public async listAllJobsWithStatus(): Promise<JobSummary[]> {\n const jobsSummary: JobSummary[] = [];\n\n for (const [queueName, queue] of this.queues) {\n const jobStates = ['active', 'waiting', 'completed', 'failed', 'delayed', 'paused'] as const;\n\n const jobsDetailsPromises = jobStates.map(async state => {\n const jobs = await queue.getJobs([state]);\n return jobs.map(\n (job): JobSummary => ({\n id: job.id ?? 'unknown',\n name: job.name ?? 'unknown',\n queueName,\n state,\n attemptsMade: job.attemptsMade,\n failedReason: job.failedReason,\n }),\n );\n });\n\n const results = await Promise.all(jobsDetailsPromises);\n const flattenedResults = results.flat();\n\n jobsSummary.push(...flattenedResults);\n }\n\n return jobsSummary;\n }\n\n /**\n * Log queue message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'queue', message, meta });\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"webserver.d.ts","sourceRoot":"","sources":["../../src/webserver/webserver.ts"],"names":[],"mappings":"AACA,OAAgB,EACd,KAAK,eAAe,EAIpB,KAAK,WAAW,EACjB,MAAM,SAAS,CAAC;AAKjB,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAIhC,MAAM,0BAA0B,CAAC;AAMlC,OAAO,KAAK,EAAE,gBAAgB,EAA+B,MAAM,gCAAgC,CAAC;AAGpG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAI1E,OAAO,EAAE,KAAK,eAAe,EAAyC,MAAM,2BAA2B,CAAC;AAExG,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;CACF;AAED,cAAM,SAAS;IACb,OAAO,CAAC,MAAM,CAAyB;IAEvC,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IAEnD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAmB;IAEpC,aAAa,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;IAE3E,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,0BAA0B,GAAG;QAAE,gBAAgB,EAAE,gBAAgB,CAAA;KAAE;IAuDvF;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBlC;;OAEG;YACW,iBAAiB;IAiD/B;;OAEG;IACH,OAAO,CAAC,cAAc;YAeR,QAAQ;YAeR,SAAS;YA2BT,UAAU;YAuCV,OAAO;YAMP,OAAO;IAIrB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,yBAAyB;IAcjC;;OAEG;YACW,eAAe;YAkPf,uBAAuB;IA4CrC,OAAO,CAAC,oBAAoB;IA8C5B,OAAO,CAAC,YAAY;IA6CP,WAAW,CAAC,EACvB,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,SAAS,EACT,WAAW,EACX,WAAW,EACX,eAAe,GAChB,EAAE;QACD,kBAAkB,EAAE,GAAG,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;QACzC,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,wBAAwB,CAAC;QACvC,eAAe,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;KACzC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2CjB;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAanC;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,OAAO,CAAC,kBAAkB;IAgC1B;;OAEG;IACI,OAAO,IAAI,OAAO;IAIzB;;OAEG;IACI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlE;AAED,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"webserver.d.ts","sourceRoot":"","sources":["../../src/webserver/webserver.ts"],"names":[],"mappings":"AACA,OAAgB,EACd,KAAK,eAAe,EAIpB,KAAK,WAAW,EACjB,MAAM,SAAS,CAAC;AAKjB,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAIhC,MAAM,0BAA0B,CAAC;AAMlC,OAAO,KAAK,EAAE,gBAAgB,EAA+B,MAAM,gCAAgC,CAAC;AAGpG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAI1E,OAAO,EAAE,KAAK,eAAe,EAAyC,MAAM,2BAA2B,CAAC;AAExG,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,cAAc;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;CACF;AAED,cAAM,SAAS;IACb,OAAO,CAAC,MAAM,CAAyB;IAEvC,OAAO,CAAC,iBAAiB,CAAoB;IAE7C,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IAEnD,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAmB;IAEpC,aAAa,EAAE,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;IAE3E,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAS;gBAEb,MAAM,EAAE,0BAA0B,GAAG;QAAE,gBAAgB,EAAE,gBAAgB,CAAA;KAAE;IAuDvF;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBlC;;OAEG;YACW,iBAAiB;IAiD/B;;OAEG;IACH,OAAO,CAAC,cAAc;YAeR,QAAQ;YAeR,SAAS;YA8BT,UAAU;YAuCV,OAAO;YAMP,OAAO;IAIrB,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,yBAAyB;IAcjC;;OAEG;YACW,eAAe;YAkPf,uBAAuB;IA4CrC,OAAO,CAAC,oBAAoB;IA8C5B,OAAO,CAAC,YAAY;IA6CP,WAAW,CAAC,EACvB,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,SAAS,EACT,WAAW,EACX,WAAW,EACX,eAAe,GAChB,EAAE;QACD,kBAAkB,EAAE,GAAG,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,WAAW,GAAG,WAAW,EAAE,CAAC;QACzC,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,wBAAwB,CAAC;QACvC,eAAe,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;KACzC,GAAG,OAAO,CAAC,IAAI,CAAC;IA2CjB;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAanC;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlC,OAAO,CAAC,kBAAkB;IAgC1B;;OAEG;IACI,OAAO,IAAI,OAAO;IAIzB;;OAEG;IACI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAGlE;AAED,eAAe,SAAS,CAAC"}
@@ -81,6 +81,8 @@ export interface EntityRouteDefinition {
81
81
  }
82
82
  export interface WebServerLogConfig {
83
83
  startUp?: boolean;
84
+ /** Paths to exclude from request logging (e.g., ['/health', '/health/live', '/health/ready']) */
85
+ excludePaths?: string[];
84
86
  }
85
87
  export interface WebServerDebugOptions {
86
88
  printRoutes?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"webserver.interface.d.ts","sourceRoot":"","sources":["../../src/webserver/webserver.interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webserver.interface.d.ts","sourceRoot":"","sources":["../../src/webserver/webserver.interface.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/webserver/webserver.interface.ts"],
4
- "sourcesContent": ["import type { FastifyReply, FastifyRequest, HTTPMethods, RouteGenericInterface } from 'fastify';\nimport type { DatabaseInstance } from '../database/index.js';\nimport type { QueueManager } from '../queue/index.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { ControllerAction, WebServerBaseControllerType } from './controller/base.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\nimport type { LifecycleManager } from '../lifecycle/lifecycle-manager.js';\nimport type { z } from 'zod';\n\nexport interface RouteSchemaDefinition<\n TParams extends z.ZodTypeAny | undefined = undefined,\n TQuery extends z.ZodTypeAny | undefined = undefined,\n TBody extends z.ZodTypeAny | undefined = undefined,\n TReply extends Record<number | `${number}`, z.ZodTypeAny> | undefined = undefined,\n THeaders extends z.ZodTypeAny | undefined = undefined,\n> {\n params?: TParams;\n querystring?: TQuery;\n body?: TBody;\n response?: TReply;\n headers?: THeaders;\n}\n\ntype InferOrDefault<TZod extends z.ZodTypeAny | undefined, TFallback> = TZod extends z.ZodTypeAny\n ? z.input<TZod>\n : TFallback;\n\ntype InferResponse<TResponse> =\n TResponse extends Record<number | `${number}`, z.ZodTypeAny>\n ? z.output<TResponse[keyof TResponse]>\n : RouteGenericInterface['Reply'];\n\nexport interface RouteHandlerContext<Schema extends RouteSchemaDefinition | undefined = undefined>\n extends RouteGenericInterface {\n Params?: Schema extends RouteSchemaDefinition<infer TParams, any, any, any, any>\n ? InferOrDefault<TParams, RouteGenericInterface['Params']>\n : RouteGenericInterface['Params'];\n Querystring?: Schema extends RouteSchemaDefinition<any, infer TQuery, any, any, any>\n ? InferOrDefault<TQuery, RouteGenericInterface['Querystring']>\n : RouteGenericInterface['Querystring'];\n Body?: Schema extends RouteSchemaDefinition<any, any, infer TBody, any, any>\n ? InferOrDefault<TBody, RouteGenericInterface['Body']>\n : RouteGenericInterface['Body'];\n Headers?: Schema extends RouteSchemaDefinition<any, any, any, any, infer THeaders>\n ? InferOrDefault<THeaders, RouteGenericInterface['Headers']>\n : RouteGenericInterface['Headers'];\n Reply?: Schema extends RouteSchemaDefinition<any, any, any, infer TReply, any>\n ? InferResponse<TReply>\n : RouteGenericInterface['Reply'];\n}\n\nexport type AnyRouteSchemaDefinition = RouteSchemaDefinition<\n z.ZodTypeAny | undefined,\n z.ZodTypeAny | undefined,\n z.ZodTypeAny | undefined,\n Record<number | `${number}`, z.ZodTypeAny> | undefined,\n z.ZodTypeAny | undefined\n>;\n\nexport type RouteHandler<Schema extends RouteSchemaDefinition | undefined = undefined> = (\n request: FastifyRequest<RouteHandlerContext<Schema>>,\n reply: FastifyReply,\n) => Promise<RouteHandlerContext<Schema>['Reply'] | void> | RouteHandlerContext<Schema>['Reply'] | void;\n\nexport interface WebServerConstructorParams {\n /** Application configuration */\n applicationConfig: ApplicationConfig;\n\n /** Web server options */\n options: WebServerOptions;\n\n /** Web server routes */\n routes?: WebServerRoute[];\n\n /** Redis instance */\n redisInstance: RedisInstance;\n\n /** Queue manager */\n queueManager: QueueManager;\n\n /** Event manager */\n eventManager: EventManager;\n\n /** Database instance */\n databaseInstance: DatabaseInstance;\n\n /** Lifecycle manager */\n lifecycleManager: LifecycleManager;\n}\n\nexport enum WebServerRouteType {\n Default = 'default',\n Entity = 'entity',\n}\n\nexport interface BaseWebServerRoute {\n /** Route type */\n type?: WebServerRouteType;\n\n /** Route path */\n path: string;\n\n /** Route controller name */\n controllerName?: string;\n\n /** Route controller */\n controller?: WebServerBaseControllerType;\n\n /** Typed route handler */\n handler?: ControllerAction<any>;\n\n /** Zod-based schema definition */\n schema?: AnyRouteSchemaDefinition;\n}\n\nexport interface DefaultWebServerRoute extends BaseWebServerRoute {\n type: WebServerRouteType.Default;\n\n /** Route method */\n method: HTTPMethods | HTTPMethods[];\n\n /** Route action */\n action?: string;\n}\n\nexport interface EntityWebServerRoute extends BaseWebServerRoute {\n type: WebServerRouteType.Entity;\n\n /** Entity name */\n entityName: string;\n}\n\nexport type WebServerRoute = DefaultWebServerRoute | EntityWebServerRoute;\n\nexport interface EntityRouteDefinition {\n path: string;\n method: HTTPMethods | HTTPMethods[];\n action: string;\n}\n\nexport interface WebServerLogConfig {\n startUp?: boolean;\n}\n\nexport interface WebServerDebugOptions {\n printRoutes?: boolean;\n simulateSlowConnection?: {\n enabled?: boolean;\n delay?: number;\n };\n}\n\nexport interface WebServerCorsBaseOptions {\n /** Whether CORS is enabled */\n enabled: boolean;\n}\n\nexport interface WebServerCorsDisabledOptionsBase {\n enabled: false;\n}\n\nexport interface WebServerCorsEnabledOptionsBase {\n enabled: true;\n}\n\nexport interface WebServerCorsEnabledOptions extends WebServerCorsEnabledOptionsBase {\n urls: string[];\n}\n\nexport type WebServerCorsOptions = WebServerCorsDisabledOptionsBase | WebServerCorsEnabledOptions;\n\nexport interface WebServerErrorsOptions {\n verbose: boolean;\n}\n\nexport interface WebServerSecurityHelmetOptions {\n enabled?: boolean;\n contentSecurityPolicy?: boolean;\n crossOriginEmbedderPolicy?: boolean;\n crossOriginOpenerPolicy?: boolean;\n crossOriginResourcePolicy?: boolean;\n dnsPrefetchControl?: boolean;\n frameguard?: boolean;\n hidePoweredBy?: boolean;\n hsts?: boolean;\n ieNoOpen?: boolean;\n noSniff?: boolean;\n originAgentCluster?: boolean;\n permittedCrossDomainPolicies?: boolean;\n referrerPolicy?: boolean;\n xssFilter?: boolean;\n}\n\nexport interface WebServerSecurityRateLimitOptions {\n enabled?: boolean;\n max?: number;\n timeWindow?: string;\n ban?: number;\n cache?: number;\n}\n\nexport interface WebServerSecurityOptions {\n helmet?: WebServerSecurityHelmetOptions;\n rateLimit?: WebServerSecurityRateLimitOptions;\n}\n\nexport interface WebServerOptions {\n /** Web server host */\n host: string;\n\n /** Web server port */\n port: number;\n\n /** Maximum request body size in bytes (default: 25MB) */\n bodyLimit?: number;\n\n /** Connection timeout in milliseconds (default: 10s) */\n connectionTimeout?: number;\n\n /** Web server CORS options */\n cors?: WebServerCorsOptions;\n\n /** Web server error options */\n errors?: WebServerErrorsOptions;\n\n /** Web server controllers directory */\n controllersDirectory: string;\n\n /** Optional directory containing route definition files */\n routesDirectory?: string;\n\n log?: WebServerLogConfig;\n\n /** Web server security options (helmet, rate limiting) */\n security?: WebServerSecurityOptions;\n\n /** Web server debug options */\n debug?: WebServerDebugOptions;\n}\n\n// export interface WebServerLogParams {\n// /** Method */\n// Method: string;\n\n// /** Path */\n// Path: string;\n\n// /** Status code */\n// Status: number;\n\n// /** IP address */\n// IP?: string;\n\n// /** Execution time */\n// Time?: string;\n\n// [key: string]: unknown;\n// }\n"],
4
+ "sourcesContent": ["import type { FastifyReply, FastifyRequest, HTTPMethods, RouteGenericInterface } from 'fastify';\nimport type { DatabaseInstance } from '../database/index.js';\nimport type { QueueManager } from '../queue/index.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { ControllerAction, WebServerBaseControllerType } from './controller/base.interface.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\nimport type { LifecycleManager } from '../lifecycle/lifecycle-manager.js';\nimport type { z } from 'zod';\n\nexport interface RouteSchemaDefinition<\n TParams extends z.ZodTypeAny | undefined = undefined,\n TQuery extends z.ZodTypeAny | undefined = undefined,\n TBody extends z.ZodTypeAny | undefined = undefined,\n TReply extends Record<number | `${number}`, z.ZodTypeAny> | undefined = undefined,\n THeaders extends z.ZodTypeAny | undefined = undefined,\n> {\n params?: TParams;\n querystring?: TQuery;\n body?: TBody;\n response?: TReply;\n headers?: THeaders;\n}\n\ntype InferOrDefault<TZod extends z.ZodTypeAny | undefined, TFallback> = TZod extends z.ZodTypeAny\n ? z.input<TZod>\n : TFallback;\n\ntype InferResponse<TResponse> =\n TResponse extends Record<number | `${number}`, z.ZodTypeAny>\n ? z.output<TResponse[keyof TResponse]>\n : RouteGenericInterface['Reply'];\n\nexport interface RouteHandlerContext<Schema extends RouteSchemaDefinition | undefined = undefined>\n extends RouteGenericInterface {\n Params?: Schema extends RouteSchemaDefinition<infer TParams, any, any, any, any>\n ? InferOrDefault<TParams, RouteGenericInterface['Params']>\n : RouteGenericInterface['Params'];\n Querystring?: Schema extends RouteSchemaDefinition<any, infer TQuery, any, any, any>\n ? InferOrDefault<TQuery, RouteGenericInterface['Querystring']>\n : RouteGenericInterface['Querystring'];\n Body?: Schema extends RouteSchemaDefinition<any, any, infer TBody, any, any>\n ? InferOrDefault<TBody, RouteGenericInterface['Body']>\n : RouteGenericInterface['Body'];\n Headers?: Schema extends RouteSchemaDefinition<any, any, any, any, infer THeaders>\n ? InferOrDefault<THeaders, RouteGenericInterface['Headers']>\n : RouteGenericInterface['Headers'];\n Reply?: Schema extends RouteSchemaDefinition<any, any, any, infer TReply, any>\n ? InferResponse<TReply>\n : RouteGenericInterface['Reply'];\n}\n\nexport type AnyRouteSchemaDefinition = RouteSchemaDefinition<\n z.ZodTypeAny | undefined,\n z.ZodTypeAny | undefined,\n z.ZodTypeAny | undefined,\n Record<number | `${number}`, z.ZodTypeAny> | undefined,\n z.ZodTypeAny | undefined\n>;\n\nexport type RouteHandler<Schema extends RouteSchemaDefinition | undefined = undefined> = (\n request: FastifyRequest<RouteHandlerContext<Schema>>,\n reply: FastifyReply,\n) => Promise<RouteHandlerContext<Schema>['Reply'] | void> | RouteHandlerContext<Schema>['Reply'] | void;\n\nexport interface WebServerConstructorParams {\n /** Application configuration */\n applicationConfig: ApplicationConfig;\n\n /** Web server options */\n options: WebServerOptions;\n\n /** Web server routes */\n routes?: WebServerRoute[];\n\n /** Redis instance */\n redisInstance: RedisInstance;\n\n /** Queue manager */\n queueManager: QueueManager;\n\n /** Event manager */\n eventManager: EventManager;\n\n /** Database instance */\n databaseInstance: DatabaseInstance;\n\n /** Lifecycle manager */\n lifecycleManager: LifecycleManager;\n}\n\nexport enum WebServerRouteType {\n Default = 'default',\n Entity = 'entity',\n}\n\nexport interface BaseWebServerRoute {\n /** Route type */\n type?: WebServerRouteType;\n\n /** Route path */\n path: string;\n\n /** Route controller name */\n controllerName?: string;\n\n /** Route controller */\n controller?: WebServerBaseControllerType;\n\n /** Typed route handler */\n handler?: ControllerAction<any>;\n\n /** Zod-based schema definition */\n schema?: AnyRouteSchemaDefinition;\n}\n\nexport interface DefaultWebServerRoute extends BaseWebServerRoute {\n type: WebServerRouteType.Default;\n\n /** Route method */\n method: HTTPMethods | HTTPMethods[];\n\n /** Route action */\n action?: string;\n}\n\nexport interface EntityWebServerRoute extends BaseWebServerRoute {\n type: WebServerRouteType.Entity;\n\n /** Entity name */\n entityName: string;\n}\n\nexport type WebServerRoute = DefaultWebServerRoute | EntityWebServerRoute;\n\nexport interface EntityRouteDefinition {\n path: string;\n method: HTTPMethods | HTTPMethods[];\n action: string;\n}\n\nexport interface WebServerLogConfig {\n startUp?: boolean;\n /** Paths to exclude from request logging (e.g., ['/health', '/health/live', '/health/ready']) */\n excludePaths?: string[];\n}\n\nexport interface WebServerDebugOptions {\n printRoutes?: boolean;\n simulateSlowConnection?: {\n enabled?: boolean;\n delay?: number;\n };\n}\n\nexport interface WebServerCorsBaseOptions {\n /** Whether CORS is enabled */\n enabled: boolean;\n}\n\nexport interface WebServerCorsDisabledOptionsBase {\n enabled: false;\n}\n\nexport interface WebServerCorsEnabledOptionsBase {\n enabled: true;\n}\n\nexport interface WebServerCorsEnabledOptions extends WebServerCorsEnabledOptionsBase {\n urls: string[];\n}\n\nexport type WebServerCorsOptions = WebServerCorsDisabledOptionsBase | WebServerCorsEnabledOptions;\n\nexport interface WebServerErrorsOptions {\n verbose: boolean;\n}\n\nexport interface WebServerSecurityHelmetOptions {\n enabled?: boolean;\n contentSecurityPolicy?: boolean;\n crossOriginEmbedderPolicy?: boolean;\n crossOriginOpenerPolicy?: boolean;\n crossOriginResourcePolicy?: boolean;\n dnsPrefetchControl?: boolean;\n frameguard?: boolean;\n hidePoweredBy?: boolean;\n hsts?: boolean;\n ieNoOpen?: boolean;\n noSniff?: boolean;\n originAgentCluster?: boolean;\n permittedCrossDomainPolicies?: boolean;\n referrerPolicy?: boolean;\n xssFilter?: boolean;\n}\n\nexport interface WebServerSecurityRateLimitOptions {\n enabled?: boolean;\n max?: number;\n timeWindow?: string;\n ban?: number;\n cache?: number;\n}\n\nexport interface WebServerSecurityOptions {\n helmet?: WebServerSecurityHelmetOptions;\n rateLimit?: WebServerSecurityRateLimitOptions;\n}\n\nexport interface WebServerOptions {\n /** Web server host */\n host: string;\n\n /** Web server port */\n port: number;\n\n /** Maximum request body size in bytes (default: 25MB) */\n bodyLimit?: number;\n\n /** Connection timeout in milliseconds (default: 10s) */\n connectionTimeout?: number;\n\n /** Web server CORS options */\n cors?: WebServerCorsOptions;\n\n /** Web server error options */\n errors?: WebServerErrorsOptions;\n\n /** Web server controllers directory */\n controllersDirectory: string;\n\n /** Optional directory containing route definition files */\n routesDirectory?: string;\n\n log?: WebServerLogConfig;\n\n /** Web server security options (helmet, rate limiting) */\n security?: WebServerSecurityOptions;\n\n /** Web server debug options */\n debug?: WebServerDebugOptions;\n}\n\n// export interface WebServerLogParams {\n// /** Method */\n// Method: string;\n\n// /** Path */\n// Path: string;\n\n// /** Status code */\n// Status: number;\n\n// /** IP address */\n// IP?: string;\n\n// /** Execution time */\n// Time?: string;\n\n// [key: string]: unknown;\n// }\n"],
5
5
  "mappings": "AA2FO,IAAK,qBAAL,kBAAKA,wBAAL;AACL,EAAAA,oBAAA,aAAU;AACV,EAAAA,oBAAA,YAAS;AAFC,SAAAA;AAAA,GAAA;",
6
6
  "names": ["WebServerRouteType"]
7
7
  }
@@ -157,7 +157,9 @@ class WebServer {
157
157
  }
158
158
  const requestId = request.headers["x-request-id"] ?? crypto.randomUUID();
159
159
  request.requestId = requestId;
160
- const pathsToIgnore = ["/health/live", "/health/ready"];
160
+ const defaultPathsToIgnore = [];
161
+ const configuredExcludePaths = this.options.log?.excludePaths ?? [];
162
+ const pathsToIgnore = [...defaultPathsToIgnore, ...configuredExcludePaths];
161
163
  if (pathsToIgnore.includes(request.url) || request.method === "OPTIONS") {
162
164
  } else {
163
165
  const startTime = Time.now();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/webserver/webserver.ts"],
4
- "sourcesContent": ["import crypto from 'node:crypto';\nimport Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n type FastifySchema,\n type HTTPMethods,\n} from 'fastify';\nimport cors from '@fastify/cors';\nimport helmet from '@fastify/helmet';\nimport rateLimit from '@fastify/rate-limit';\nimport multipart from '@fastify/multipart';\nimport {\n type AnyRouteSchemaDefinition,\n type WebServerConstructorParams,\n type WebServerOptions,\n type WebServerRoute,\n WebServerRouteType,\n} from './webserver.interface.js';\nimport { Logger } from '../logger/index.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport WebServerUtil from './util.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport type { ControllerAction, WebServerBaseControllerType } from './controller/base.interface.js';\nimport type { QueueManager } from '../queue/index.js';\nimport { WebServerHealthController } from '../index.js';\nimport type { LifecycleManager } from '../lifecycle/lifecycle-manager.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\nimport { enterRequestContext } from '../request-context/index.js';\nimport { type ZodTypeProvider, serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n startTime?: number;\n requestId?: string;\n }\n}\n\nclass WebServer {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: WebServerOptions;\n private routes: WebServerRoute[];\n private readonly explicitRoutesConfigured: boolean;\n\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private eventManager: EventManager;\n private databaseInstance: DatabaseInstance;\n\n public fastifyServer: FastifyInstance<any, any, any, any, ZodTypeProvider>;\n\n private lifecycleManager: LifecycleManager;\n private _isReady = false;\n\n constructor(params: WebServerConstructorParams & { lifecycleManager: LifecycleManager }) {\n // Define default options\n const defaultOptions: Partial<WebServerOptions> = {\n host: '0.0.0.0',\n port: 3001,\n cors: {\n enabled: false,\n },\n errors: {\n verbose: false,\n },\n debug: {\n printRoutes: false,\n simulateSlowConnection: {\n enabled: false,\n delay: 250,\n },\n },\n log: {\n startUp: true,\n },\n };\n\n // Merge default options\n const mergedOptions = Helper.defaultsDeep(params.options, defaultOptions);\n\n this.applicationConfig = params.applicationConfig;\n\n this.options = mergedOptions;\n\n const staticRoutes = Array.isArray(params.routes) ? params.routes : [];\n this.explicitRoutesConfigured = Array.isArray(params.routes);\n this.routes = [...staticRoutes];\n\n this.redisInstance = params.redisInstance;\n this.queueManager = params.queueManager;\n this.eventManager = params.eventManager;\n this.databaseInstance = params.databaseInstance;\n this.lifecycleManager = params.lifecycleManager;\n\n // Create Fastify server\n const defaultBodyLimit = 25 * 1024 * 1024; // 25MB (safer default)\n const defaultConnectionTimeout = 10 * 1000; // 10 seconds (safer default)\n\n this.fastifyServer = Fastify({\n logger: false,\n bodyLimit: this.options.bodyLimit ?? defaultBodyLimit,\n connectionTimeout: this.options.connectionTimeout ?? defaultConnectionTimeout,\n }).withTypeProvider<ZodTypeProvider>();\n\n // Set up Zod validators and serializers for automatic schema validation\n this.fastifyServer.setValidatorCompiler(validatorCompiler);\n this.fastifyServer.setSerializerCompiler(serializerCompiler);\n }\n\n /**\n * Load web server.\n */\n public async load(): Promise<void> {\n // Configure security (helmet, rate limiting)\n await this.configureSecurity();\n\n // Configure hooks\n this.configureHooks();\n\n // Configure CORS\n this.configureCORS();\n\n // Configure multipart uploads\n this.configureMultipartUploads();\n\n // Configure routes\n await this.configureRoutes();\n }\n\n /**\n * Configure security features (Helmet, Rate Limiting)\n */\n private async configureSecurity(): Promise<void> {\n const security = this.options.security ?? {};\n\n // Configure Helmet for security headers\n const helmetConfig = security.helmet ?? { enabled: true };\n if (helmetConfig.enabled !== false) {\n await this.fastifyServer.register(helmet, {\n contentSecurityPolicy: helmetConfig.contentSecurityPolicy !== false,\n crossOriginEmbedderPolicy: helmetConfig.crossOriginEmbedderPolicy !== false,\n crossOriginOpenerPolicy: helmetConfig.crossOriginOpenerPolicy !== false,\n crossOriginResourcePolicy: helmetConfig.crossOriginResourcePolicy !== false,\n dnsPrefetchControl: helmetConfig.dnsPrefetchControl !== false,\n frameguard: helmetConfig.frameguard !== false,\n hidePoweredBy: helmetConfig.hidePoweredBy !== false,\n hsts: helmetConfig.hsts !== false,\n ieNoOpen: helmetConfig.ieNoOpen !== false,\n noSniff: helmetConfig.noSniff !== false,\n originAgentCluster: helmetConfig.originAgentCluster !== false,\n permittedCrossDomainPolicies: helmetConfig.permittedCrossDomainPolicies !== false,\n referrerPolicy: helmetConfig.referrerPolicy !== false,\n xssFilter: helmetConfig.xssFilter !== false,\n });\n }\n\n // Configure rate limiting\n const rateLimitConfig = security.rateLimit ?? { enabled: true };\n if (rateLimitConfig.enabled !== false) {\n await this.fastifyServer.register(rateLimit, {\n max: rateLimitConfig.max ?? 1000,\n timeWindow: rateLimitConfig.timeWindow ?? '1 minute',\n ban: rateLimitConfig.ban,\n cache: rateLimitConfig.cache ?? 5000,\n });\n }\n\n // Warn about wildcard CORS in production\n if (process.env.NODE_ENV === 'production' && this.options.cors?.enabled) {\n const corsConfig = this.options.cors as { enabled: true; urls: string[] };\n if (corsConfig.urls?.includes('*')) {\n this.logger.warn({\n message: 'Wildcard CORS (*) is enabled in production - this is a security risk',\n meta: {\n recommendation: 'Specify allowed origins explicitly',\n },\n });\n }\n }\n }\n\n /**\n * Configure hooks.\n */\n private configureHooks(): void {\n this.fastifyServer.addHook('onListen', async () => this.onListen());\n this.fastifyServer.addHook('onRequest', async request => this.onRequest(request));\n this.fastifyServer.addHook('onResponse', async (request, reply) => this.onResponse(request, reply));\n this.fastifyServer.addHook('onError', async (request, reply, error) => this.onError(request, reply, error));\n this.fastifyServer.addHook('onClose', async () => this.onClose());\n\n // if (process.env.NODE_ENV === 'local') {\n // this.fastifyServer.addHook('onSend', (request, reply, payload, done) => {\n // reply.header('Cache-Control', 'no-store');\n // done();\n // });\n // }\n }\n\n private async onListen(): Promise<void> {\n const address = this.fastifyServer.server.address();\n const port = typeof address === 'string' ? address : address?.port;\n\n if (this.options.log?.startUp) {\n this.log('Started', {\n Host: this.options.host,\n Port: port,\n // CORS: this.options.cors?.enabled && this.options.cors?..length > 0 ? this.options.corsUrls.join(', ') : 'Disabled',\n CORS: this.options.cors?.enabled ? this.options.cors.urls.join(', ') : 'Disabled',\n 'Fastify Version': this.fastifyServer.version,\n });\n }\n }\n\n private async onRequest(request: FastifyRequest): Promise<void> {\n if (\n this.options.debug?.simulateSlowConnection?.enabled &&\n this.options.debug?.simulateSlowConnection?.delay &&\n this.options.debug?.simulateSlowConnection?.delay > 0\n ) {\n await new Promise(resolve => setTimeout(resolve, this.options.debug?.simulateSlowConnection?.delay));\n }\n\n // Generate or use existing request ID for correlation\n const requestId = (request.headers['x-request-id'] as string | undefined) ?? crypto.randomUUID();\n request.requestId = requestId;\n\n const pathsToIgnore = ['/health/live', '/health/ready'];\n\n if (pathsToIgnore.includes(request.url) || request.method === 'OPTIONS') {\n // ...\n } else {\n const startTime = Time.now();\n request.startTime = startTime;\n\n // Initialize AsyncLocalStorage context for this request\n // Using enterWith() to set context for the current async execution\n enterRequestContext({ requestId, startTime });\n }\n }\n\n private async onResponse(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n // Add request ID to response headers for client-side correlation\n if (request.requestId) {\n reply.header('X-Request-ID', request.requestId);\n }\n\n if (!request.startTime) {\n return;\n }\n\n const executionTime = Time.calculateElapsedTimeMs({\n startTime: request.startTime,\n });\n const formattedExecutionTime = Time.formatTime({\n time: executionTime,\n numDecimals: 3,\n });\n\n const ip = request.headers['x-forwarded-for'] ?? request.ip;\n\n const logParams: Record<string, unknown> = {\n Method: request.method,\n Path: request.url,\n Status: reply.statusCode,\n };\n\n if (process.env.NODE_ENV !== 'development') {\n logParams.IP = ip.toString();\n }\n\n logParams.Time = formattedExecutionTime;\n\n // if (cluster.isWorker && cluster.worker) {\n // logParams.Worker = cluster.worker.id;\n // }\n\n this.log('API Request', logParams);\n }\n\n private async onError(request: FastifyRequest, reply: FastifyReply, error: Error): Promise<void> {\n // Adjusted for Fastify types\n Logger.error({ error });\n // Implement any additional logic here\n }\n\n private async onClose(): Promise<void> {\n this.log('Stopped');\n }\n\n private configureCORS(): void {\n if (!this.options.cors?.enabled) {\n return;\n }\n\n // Handle wildcard origin for development\n const origin = this.options.cors.urls.includes('*') ? true : this.options.cors.urls;\n\n this.fastifyServer.register(cors, {\n origin,\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization'],\n preflightContinue: false,\n optionsSuccessStatus: 204,\n // credentials: true,\n });\n }\n\n private configureMultipartUploads(): void {\n this.fastifyServer.register(multipart, {\n // attachFieldsToBody: true,\n limits: {\n fieldNameSize: 100,\n fieldSize: 1024 * 1024 * 10,\n fields: 10,\n fileSize: 1024 * 1024 * 1024 * 10, // 10GB file size limit\n files: 1,\n headerPairs: 2000,\n },\n });\n }\n\n /**\n * Configure routes.\n */\n private async configureRoutes(): Promise<void> {\n if (this.options.routesDirectory && this.explicitRoutesConfigured) {\n const baseMessage =\n 'Invalid web server configuration: choose either \"routesDirectory\" for automatic discovery or provide a \"routes\" array.';\n const guidance =\n this.routes.length === 0\n ? ' Remove the empty routes array when using \"routesDirectory\".'\n : ' Remove one of these options so only a single routes source is configured.';\n\n throw new Error(`${baseMessage}${guidance}`);\n }\n\n await this.loadRoutesFromDirectory();\n\n // Check if controllers directory exists\n const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory ?? '');\n\n if (!controllersDirectoryExists) {\n const routesRequiringControllers = this.routes.length === 0 || this.routes.some(route => !route.handler);\n\n if (routesRequiringControllers) {\n Logger.warn({\n message: 'Web server controllers directory not found',\n meta: {\n Directory: this.options.controllersDirectory,\n },\n });\n\n return;\n }\n }\n\n // Load controllers\n const controllers = controllersDirectoryExists\n ? await Loader.loadModulesInDirectory({\n directory: this.options.controllersDirectory,\n extensions: ['.ts', '.js'],\n })\n : {};\n\n // Add health check routes\n this.routes.push(\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/live',\n controller: WebServerHealthController,\n action: 'live',\n },\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/ready',\n controller: WebServerHealthController,\n action: 'ready',\n },\n );\n\n // Go through each route\n for (const route of this.routes) {\n let ControllerClass: WebServerBaseControllerType;\n\n let controllerName;\n\n if (route.handler && !route.controller && !route.controllerName) {\n if (route.type && route.type !== WebServerRouteType.Default) {\n throw new Error('Handler-only routes are only supported for default route type');\n }\n\n if (!('method' in route)) {\n throw new Error('Handler-only routes require an HTTP method');\n }\n\n const schema = this.buildFastifySchema(route.schema);\n\n this.fastifyServer.route({\n method: route.method,\n url: route.path,\n handler: route.handler,\n ...(schema ? { schema } : {}),\n });\n\n continue;\n }\n\n if (route.controller) {\n ControllerClass = route.controller;\n\n controllerName = ControllerClass.name;\n } else if (route.controllerName) {\n ControllerClass = controllers[route.controllerName] as WebServerBaseControllerType;\n\n controllerName = route.controllerName;\n } else {\n throw new Error('Web server controller config not found');\n }\n\n if (typeof ControllerClass !== 'function') {\n const controllerPath = `${this.options.controllersDirectory}/${route.controllerName}.ts`;\n\n Logger.warn({\n message: 'Web server controller not found',\n meta: {\n Controller: route.controllerName,\n Path: controllerPath,\n Route: `${route.path}`,\n },\n });\n\n continue;\n }\n\n // Initialize controller instance\n const controllerInstance = new ControllerClass({\n applicationConfig: this.applicationConfig,\n webServerOptions: this.options,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n eventManager: this.eventManager,\n databaseInstance: this.databaseInstance,\n lifecycleManager: this.lifecycleManager,\n });\n\n let routeMethod;\n let routeAction;\n let routePath;\n\n switch (route.type) {\n case WebServerRouteType.Default: {\n routeMethod = route.method;\n routeAction = route.action;\n routePath = route.path;\n\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeSchema: route.schema,\n handlerOverride: route.handler?.bind(controllerInstance),\n });\n\n break;\n }\n case WebServerRouteType.Entity: {\n if (this.applicationConfig.database?.enabled === true) {\n const entityModel = await Loader.loadEntityModule({\n entitiesDirectory: this.applicationConfig.database.entitiesDirectory,\n entityName: route.entityName,\n });\n\n const entitySchemaSource = (entityModel as { schema?: { describe?: () => unknown } }).schema;\n\n if (entitySchemaSource && typeof entitySchemaSource.describe !== 'function') {\n const reportedType =\n typeof entitySchemaSource === 'object'\n ? (entitySchemaSource?.constructor?.name ?? 'object')\n : typeof entitySchemaSource;\n\n throw new Error(\n `Entity route auto-validation requires a Joi schema with a describe() method. ` +\n `Entity \"${route.entityName}\" provided a ${reportedType}. ` +\n `If you're using Zod (schema/schemaUpdate) for this entity, migrate to the new DynamicEntity helpers or ` +\n `attach typed route validators instead of relying on WebServerRouteType.Entity auto-validation.`,\n );\n }\n\n const entitySchemaDescription =\n typeof entitySchemaSource?.describe === 'function'\n ? (entitySchemaSource.describe() as\n | {\n keys?: Record<string, { type: string; flags?: { presence?: string }; [key: string]: unknown }>;\n [key: string]: unknown;\n }\n | undefined)\n : undefined;\n\n if (\n entitySchemaSource &&\n (entitySchemaDescription === undefined ||\n typeof entitySchemaDescription !== 'object' ||\n !('keys' in entitySchemaDescription))\n ) {\n const detectedType =\n entitySchemaDescription && typeof entitySchemaDescription === 'object'\n ? (entitySchemaDescription.constructor?.name ?? 'object')\n : typeof entitySchemaDescription;\n\n throw new Error(\n `Entity route auto-validation expected Joi.describe() output with a \"keys\" map, ` +\n `but entity \"${route.entityName}\" returned ${detectedType}. ` +\n `This usually means the entity uses Zod schemas. ` +\n `Switch the entity to use DynamicEntity.defineSchemas or provide Joi-based validation for \"${route.path}\".`,\n );\n }\n\n const schemaKeys = entitySchemaDescription?.keys;\n\n const formattedEntityValidationSchema =\n entitySchemaDescription && schemaKeys\n ? {\n type: 'object',\n properties: Object.fromEntries(\n Object.entries(schemaKeys).map(([key, value]) => [key, { type: value.type }]),\n ),\n required: Object.keys(schemaKeys).filter(\n // Dynamic schema inspection of joi describe output; keys are from trusted entity definitions\n // eslint-disable-next-line security/detect-object-injection\n key => schemaKeys[key].flags?.presence === 'required',\n ),\n }\n : {};\n\n const entityRouteDefinitions = WebServerUtil.getEntityRouteDefinitions({\n basePath: route.path,\n entityValidationSchema: formattedEntityValidationSchema,\n });\n\n for (const entityRouteDefinition of entityRouteDefinitions) {\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod: entityRouteDefinition.method,\n routePath: entityRouteDefinition.path,\n routeAction: entityRouteDefinition.action,\n routeSchema: route.schema,\n handlerOverride: route.handler?.bind(controllerInstance),\n });\n }\n }\n\n break;\n }\n }\n }\n\n if (this.options.debug?.printRoutes) {\n this.log(`Routes:\\n${this.fastifyServer.printRoutes()}`);\n }\n }\n\n private async loadRoutesFromDirectory(): Promise<void> {\n const { routesDirectory } = this.options;\n\n if (!routesDirectory) {\n return;\n }\n\n const directoryExists = await File.pathExists(routesDirectory);\n\n if (!directoryExists) {\n this.logger.warn({\n message: 'Web server routes directory not found',\n meta: {\n Directory: routesDirectory,\n },\n });\n\n return;\n }\n\n const routeModules = await Loader.loadModulesInDirectory<\n WebServerRoute | WebServerRoute[] | { routes?: WebServerRoute[] }\n >({\n directory: routesDirectory,\n extensions: ['.ts', '.js'],\n });\n\n const loadedRoutes: WebServerRoute[] = [];\n\n for (const [moduleName, exportedRoutes] of Object.entries(routeModules)) {\n const normalizedRoutes = this.normalizeRouteExport(exportedRoutes, moduleName);\n\n if (normalizedRoutes.length === 0) {\n continue;\n }\n\n loadedRoutes.push(...normalizedRoutes);\n }\n\n if (loadedRoutes.length > 0) {\n this.routes.push(...loadedRoutes);\n }\n }\n\n private normalizeRouteExport(exportedValue: unknown, moduleName: string): WebServerRoute[] {\n const ensureRouteArray = (value: unknown): WebServerRoute[] => {\n if (Array.isArray(value)) {\n return value;\n }\n\n if (value && typeof value === 'object') {\n const maybeRoute = value as { routes?: unknown };\n\n if (Array.isArray(maybeRoute.routes)) {\n return maybeRoute.routes as WebServerRoute[];\n }\n }\n\n return value ? [value as WebServerRoute] : [];\n };\n\n const routeCandidates = ensureRouteArray(exportedValue);\n const validRoutes: WebServerRoute[] = [];\n\n for (const [index, candidate] of routeCandidates.entries()) {\n if (this.isValidRoute(candidate)) {\n validRoutes.push(candidate);\n } else {\n this.logger.warn({\n message: 'Invalid web server route definition skipped',\n meta: {\n Module: moduleName,\n Index: index,\n },\n });\n }\n }\n\n if (validRoutes.length === 0 && routeCandidates.length > 0) {\n this.logger.warn({\n message: 'No valid routes exported from module',\n meta: {\n Module: moduleName,\n },\n });\n }\n\n return validRoutes;\n }\n\n private isValidRoute(route: unknown): route is WebServerRoute {\n if (!route || typeof route !== 'object') {\n return false;\n }\n\n const candidate = route as Record<string, unknown>;\n const routePath = candidate.path;\n\n if (typeof routePath !== 'string' || routePath.length === 0) {\n return false;\n }\n\n const routeType = candidate.type ?? WebServerRouteType.Default;\n\n const controllerProvided =\n typeof candidate.controller === 'function' || typeof candidate.controllerName === 'string';\n const handlerProvided = typeof candidate.handler === 'function';\n\n if (routeType === WebServerRouteType.Entity || routeType === 'entity') {\n return controllerProvided && typeof candidate.entityName === 'string' && candidate.entityName.length > 0;\n }\n\n // For default routes, either controller+action OR handler must be provided\n if (!controllerProvided && !handlerProvided) {\n return false;\n }\n\n const method = candidate.method;\n\n const isValidMethod =\n typeof method === 'string' ||\n (Array.isArray(method) && method.length > 0 && method.every(m => typeof m === 'string'));\n\n // If handler is provided, we don't need action\n if (handlerProvided) {\n return isValidMethod;\n }\n\n // If controller is provided, we need action\n const action = candidate.action;\n const isValidAction = typeof action === 'string' && action.length > 0;\n\n return isValidMethod && isValidAction;\n }\n\n public async defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeSchema,\n handlerOverride,\n }: {\n controllerInstance: any;\n controllerName: string;\n routeMethod: HTTPMethods | HTTPMethods[];\n routePath: string;\n routeAction?: string;\n routeSchema?: AnyRouteSchemaDefinition;\n handlerOverride?: ControllerAction<any>;\n }): Promise<void> {\n let handler = handlerOverride;\n\n if (!handler) {\n if (!routeAction) {\n throw new Error('Route action is required when handler override is not provided');\n }\n\n if (!/^[A-Za-z0-9_]+$/.test(routeAction) || ['__proto__', 'prototype', 'constructor'].includes(routeAction)) {\n throw new Error('Invalid controller action name');\n }\n\n const controllerHandler = controllerInstance[routeAction as keyof typeof controllerInstance];\n\n if (!controllerHandler) {\n Logger.warn({\n message: 'Web server controller action not found',\n meta: {\n Controller: controllerName,\n Action: routeAction,\n },\n });\n\n throw new Error('Web server controller action not found');\n }\n\n handler = controllerHandler.bind(controllerInstance) as ControllerAction<any>;\n }\n\n const fastifySchema = this.buildFastifySchema(routeSchema);\n\n if (!handler) {\n throw new Error('Route handler could not be resolved');\n }\n\n this.fastifyServer.route({\n method: routeMethod,\n url: routePath,\n handler: handler as unknown as (request: FastifyRequest, reply: FastifyReply) => unknown,\n ...(fastifySchema ? { schema: fastifySchema } : {}),\n });\n }\n\n /**\n * Start web server.\n */\n public async start(): Promise<void> {\n try {\n await this.fastifyServer.listen({\n host: this.options.host,\n port: this.options.port,\n });\n this._isReady = true;\n } catch (error) {\n Logger.error({ error });\n throw error;\n }\n }\n\n /**\n * Stop web server.\n */\n public async stop(): Promise<void> {\n this._isReady = false;\n // Close Fastify server\n await this.fastifyServer.close();\n }\n\n private buildFastifySchema(routeSchema?: AnyRouteSchemaDefinition): FastifySchema | undefined {\n if (!routeSchema) {\n return undefined;\n }\n\n const schema: FastifySchema = {};\n\n // With ZodTypeProvider, we can pass Zod schemas directly\n // The type provider handles validation automatically\n if (routeSchema.params) {\n schema.params = routeSchema.params;\n }\n\n if (routeSchema.querystring) {\n schema.querystring = routeSchema.querystring;\n }\n\n if (routeSchema.body) {\n schema.body = routeSchema.body;\n }\n\n if (routeSchema.headers) {\n schema.headers = routeSchema.headers;\n }\n\n if (routeSchema.response) {\n schema.response = routeSchema.response;\n }\n\n return schema;\n }\n\n /**\n * Check if web server is ready to accept traffic.\n */\n public isReady(): boolean {\n return this._isReady && this.fastifyServer.server?.listening === true;\n }\n\n /**\n * Log web server message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'webServer', message, meta });\n }\n}\n\nexport default WebServer;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import crypto from 'node:crypto';\nimport Fastify, {\n type FastifyInstance,\n type FastifyReply,\n type FastifyRequest,\n type FastifySchema,\n type HTTPMethods,\n} from 'fastify';\nimport cors from '@fastify/cors';\nimport helmet from '@fastify/helmet';\nimport rateLimit from '@fastify/rate-limit';\nimport multipart from '@fastify/multipart';\nimport {\n type AnyRouteSchemaDefinition,\n type WebServerConstructorParams,\n type WebServerOptions,\n type WebServerRoute,\n WebServerRouteType,\n} from './webserver.interface.js';\nimport { Logger } from '../logger/index.js';\nimport { File, Helper, Loader, Time } from '../util/index.js';\nimport WebServerUtil from './util.js';\nimport type { RedisInstance } from '../redis/index.js';\nimport type { DatabaseInstance } from '../database/index.js';\nimport type { ControllerAction, WebServerBaseControllerType } from './controller/base.interface.js';\nimport type { QueueManager } from '../queue/index.js';\nimport { WebServerHealthController } from '../index.js';\nimport type { LifecycleManager } from '../lifecycle/lifecycle-manager.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport type EventManager from '../event/manager.js';\nimport { enterRequestContext } from '../request-context/index.js';\nimport { type ZodTypeProvider, serializerCompiler, validatorCompiler } from 'fastify-type-provider-zod';\n\ndeclare module 'fastify' {\n interface FastifyRequest {\n startTime?: number;\n requestId?: string;\n }\n}\n\nclass WebServer {\n private logger: typeof Logger = Logger;\n\n private applicationConfig: ApplicationConfig;\n\n private options: WebServerOptions;\n private routes: WebServerRoute[];\n private readonly explicitRoutesConfigured: boolean;\n\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private eventManager: EventManager;\n private databaseInstance: DatabaseInstance;\n\n public fastifyServer: FastifyInstance<any, any, any, any, ZodTypeProvider>;\n\n private lifecycleManager: LifecycleManager;\n private _isReady = false;\n\n constructor(params: WebServerConstructorParams & { lifecycleManager: LifecycleManager }) {\n // Define default options\n const defaultOptions: Partial<WebServerOptions> = {\n host: '0.0.0.0',\n port: 3001,\n cors: {\n enabled: false,\n },\n errors: {\n verbose: false,\n },\n debug: {\n printRoutes: false,\n simulateSlowConnection: {\n enabled: false,\n delay: 250,\n },\n },\n log: {\n startUp: true,\n },\n };\n\n // Merge default options\n const mergedOptions = Helper.defaultsDeep(params.options, defaultOptions);\n\n this.applicationConfig = params.applicationConfig;\n\n this.options = mergedOptions;\n\n const staticRoutes = Array.isArray(params.routes) ? params.routes : [];\n this.explicitRoutesConfigured = Array.isArray(params.routes);\n this.routes = [...staticRoutes];\n\n this.redisInstance = params.redisInstance;\n this.queueManager = params.queueManager;\n this.eventManager = params.eventManager;\n this.databaseInstance = params.databaseInstance;\n this.lifecycleManager = params.lifecycleManager;\n\n // Create Fastify server\n const defaultBodyLimit = 25 * 1024 * 1024; // 25MB (safer default)\n const defaultConnectionTimeout = 10 * 1000; // 10 seconds (safer default)\n\n this.fastifyServer = Fastify({\n logger: false,\n bodyLimit: this.options.bodyLimit ?? defaultBodyLimit,\n connectionTimeout: this.options.connectionTimeout ?? defaultConnectionTimeout,\n }).withTypeProvider<ZodTypeProvider>();\n\n // Set up Zod validators and serializers for automatic schema validation\n this.fastifyServer.setValidatorCompiler(validatorCompiler);\n this.fastifyServer.setSerializerCompiler(serializerCompiler);\n }\n\n /**\n * Load web server.\n */\n public async load(): Promise<void> {\n // Configure security (helmet, rate limiting)\n await this.configureSecurity();\n\n // Configure hooks\n this.configureHooks();\n\n // Configure CORS\n this.configureCORS();\n\n // Configure multipart uploads\n this.configureMultipartUploads();\n\n // Configure routes\n await this.configureRoutes();\n }\n\n /**\n * Configure security features (Helmet, Rate Limiting)\n */\n private async configureSecurity(): Promise<void> {\n const security = this.options.security ?? {};\n\n // Configure Helmet for security headers\n const helmetConfig = security.helmet ?? { enabled: true };\n if (helmetConfig.enabled !== false) {\n await this.fastifyServer.register(helmet, {\n contentSecurityPolicy: helmetConfig.contentSecurityPolicy !== false,\n crossOriginEmbedderPolicy: helmetConfig.crossOriginEmbedderPolicy !== false,\n crossOriginOpenerPolicy: helmetConfig.crossOriginOpenerPolicy !== false,\n crossOriginResourcePolicy: helmetConfig.crossOriginResourcePolicy !== false,\n dnsPrefetchControl: helmetConfig.dnsPrefetchControl !== false,\n frameguard: helmetConfig.frameguard !== false,\n hidePoweredBy: helmetConfig.hidePoweredBy !== false,\n hsts: helmetConfig.hsts !== false,\n ieNoOpen: helmetConfig.ieNoOpen !== false,\n noSniff: helmetConfig.noSniff !== false,\n originAgentCluster: helmetConfig.originAgentCluster !== false,\n permittedCrossDomainPolicies: helmetConfig.permittedCrossDomainPolicies !== false,\n referrerPolicy: helmetConfig.referrerPolicy !== false,\n xssFilter: helmetConfig.xssFilter !== false,\n });\n }\n\n // Configure rate limiting\n const rateLimitConfig = security.rateLimit ?? { enabled: true };\n if (rateLimitConfig.enabled !== false) {\n await this.fastifyServer.register(rateLimit, {\n max: rateLimitConfig.max ?? 1000,\n timeWindow: rateLimitConfig.timeWindow ?? '1 minute',\n ban: rateLimitConfig.ban,\n cache: rateLimitConfig.cache ?? 5000,\n });\n }\n\n // Warn about wildcard CORS in production\n if (process.env.NODE_ENV === 'production' && this.options.cors?.enabled) {\n const corsConfig = this.options.cors as { enabled: true; urls: string[] };\n if (corsConfig.urls?.includes('*')) {\n this.logger.warn({\n message: 'Wildcard CORS (*) is enabled in production - this is a security risk',\n meta: {\n recommendation: 'Specify allowed origins explicitly',\n },\n });\n }\n }\n }\n\n /**\n * Configure hooks.\n */\n private configureHooks(): void {\n this.fastifyServer.addHook('onListen', async () => this.onListen());\n this.fastifyServer.addHook('onRequest', async request => this.onRequest(request));\n this.fastifyServer.addHook('onResponse', async (request, reply) => this.onResponse(request, reply));\n this.fastifyServer.addHook('onError', async (request, reply, error) => this.onError(request, reply, error));\n this.fastifyServer.addHook('onClose', async () => this.onClose());\n\n // if (process.env.NODE_ENV === 'local') {\n // this.fastifyServer.addHook('onSend', (request, reply, payload, done) => {\n // reply.header('Cache-Control', 'no-store');\n // done();\n // });\n // }\n }\n\n private async onListen(): Promise<void> {\n const address = this.fastifyServer.server.address();\n const port = typeof address === 'string' ? address : address?.port;\n\n if (this.options.log?.startUp) {\n this.log('Started', {\n Host: this.options.host,\n Port: port,\n // CORS: this.options.cors?.enabled && this.options.cors?..length > 0 ? this.options.corsUrls.join(', ') : 'Disabled',\n CORS: this.options.cors?.enabled ? this.options.cors.urls.join(', ') : 'Disabled',\n 'Fastify Version': this.fastifyServer.version,\n });\n }\n }\n\n private async onRequest(request: FastifyRequest): Promise<void> {\n if (\n this.options.debug?.simulateSlowConnection?.enabled &&\n this.options.debug?.simulateSlowConnection?.delay &&\n this.options.debug?.simulateSlowConnection?.delay > 0\n ) {\n await new Promise(resolve => setTimeout(resolve, this.options.debug?.simulateSlowConnection?.delay));\n }\n\n // Generate or use existing request ID for correlation\n const requestId = (request.headers['x-request-id'] as string | undefined) ?? crypto.randomUUID();\n request.requestId = requestId;\n\n // Default health check paths to ignore from logging\n const defaultPathsToIgnore: string[] = [];\n const configuredExcludePaths = this.options.log?.excludePaths ?? [];\n const pathsToIgnore = [...defaultPathsToIgnore, ...configuredExcludePaths];\n\n if (pathsToIgnore.includes(request.url) || request.method === 'OPTIONS') {\n // ...\n } else {\n const startTime = Time.now();\n request.startTime = startTime;\n\n // Initialize AsyncLocalStorage context for this request\n // Using enterWith() to set context for the current async execution\n enterRequestContext({ requestId, startTime });\n }\n }\n\n private async onResponse(request: FastifyRequest, reply: FastifyReply): Promise<void> {\n // Add request ID to response headers for client-side correlation\n if (request.requestId) {\n reply.header('X-Request-ID', request.requestId);\n }\n\n if (!request.startTime) {\n return;\n }\n\n const executionTime = Time.calculateElapsedTimeMs({\n startTime: request.startTime,\n });\n const formattedExecutionTime = Time.formatTime({\n time: executionTime,\n numDecimals: 3,\n });\n\n const ip = request.headers['x-forwarded-for'] ?? request.ip;\n\n const logParams: Record<string, unknown> = {\n Method: request.method,\n Path: request.url,\n Status: reply.statusCode,\n };\n\n if (process.env.NODE_ENV !== 'development') {\n logParams.IP = ip.toString();\n }\n\n logParams.Time = formattedExecutionTime;\n\n // if (cluster.isWorker && cluster.worker) {\n // logParams.Worker = cluster.worker.id;\n // }\n\n this.log('API Request', logParams);\n }\n\n private async onError(request: FastifyRequest, reply: FastifyReply, error: Error): Promise<void> {\n // Adjusted for Fastify types\n Logger.error({ error });\n // Implement any additional logic here\n }\n\n private async onClose(): Promise<void> {\n this.log('Stopped');\n }\n\n private configureCORS(): void {\n if (!this.options.cors?.enabled) {\n return;\n }\n\n // Handle wildcard origin for development\n const origin = this.options.cors.urls.includes('*') ? true : this.options.cors.urls;\n\n this.fastifyServer.register(cors, {\n origin,\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization'],\n preflightContinue: false,\n optionsSuccessStatus: 204,\n // credentials: true,\n });\n }\n\n private configureMultipartUploads(): void {\n this.fastifyServer.register(multipart, {\n // attachFieldsToBody: true,\n limits: {\n fieldNameSize: 100,\n fieldSize: 1024 * 1024 * 10,\n fields: 10,\n fileSize: 1024 * 1024 * 1024 * 10, // 10GB file size limit\n files: 1,\n headerPairs: 2000,\n },\n });\n }\n\n /**\n * Configure routes.\n */\n private async configureRoutes(): Promise<void> {\n if (this.options.routesDirectory && this.explicitRoutesConfigured) {\n const baseMessage =\n 'Invalid web server configuration: choose either \"routesDirectory\" for automatic discovery or provide a \"routes\" array.';\n const guidance =\n this.routes.length === 0\n ? ' Remove the empty routes array when using \"routesDirectory\".'\n : ' Remove one of these options so only a single routes source is configured.';\n\n throw new Error(`${baseMessage}${guidance}`);\n }\n\n await this.loadRoutesFromDirectory();\n\n // Check if controllers directory exists\n const controllersDirectoryExists = await File.pathExists(this.options.controllersDirectory ?? '');\n\n if (!controllersDirectoryExists) {\n const routesRequiringControllers = this.routes.length === 0 || this.routes.some(route => !route.handler);\n\n if (routesRequiringControllers) {\n Logger.warn({\n message: 'Web server controllers directory not found',\n meta: {\n Directory: this.options.controllersDirectory,\n },\n });\n\n return;\n }\n }\n\n // Load controllers\n const controllers = controllersDirectoryExists\n ? await Loader.loadModulesInDirectory({\n directory: this.options.controllersDirectory,\n extensions: ['.ts', '.js'],\n })\n : {};\n\n // Add health check routes\n this.routes.push(\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/live',\n controller: WebServerHealthController,\n action: 'live',\n },\n {\n type: WebServerRouteType.Default,\n method: 'GET',\n path: '/health/ready',\n controller: WebServerHealthController,\n action: 'ready',\n },\n );\n\n // Go through each route\n for (const route of this.routes) {\n let ControllerClass: WebServerBaseControllerType;\n\n let controllerName;\n\n if (route.handler && !route.controller && !route.controllerName) {\n if (route.type && route.type !== WebServerRouteType.Default) {\n throw new Error('Handler-only routes are only supported for default route type');\n }\n\n if (!('method' in route)) {\n throw new Error('Handler-only routes require an HTTP method');\n }\n\n const schema = this.buildFastifySchema(route.schema);\n\n this.fastifyServer.route({\n method: route.method,\n url: route.path,\n handler: route.handler,\n ...(schema ? { schema } : {}),\n });\n\n continue;\n }\n\n if (route.controller) {\n ControllerClass = route.controller;\n\n controllerName = ControllerClass.name;\n } else if (route.controllerName) {\n ControllerClass = controllers[route.controllerName] as WebServerBaseControllerType;\n\n controllerName = route.controllerName;\n } else {\n throw new Error('Web server controller config not found');\n }\n\n if (typeof ControllerClass !== 'function') {\n const controllerPath = `${this.options.controllersDirectory}/${route.controllerName}.ts`;\n\n Logger.warn({\n message: 'Web server controller not found',\n meta: {\n Controller: route.controllerName,\n Path: controllerPath,\n Route: `${route.path}`,\n },\n });\n\n continue;\n }\n\n // Initialize controller instance\n const controllerInstance = new ControllerClass({\n applicationConfig: this.applicationConfig,\n webServerOptions: this.options,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n eventManager: this.eventManager,\n databaseInstance: this.databaseInstance,\n lifecycleManager: this.lifecycleManager,\n });\n\n let routeMethod;\n let routeAction;\n let routePath;\n\n switch (route.type) {\n case WebServerRouteType.Default: {\n routeMethod = route.method;\n routeAction = route.action;\n routePath = route.path;\n\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeSchema: route.schema,\n handlerOverride: route.handler?.bind(controllerInstance),\n });\n\n break;\n }\n case WebServerRouteType.Entity: {\n if (this.applicationConfig.database?.enabled === true) {\n const entityModel = await Loader.loadEntityModule({\n entitiesDirectory: this.applicationConfig.database.entitiesDirectory,\n entityName: route.entityName,\n });\n\n const entitySchemaSource = (entityModel as { schema?: { describe?: () => unknown } }).schema;\n\n if (entitySchemaSource && typeof entitySchemaSource.describe !== 'function') {\n const reportedType =\n typeof entitySchemaSource === 'object'\n ? (entitySchemaSource?.constructor?.name ?? 'object')\n : typeof entitySchemaSource;\n\n throw new Error(\n `Entity route auto-validation requires a Joi schema with a describe() method. ` +\n `Entity \"${route.entityName}\" provided a ${reportedType}. ` +\n `If you're using Zod (schema/schemaUpdate) for this entity, migrate to the new DynamicEntity helpers or ` +\n `attach typed route validators instead of relying on WebServerRouteType.Entity auto-validation.`,\n );\n }\n\n const entitySchemaDescription =\n typeof entitySchemaSource?.describe === 'function'\n ? (entitySchemaSource.describe() as\n | {\n keys?: Record<string, { type: string; flags?: { presence?: string }; [key: string]: unknown }>;\n [key: string]: unknown;\n }\n | undefined)\n : undefined;\n\n if (\n entitySchemaSource &&\n (entitySchemaDescription === undefined ||\n typeof entitySchemaDescription !== 'object' ||\n !('keys' in entitySchemaDescription))\n ) {\n const detectedType =\n entitySchemaDescription && typeof entitySchemaDescription === 'object'\n ? (entitySchemaDescription.constructor?.name ?? 'object')\n : typeof entitySchemaDescription;\n\n throw new Error(\n `Entity route auto-validation expected Joi.describe() output with a \"keys\" map, ` +\n `but entity \"${route.entityName}\" returned ${detectedType}. ` +\n `This usually means the entity uses Zod schemas. ` +\n `Switch the entity to use DynamicEntity.defineSchemas or provide Joi-based validation for \"${route.path}\".`,\n );\n }\n\n const schemaKeys = entitySchemaDescription?.keys;\n\n const formattedEntityValidationSchema =\n entitySchemaDescription && schemaKeys\n ? {\n type: 'object',\n properties: Object.fromEntries(\n Object.entries(schemaKeys).map(([key, value]) => [key, { type: value.type }]),\n ),\n required: Object.keys(schemaKeys).filter(\n // Dynamic schema inspection of joi describe output; keys are from trusted entity definitions\n // eslint-disable-next-line security/detect-object-injection\n key => schemaKeys[key].flags?.presence === 'required',\n ),\n }\n : {};\n\n const entityRouteDefinitions = WebServerUtil.getEntityRouteDefinitions({\n basePath: route.path,\n entityValidationSchema: formattedEntityValidationSchema,\n });\n\n for (const entityRouteDefinition of entityRouteDefinitions) {\n this.defineRoute({\n controllerInstance,\n controllerName,\n routeMethod: entityRouteDefinition.method,\n routePath: entityRouteDefinition.path,\n routeAction: entityRouteDefinition.action,\n routeSchema: route.schema,\n handlerOverride: route.handler?.bind(controllerInstance),\n });\n }\n }\n\n break;\n }\n }\n }\n\n if (this.options.debug?.printRoutes) {\n this.log(`Routes:\\n${this.fastifyServer.printRoutes()}`);\n }\n }\n\n private async loadRoutesFromDirectory(): Promise<void> {\n const { routesDirectory } = this.options;\n\n if (!routesDirectory) {\n return;\n }\n\n const directoryExists = await File.pathExists(routesDirectory);\n\n if (!directoryExists) {\n this.logger.warn({\n message: 'Web server routes directory not found',\n meta: {\n Directory: routesDirectory,\n },\n });\n\n return;\n }\n\n const routeModules = await Loader.loadModulesInDirectory<\n WebServerRoute | WebServerRoute[] | { routes?: WebServerRoute[] }\n >({\n directory: routesDirectory,\n extensions: ['.ts', '.js'],\n });\n\n const loadedRoutes: WebServerRoute[] = [];\n\n for (const [moduleName, exportedRoutes] of Object.entries(routeModules)) {\n const normalizedRoutes = this.normalizeRouteExport(exportedRoutes, moduleName);\n\n if (normalizedRoutes.length === 0) {\n continue;\n }\n\n loadedRoutes.push(...normalizedRoutes);\n }\n\n if (loadedRoutes.length > 0) {\n this.routes.push(...loadedRoutes);\n }\n }\n\n private normalizeRouteExport(exportedValue: unknown, moduleName: string): WebServerRoute[] {\n const ensureRouteArray = (value: unknown): WebServerRoute[] => {\n if (Array.isArray(value)) {\n return value;\n }\n\n if (value && typeof value === 'object') {\n const maybeRoute = value as { routes?: unknown };\n\n if (Array.isArray(maybeRoute.routes)) {\n return maybeRoute.routes as WebServerRoute[];\n }\n }\n\n return value ? [value as WebServerRoute] : [];\n };\n\n const routeCandidates = ensureRouteArray(exportedValue);\n const validRoutes: WebServerRoute[] = [];\n\n for (const [index, candidate] of routeCandidates.entries()) {\n if (this.isValidRoute(candidate)) {\n validRoutes.push(candidate);\n } else {\n this.logger.warn({\n message: 'Invalid web server route definition skipped',\n meta: {\n Module: moduleName,\n Index: index,\n },\n });\n }\n }\n\n if (validRoutes.length === 0 && routeCandidates.length > 0) {\n this.logger.warn({\n message: 'No valid routes exported from module',\n meta: {\n Module: moduleName,\n },\n });\n }\n\n return validRoutes;\n }\n\n private isValidRoute(route: unknown): route is WebServerRoute {\n if (!route || typeof route !== 'object') {\n return false;\n }\n\n const candidate = route as Record<string, unknown>;\n const routePath = candidate.path;\n\n if (typeof routePath !== 'string' || routePath.length === 0) {\n return false;\n }\n\n const routeType = candidate.type ?? WebServerRouteType.Default;\n\n const controllerProvided =\n typeof candidate.controller === 'function' || typeof candidate.controllerName === 'string';\n const handlerProvided = typeof candidate.handler === 'function';\n\n if (routeType === WebServerRouteType.Entity || routeType === 'entity') {\n return controllerProvided && typeof candidate.entityName === 'string' && candidate.entityName.length > 0;\n }\n\n // For default routes, either controller+action OR handler must be provided\n if (!controllerProvided && !handlerProvided) {\n return false;\n }\n\n const method = candidate.method;\n\n const isValidMethod =\n typeof method === 'string' ||\n (Array.isArray(method) && method.length > 0 && method.every(m => typeof m === 'string'));\n\n // If handler is provided, we don't need action\n if (handlerProvided) {\n return isValidMethod;\n }\n\n // If controller is provided, we need action\n const action = candidate.action;\n const isValidAction = typeof action === 'string' && action.length > 0;\n\n return isValidMethod && isValidAction;\n }\n\n public async defineRoute({\n controllerInstance,\n controllerName,\n routeMethod,\n routePath,\n routeAction,\n routeSchema,\n handlerOverride,\n }: {\n controllerInstance: any;\n controllerName: string;\n routeMethod: HTTPMethods | HTTPMethods[];\n routePath: string;\n routeAction?: string;\n routeSchema?: AnyRouteSchemaDefinition;\n handlerOverride?: ControllerAction<any>;\n }): Promise<void> {\n let handler = handlerOverride;\n\n if (!handler) {\n if (!routeAction) {\n throw new Error('Route action is required when handler override is not provided');\n }\n\n if (!/^[A-Za-z0-9_]+$/.test(routeAction) || ['__proto__', 'prototype', 'constructor'].includes(routeAction)) {\n throw new Error('Invalid controller action name');\n }\n\n const controllerHandler = controllerInstance[routeAction as keyof typeof controllerInstance];\n\n if (!controllerHandler) {\n Logger.warn({\n message: 'Web server controller action not found',\n meta: {\n Controller: controllerName,\n Action: routeAction,\n },\n });\n\n throw new Error('Web server controller action not found');\n }\n\n handler = controllerHandler.bind(controllerInstance) as ControllerAction<any>;\n }\n\n const fastifySchema = this.buildFastifySchema(routeSchema);\n\n if (!handler) {\n throw new Error('Route handler could not be resolved');\n }\n\n this.fastifyServer.route({\n method: routeMethod,\n url: routePath,\n handler: handler as unknown as (request: FastifyRequest, reply: FastifyReply) => unknown,\n ...(fastifySchema ? { schema: fastifySchema } : {}),\n });\n }\n\n /**\n * Start web server.\n */\n public async start(): Promise<void> {\n try {\n await this.fastifyServer.listen({\n host: this.options.host,\n port: this.options.port,\n });\n this._isReady = true;\n } catch (error) {\n Logger.error({ error });\n throw error;\n }\n }\n\n /**\n * Stop web server.\n */\n public async stop(): Promise<void> {\n this._isReady = false;\n // Close Fastify server\n await this.fastifyServer.close();\n }\n\n private buildFastifySchema(routeSchema?: AnyRouteSchemaDefinition): FastifySchema | undefined {\n if (!routeSchema) {\n return undefined;\n }\n\n const schema: FastifySchema = {};\n\n // With ZodTypeProvider, we can pass Zod schemas directly\n // The type provider handles validation automatically\n if (routeSchema.params) {\n schema.params = routeSchema.params;\n }\n\n if (routeSchema.querystring) {\n schema.querystring = routeSchema.querystring;\n }\n\n if (routeSchema.body) {\n schema.body = routeSchema.body;\n }\n\n if (routeSchema.headers) {\n schema.headers = routeSchema.headers;\n }\n\n if (routeSchema.response) {\n schema.response = routeSchema.response;\n }\n\n return schema;\n }\n\n /**\n * Check if web server is ready to accept traffic.\n */\n public isReady(): boolean {\n return this._isReady && this.fastifyServer.server?.listening === true;\n }\n\n /**\n * Log web server message\n */\n public log(message: string, meta?: Record<string, unknown>): void {\n this.logger.custom({ level: 'webServer', message, meta });\n }\n}\n\nexport default WebServer;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket-server.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-server.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,7 @@ import logger from "../logger/logger.js";
15
15
  import { WebSocketAuthService } from "./websocket-auth.js";
16
16
  import { File, Loader } from "../util/index.js";
17
17
  import { executeWithMiddleware } from "./subscriber-middleware.js";
18
+ import { runWithContextAsync } from "../request-context/index.js";
18
19
  class WebSocketServer extends WebSocketBase {
19
20
  static {
20
21
  __name(this, "WebSocketServer");
@@ -660,38 +661,40 @@ class WebSocketServer extends WebSocketBase {
660
661
  );
661
662
  }, "handleServerClientDisconnection");
662
663
  handleClientMessage = /* @__PURE__ */ __name(async (ws, message) => {
663
- try {
664
- const clientId = this.clientManager.getClientId({
665
- ws
666
- });
667
- if (!clientId) {
668
- log("Client ID not found when handling server message");
669
- return;
670
- }
671
- const serverMessageResponse = await this.handleServerMessage(ws, message, clientId);
672
- if (serverMessageResponse) {
673
- this.sendClientMessage(ws, {
674
- type: serverMessageResponse.type,
675
- action: serverMessageResponse.action,
676
- response: serverMessageResponse?.response
664
+ return runWithContextAsync(void 0, async () => {
665
+ try {
666
+ const clientId = this.clientManager.getClientId({
667
+ ws
677
668
  });
678
- if (serverMessageResponse?.response && typeof serverMessageResponse.response === "object" && "error" in serverMessageResponse.response) {
679
- Logger.error({
680
- error: serverMessageResponse.response.error,
681
- meta: {
682
- clientId,
683
- type: serverMessageResponse.type,
684
- action: serverMessageResponse.action
685
- }
669
+ if (!clientId) {
670
+ log("Client ID not found when handling server message");
671
+ return;
672
+ }
673
+ const serverMessageResponse = await this.handleServerMessage(ws, message, clientId);
674
+ if (serverMessageResponse) {
675
+ this.sendClientMessage(ws, {
676
+ type: serverMessageResponse.type,
677
+ action: serverMessageResponse.action,
678
+ response: serverMessageResponse?.response
686
679
  });
680
+ if (serverMessageResponse?.response && typeof serverMessageResponse.response === "object" && "error" in serverMessageResponse.response) {
681
+ Logger.error({
682
+ error: serverMessageResponse.response.error,
683
+ meta: {
684
+ clientId,
685
+ type: serverMessageResponse.type,
686
+ action: serverMessageResponse.action
687
+ }
688
+ });
689
+ }
687
690
  }
691
+ } catch (error) {
692
+ Logger.error({ error });
693
+ log("Error handling client message", {
694
+ Error: error
695
+ });
688
696
  }
689
- } catch (error) {
690
- Logger.error({ error });
691
- log("Error handling client message", {
692
- Error: error
693
- });
694
- }
697
+ });
695
698
  }, "handleClientMessage");
696
699
  handleMessageError(clientId, error) {
697
700
  this.redisInstance.publisherClient.publish(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/websocket/websocket-server.ts"],
4
- "sourcesContent": ["import { type RawData, WebSocketServer as WS, WebSocket } from 'ws';\nimport {\n type WebSocketOptions,\n WebSocketRedisSubscriberEvent,\n type WebSocketRoute,\n type WebSocketSubscriberDefinition,\n type WebSocketSubscriberHandlerContext,\n type WebSocketSubscriberMatcher,\n type WebSocketType,\n} from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketServerProps } from './websocket-server.interface.js';\nimport WebSocketClientManager from './websocket-client-manager.js';\nimport { generateClientId, log } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport { Logger } from '../logger/index.js';\nimport path from 'path';\nimport { type WebApplicationConfig, baseDir } from '../index.js';\nimport WebSocketRoomManager from './websocket-room-manager.js';\nimport logger from '../logger/logger.js';\nimport type { FastifyInstance } from 'fastify';\nimport { WebSocketAuthService } from './websocket-auth.js';\nimport { File, Loader } from '../util/index.js';\nimport { executeWithMiddleware } from './subscriber-middleware.js';\n\nexport default class WebSocketServer extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'joinRoom',\n controllerName: 'system',\n },\n {\n type: 'system',\n action: 'leaveRoom',\n controllerName: 'system',\n },\n ];\n\n private server?: WS;\n\n private abortController = new AbortController();\n private workerId: number | null;\n private uniqueInstanceId: string;\n private applicationConfig: WebApplicationConfig;\n private options: WebSocketOptions;\n public clientManager = new WebSocketClientManager();\n private roomManager = new WebSocketRoomManager({\n clientManager: this.clientManager,\n });\n private authService: WebSocketAuthService;\n\n public get rooms() {\n return this.roomManager.rooms;\n }\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private subscriberHandlersByChannel: Map<string, WebSocketSubscriberDefinition[]> = new Map();\n private subscriberMatcherHandlers: WebSocketSubscriberDefinition[] = [];\n private wildcardSubscriberHandlers: WebSocketSubscriberDefinition[] = [];\n\n /** Redis subscriber events */\n private redisSubscriberEvents: string[] = [\n WebSocketRedisSubscriberEvent.ClientConnected,\n WebSocketRedisSubscriberEvent.ClientJoinedRoom,\n WebSocketRedisSubscriberEvent.ClientLeftRoom,\n WebSocketRedisSubscriberEvent.ClientDisconnected,\n WebSocketRedisSubscriberEvent.DisconnectClient,\n WebSocketRedisSubscriberEvent.SendMessage,\n WebSocketRedisSubscriberEvent.SendMessageToAll,\n WebSocketRedisSubscriberEvent.MessageError,\n WebSocketRedisSubscriberEvent.QueueJobCompleted,\n WebSocketRedisSubscriberEvent.QueueJobError,\n WebSocketRedisSubscriberEvent.Custom,\n ];\n\n constructor(props: WebSocketServerProps) {\n super();\n\n this.uniqueInstanceId = props.uniqueInstanceId;\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n this.workerId = props.workerId;\n this.authService = new WebSocketAuthService(props.applicationConfig);\n }\n\n public get type(): WebSocketType {\n return 'server';\n }\n\n private async validateWebSocketAuth(\n url: string,\n ): Promise<{ userId: number; payload: Record<string, unknown> } | null> {\n return this.authService.validateAuth(url);\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'server');\n\n // Configure default routes\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n // Configure custom routes\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n\n await this.loadSubscriberHandlers();\n }\n\n private async loadSubscriberHandlers(): Promise<void> {\n this.subscriberHandlersByChannel.clear();\n this.subscriberMatcherHandlers = [];\n this.wildcardSubscriberHandlers = [];\n\n const config = this.options.subscriberHandlers;\n\n if (!config) {\n return;\n }\n\n const definitions: WebSocketSubscriberDefinition[] = [];\n\n if (config.directory) {\n const directoryExists = await File.pathExists(config.directory);\n\n if (!directoryExists) {\n logger.warn('WebSocket subscriber handlers directory not found', {\n Directory: config.directory,\n });\n } else {\n const modules = await Loader.loadModulesInDirectory<unknown>({\n directory: config.directory,\n extensions: ['.ts', '.js'],\n });\n\n for (const [moduleName, moduleExport] of Object.entries(modules)) {\n definitions.push(\n ...this.normalizeSubscriberExport(moduleExport, {\n source: 'file',\n moduleName,\n directory: config.directory,\n }),\n );\n }\n }\n }\n\n if (Array.isArray(config.handlers)) {\n for (const handler of config.handlers) {\n definitions.push(\n ...this.normalizeSubscriberExport(handler, {\n source: 'inline',\n }),\n );\n }\n }\n\n for (const definition of definitions) {\n this.registerSubscriberDefinition(definition);\n }\n\n if (definitions.length > 0) {\n logger.info('WebSocket subscriber handlers loaded', {\n Channels: Array.from(this.subscriberHandlersByChannel.keys()),\n Matchers: this.subscriberMatcherHandlers.length,\n Wildcards: this.wildcardSubscriberHandlers.length,\n });\n }\n }\n\n private normalizeSubscriberExport(\n value: unknown,\n metadata: { source: 'file' | 'inline'; moduleName?: string; directory?: string },\n ): WebSocketSubscriberDefinition[] {\n if (!value) {\n return [];\n }\n\n if (Array.isArray(value)) {\n return value.flatMap(entry => this.normalizeSubscriberExport(entry, metadata));\n }\n\n if (typeof value === 'function') {\n const moduleChannel = metadata.moduleName ?? value.name ?? 'anonymous';\n\n return [\n {\n name: metadata.moduleName ?? value.name,\n channels: [moduleChannel],\n handle: async context => {\n await value(context);\n },\n },\n ];\n }\n\n if (typeof value === 'object') {\n const definition = this.normalizeSubscriberObject(value as Record<string, unknown>, metadata);\n if (definition) {\n return [definition];\n }\n\n return Object.values(value as Record<string, unknown>).flatMap(entry =>\n this.normalizeSubscriberExport(entry, metadata),\n );\n }\n\n return [];\n }\n\n private normalizeSubscriberObject(\n value: Record<string, unknown>,\n metadata: { source: 'file' | 'inline'; moduleName?: string },\n ): WebSocketSubscriberDefinition | null {\n const handle = value.handle;\n\n if (typeof handle !== 'function') {\n return null;\n }\n\n let channelSource: unknown;\n if (Object.prototype.hasOwnProperty.call(value, 'channel')) {\n channelSource = value.channel;\n } else if (Object.prototype.hasOwnProperty.call(value, 'channels')) {\n channelSource = value.channels;\n }\n\n const channels = this.normalizeChannels(channelSource);\n\n let matcherSource: unknown;\n if (Object.prototype.hasOwnProperty.call(value, 'match')) {\n matcherSource = value.match;\n } else if (Object.prototype.hasOwnProperty.call(value, 'matcher')) {\n matcherSource = value.matcher;\n } else if (Object.prototype.hasOwnProperty.call(value, 'matchers')) {\n matcherSource = value.matchers;\n }\n\n const matchers = this.normalizeMatchers(matcherSource);\n\n if (channels.length === 0 && matchers.length === 0) {\n logger.warn('Skipping WebSocket subscriber handler without channels or matchers', {\n Source: metadata.source,\n Module: metadata.moduleName,\n });\n\n return null;\n }\n\n const definition: WebSocketSubscriberDefinition = {\n name: typeof value.name === 'string' ? value.name : metadata.moduleName,\n description: typeof value.description === 'string' ? value.description : undefined,\n priority: typeof value.priority === 'number' ? value.priority : undefined,\n channels,\n matchers,\n handle: handle as (context: WebSocketSubscriberHandlerContext) => unknown | Promise<unknown>,\n };\n\n return definition;\n }\n\n private normalizeChannels(input: unknown): string[] {\n if (typeof input === 'string') {\n const trimmed = input.trim();\n return trimmed.length > 0 ? [trimmed] : [];\n }\n\n if (Array.isArray(input)) {\n return input\n .filter((channel): channel is string => typeof channel === 'string')\n .map(channel => channel.trim())\n .filter(channel => channel.length > 0);\n }\n\n return [];\n }\n\n private normalizeMatchers(input: unknown): WebSocketSubscriberMatcher[] {\n if (!input) {\n return [];\n }\n\n const matchers: WebSocketSubscriberMatcher[] = [];\n const addMatcher = (matcher: unknown) => {\n if (matcher instanceof RegExp || typeof matcher === 'function') {\n matchers.push(matcher as WebSocketSubscriberMatcher);\n } else if (typeof matcher === 'string') {\n const trimmed = matcher.trim();\n if (trimmed.length > 0) {\n matchers.push(trimmed as WebSocketSubscriberMatcher);\n }\n }\n };\n\n if (Array.isArray(input)) {\n input.forEach(addMatcher);\n } else {\n addMatcher(input);\n }\n\n return matchers;\n }\n\n private registerSubscriberDefinition(definition: WebSocketSubscriberDefinition): void {\n const normalizedPriority = definition.priority ?? 0;\n const channels = definition.channels?.map(channel => channel.trim()).filter(Boolean) ?? [];\n\n const normalizedDefinition: WebSocketSubscriberDefinition = {\n ...definition,\n priority: normalizedPriority,\n channels,\n matchers: definition.matchers ?? [],\n };\n\n if (channels.length === 0 && normalizedDefinition.matchers?.length === 0) {\n logger.warn('Skipping WebSocket subscriber handler registration due to missing filters', {\n Handler: definition.name ?? '(anonymous)',\n });\n\n return;\n }\n\n if (channels.length > 0) {\n for (const channel of channels) {\n if (channel === '*') {\n this.wildcardSubscriberHandlers.push(normalizedDefinition);\n continue;\n }\n\n const channelHandlers = this.subscriberHandlersByChannel.get(channel) ?? [];\n channelHandlers.push(normalizedDefinition);\n this.subscriberHandlersByChannel.set(channel, channelHandlers);\n }\n }\n\n if (normalizedDefinition.matchers && normalizedDefinition.matchers.length > 0) {\n this.subscriberMatcherHandlers.push(normalizedDefinition);\n }\n }\n\n private doesDefinitionMatch(\n definition: WebSocketSubscriberDefinition,\n context: WebSocketSubscriberHandlerContext,\n ): boolean {\n if (!definition.matchers || definition.matchers.length === 0) {\n return false;\n }\n\n return definition.matchers.some(matcher => this.evaluateMatcher(matcher, context));\n }\n\n private evaluateMatcher(matcher: WebSocketSubscriberMatcher, context: WebSocketSubscriberHandlerContext): boolean {\n if (typeof matcher === 'string') {\n if (matcher === '*') {\n return true;\n }\n\n return matcher === context.channel;\n }\n\n if (matcher instanceof RegExp) {\n return matcher.test(context.channel);\n }\n\n try {\n return Boolean(matcher(context));\n } catch (error) {\n logger.error({\n error,\n message: 'WebSocket subscriber matcher threw an error',\n meta: {\n Channel: context.channel,\n Matcher: String(matcher),\n },\n });\n\n return false;\n }\n }\n\n private async executeSubscriberHandlers(channel: string, message: any): Promise<void> {\n if (\n this.subscriberHandlersByChannel.size === 0 &&\n this.subscriberMatcherHandlers.length === 0 &&\n this.wildcardSubscriberHandlers.length === 0\n ) {\n return;\n }\n\n const context: WebSocketSubscriberHandlerContext = {\n channel,\n message,\n webSocketServer: this,\n databaseInstance: this.databaseInstance,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n };\n\n const candidates = new Set<WebSocketSubscriberDefinition>();\n\n const channelHandlers = this.subscriberHandlersByChannel.get(channel);\n\n if (channelHandlers) {\n channelHandlers.forEach(handler => candidates.add(handler));\n }\n\n this.wildcardSubscriberHandlers.forEach(handler => candidates.add(handler));\n\n for (const definition of this.subscriberMatcherHandlers) {\n if (this.doesDefinitionMatch(definition, context)) {\n candidates.add(definition);\n }\n }\n\n if (candidates.size === 0) {\n return;\n }\n\n const orderedHandlers = Array.from(candidates).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n\n for (const handlerDef of orderedHandlers) {\n try {\n // Execute handler with middleware if available\n if (handlerDef.middleware && handlerDef.middleware.length > 0) {\n await executeWithMiddleware(handlerDef.handle, handlerDef.middleware, context);\n } else {\n await handlerDef.handle(context);\n }\n } catch (error) {\n logger.error({\n error,\n message: 'WebSocket subscriber handler failed',\n meta: {\n Handler: handlerDef.name ?? '(anonymous)',\n Channel: channel,\n },\n });\n }\n }\n }\n\n public async start({ fastifyServer }: { fastifyServer: FastifyInstance }): Promise<{ server: WS }> {\n return new Promise(resolve => {\n const server = new WS({\n noServer: true, // We're handling the server externally\n });\n\n this.server = server;\n\n // Ensure this is called after the server has been properly set up\n this.handleServerStart();\n\n fastifyServer.server.on('upgrade', async (request, socket, head) => {\n if (request.url?.startsWith('/ws')) {\n try {\n // Validate authentication token if provided\n const authenticatedUser = await this.validateWebSocketAuth(request.url);\n\n server.handleUpgrade(request, socket, head, ws => {\n server.emit('connection', ws, request, authenticatedUser);\n });\n } catch (error: any) {\n log('WebSocket authentication failed', { error: error.message });\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n }\n } else {\n socket.destroy();\n }\n });\n\n server.on('error', this.handleServerError);\n\n server.on(\n 'connection',\n (ws: WebSocket, request: any, authenticatedUser: { userId: number; payload: any } | null) => {\n this.handleServerClientConnection(ws, authenticatedUser);\n },\n );\n\n // Resolve the promise with the server instance\n resolve({ server });\n });\n }\n\n public async stop(): Promise<void> {\n // Abort all ongoing operations (intervals, etc.)\n this.abortController.abort();\n\n // Clean up Redis subscriber listeners\n this.redisInstance.subscriberClient?.removeListener('message', this.handleSubscriberMessage);\n\n // Unsubscribe from all Redis events\n this.redisSubscriberEvents.forEach(subscriberEventName => {\n this.redisInstance.subscriberClient?.unsubscribe(subscriberEventName);\n });\n\n // Close all client connections and clean up\n if (this.server) {\n this.server.clients.forEach(client => {\n client.removeAllListeners();\n client.close();\n });\n\n this.server.removeAllListeners();\n this.server.close();\n }\n\n // Clean up client manager and room manager\n this.clientManager.cleanup();\n this.roomManager.cleanup();\n\n // Reset managers\n this.clientManager = new WebSocketClientManager();\n this.roomManager = new WebSocketRoomManager({\n clientManager: this.clientManager,\n });\n\n // Create new AbortController for potential restart\n this.abortController = new AbortController();\n\n log('Server stopped');\n }\n\n protected getControllerDependencies(): {\n webSocketServer: WebSocketServer;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n webSocketServer: this,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleServerStart = (): void => {\n if (!this.server) {\n throw new Error('WebSocket server not started');\n }\n\n if (this.options.disconnectInactiveClients?.enabled && this.options.disconnectInactiveClients.intervalCheckTime) {\n // Note: setInterval with signal option requires Node.js 15+\n // TypeScript types may not reflect this, so we use type assertion\n (setInterval as (fn: () => void, ms: number, options?: { signal: AbortSignal }) => NodeJS.Timeout)(\n () => this.checkInactiveClients(),\n this.options.disconnectInactiveClients.intervalCheckTime,\n { signal: this.abortController.signal },\n );\n }\n\n // Go through each event and subscribe to it\n this.redisSubscriberEvents.forEach(subscriberEventName => {\n // Subscribe to event\n this.redisInstance.subscriberClient?.subscribe(subscriberEventName);\n });\n\n // Handle subscriber message\n this.redisInstance.subscriberClient.on('message', this.handleSubscriberMessage);\n\n log('Server started', {\n Host: this.options.host,\n URL: this.options.url,\n });\n\n if (this.options.events?.onServerStarted) {\n this.options.events.onServerStarted({\n webSocketServer: this.server,\n });\n }\n };\n\n /**\n * Handle subscriber message.\n */\n private handleSubscriberMessage = async (channel: string, message: string): Promise<void> => {\n let parsedMessage: { [key: string]: any };\n\n try {\n parsedMessage = JSON.parse(message);\n } catch (error) {\n log('Failed to parse subscriber message', {\n Channel: channel,\n Message: message,\n Error: error,\n });\n\n return;\n }\n\n const includeSender = parsedMessage.includeSender === true;\n\n const isSameWorker = parsedMessage.workerId === this.workerId;\n\n // Check if message is from the same worker\n if (includeSender !== true && isSameWorker) {\n // Ignore the message if it's from the same worker\n return;\n }\n\n log('Incoming subscriber message', {\n Channel: channel,\n // 'Run Same Worker': parsedMessage.includeSender ? 'Yes' : 'No',\n 'Client ID': parsedMessage.clientId ?? '-',\n });\n\n switch (channel) {\n case WebSocketRedisSubscriberEvent.ClientConnected: {\n this.onClientConnect({\n clientId: parsedMessage.clientId,\n lastActivity: parsedMessage.lastActivity,\n user: parsedMessage.user,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.ClientDisconnected: {\n this.onClientDisconnect({\n clientId: parsedMessage.clientId,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.DisconnectClient: {\n const clientToDisconnect = this.clientManager.getClient({\n clientId: parsedMessage.clientId,\n // requireWs: true,\n });\n\n if (clientToDisconnect) {\n this.clientManager.disconnectClient({\n clientId: parsedMessage.clientId,\n });\n\n // Remove client from rooms\n this.roomManager.removeClientFromAllRooms({\n clientId: parsedMessage.clientId,\n });\n }\n\n break;\n }\n case WebSocketRedisSubscriberEvent.ClientJoinedRoom: {\n this.onJoinRoom({\n clientId: parsedMessage.clientId,\n roomName: parsedMessage.roomName,\n userData: parsedMessage.user,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.ClientLeftRoom: {\n this.roomManager.removeClientFromRoom({\n roomName: parsedMessage.room,\n clientId: parsedMessage.clientId,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.SendMessage: {\n break;\n }\n case WebSocketRedisSubscriberEvent.SendMessageToAll: {\n this.broadcastToAllClients({ data: parsedMessage });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.MessageError: {\n this.sendMessageError({\n webSocketClientId: parsedMessage.clientId,\n error: parsedMessage.error,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.QueueJobCompleted: {\n // const parsedMessage = JSON.parse(message);\n\n break;\n }\n case WebSocketRedisSubscriberEvent.QueueJobError: {\n // For queue job errors, merge error information into data field\n parsedMessage.data = {\n ...(parsedMessage.data ?? {}),\n error: parsedMessage.error,\n };\n\n break;\n }\n case WebSocketRedisSubscriberEvent.Custom: {\n // Custom logic is being handled in the app\n\n break;\n }\n default: {\n log('Unknown subscriber message received', {\n Channel: channel,\n Message: message,\n });\n }\n }\n\n await this.executeSubscriberHandlers(channel, parsedMessage);\n };\n\n private handleServerError = (error: Error): void => {\n Logger.error({ error });\n };\n\n private handleServerClientConnection = (\n ws: WebSocket,\n authenticatedUser?: { userId: number; payload: any } | null,\n ): void => {\n const clientId = generateClientId();\n\n const lastActivity = Date.now();\n\n ws.on('message', (message: RawData) => this.handleClientMessage(ws, message));\n\n ws.on('close', () => {\n this.handleServerClientDisconnection(clientId);\n this.clientManager.removeClient(clientId);\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n });\n\n try {\n this.clientManager.addClient({\n clientId,\n ws,\n lastActivity,\n user: authenticatedUser,\n });\n\n // Let other workers know that the client has connected\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientConnected,\n JSON.stringify({\n clientId,\n lastActivity,\n workerId: this.workerId,\n user: authenticatedUser,\n }),\n );\n\n // Send authentication success message if user is authenticated\n if (authenticatedUser) {\n this.sendClientMessage(ws, {\n type: 'auth',\n action: 'authenticated',\n data: {\n userId: authenticatedUser.userId,\n message: 'Authentication successful',\n },\n });\n }\n } catch (error) {\n logger.error({ error });\n }\n };\n\n public leaveRoom({ ws, roomName }: { ws: WebSocket; roomName: string }): void {\n const clientId = this.clientManager.getClientId({ ws });\n\n if (!clientId) {\n log('Client ID not found when removing client from room');\n\n return;\n }\n\n // Check if client is in room\n const clientInRoom = this.roomManager.isClientInRoom({\n clientId,\n roomName,\n });\n\n if (!clientInRoom) {\n log('Client not in room when removing client from room', {\n 'Client ID': clientId || '-',\n 'Room Name': roomName,\n });\n\n return;\n }\n\n this.roomManager.removeClientFromRoom({\n roomName,\n clientId,\n });\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientLeftRoom,\n JSON.stringify({\n clientId,\n room: roomName,\n workerId: this.workerId,\n }),\n );\n\n // Optionally send a message to the client\n this.sendClientMessage(ws, {\n type: 'user',\n action: 'leftRoom',\n data: {\n roomName,\n },\n });\n }\n\n private onClientConnect({\n clientId,\n lastActivity,\n user,\n }: {\n clientId: string;\n lastActivity: number;\n user?: { userId: number; payload: any } | null;\n }): void {\n this.clientManager.addClient({\n clientId,\n ws: null,\n lastActivity,\n user,\n });\n }\n\n private onClientDisconnect({ clientId }: { clientId: string }): void {\n // Set client as disconnected\n this.clientManager.removeClient(clientId);\n\n // Remove client from rooms\n this.roomManager.removeClientFromAllRooms({ clientId });\n }\n\n private handleServerClientDisconnection = (clientId: string): void => {\n const client = this.clientManager.getClient({\n clientId,\n });\n\n if (!client) {\n log('Client not found when handling server client disconnection', {\n 'Client ID': clientId || '-',\n });\n\n return;\n }\n\n this.onClientDisconnect({ clientId });\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientDisconnected,\n JSON.stringify({\n clientId,\n workerId: this.workerId,\n }),\n );\n\n // log('Client disconnected', { ID: clientId });\n };\n\n private handleClientMessage = async (ws: WebSocket, message: RawData): Promise<void> => {\n try {\n const clientId = this.clientManager.getClientId({\n ws,\n });\n\n if (!clientId) {\n log('Client ID not found when handling server message');\n\n return;\n }\n\n // Handle server message\n const serverMessageResponse = await this.handleServerMessage(ws, message, clientId);\n\n if (serverMessageResponse) {\n this.sendClientMessage(ws, {\n type: serverMessageResponse.type,\n action: serverMessageResponse.action,\n response: serverMessageResponse?.response,\n });\n\n if (\n serverMessageResponse?.response &&\n typeof serverMessageResponse.response === 'object' &&\n 'error' in serverMessageResponse.response\n ) {\n // Log error but don't throw to prevent connection disruption\n Logger.error({\n error: serverMessageResponse.response.error,\n meta: {\n clientId,\n type: serverMessageResponse.type,\n action: serverMessageResponse.action,\n },\n });\n }\n }\n } catch (error) {\n Logger.error({ error });\n\n log('Error handling client message', {\n Error: error,\n });\n }\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.MessageError,\n JSON.stringify({\n includeSender: true,\n clientId,\n error,\n }),\n );\n }\n\n /**\n * Check and disconnect inactive clients based on configuration\n * This helps prevent stale connections from accumulating\n */\n private checkInactiveClients(): void {\n const config = this.options.disconnectInactiveClients;\n\n if (!config?.enabled || !config.inactiveTime) {\n return;\n }\n\n if (config.log) {\n log('Checking inactive clients...');\n }\n\n const now = Date.now();\n const clients = this.clientManager.getClients();\n\n for (const client of clients) {\n const inactiveTime = now - client.lastActivity;\n\n if (inactiveTime > config.inactiveTime) {\n this.clientManager.disconnectClient(client.clientId);\n\n if (config.log) {\n log('Disconnected inactive client', {\n 'Client ID': client.clientId,\n 'Inactive Time': `${inactiveTime}ms`,\n });\n }\n }\n }\n }\n\n /**\n * Broadcast a message to all connected WebSocket clients\n * @param data - The data to broadcast (will be JSON stringified)\n * @param excludeClientId - Optional client ID to exclude from broadcast\n * @param predicate - Optional function to filter clients\n */\n public broadcastToAllClients({\n data,\n excludeClientId,\n predicate,\n }: {\n data: { [key: string]: any };\n excludeClientId?: string;\n predicate?: (clientData: { clientId: string; userData: any }) => boolean;\n }): void {\n if (!this.server) {\n log('Server not started when broadcasting to all clients');\n return;\n }\n\n for (const client of this.server.clients) {\n if (client.readyState !== WebSocket.OPEN) {\n continue;\n }\n\n const clientId = this.clientManager.getClientId({ ws: client });\n\n // Skip excluded client if specified\n if (excludeClientId && clientId === excludeClientId) {\n continue;\n }\n\n // Apply custom predicate filter\n if (predicate && clientId) {\n const clientData = this.clientManager.getClient({ clientId });\n if (!clientData || !predicate({ clientId, userData: clientData.user })) {\n continue;\n }\n }\n\n client.send(JSON.stringify(data));\n }\n }\n\n /**\n * Broadcast a message to all clients in a specific room\n * @param roomName - The room to broadcast to\n * @param data - The data to broadcast\n * @param excludeClientId - Optional client ID to exclude from broadcast\n */\n public broadcastToRoom({\n roomName,\n data,\n excludeClientId,\n }: {\n roomName: string;\n data: { [key: string]: any };\n excludeClientId?: string;\n }): void {\n if (!this.server) {\n log('Server not started when broadcasting to room', { roomName });\n return;\n }\n\n const room = this.roomManager.rooms.get(roomName);\n if (!room) {\n log('Room not found when broadcasting', { roomName });\n return;\n }\n\n for (const clientId of room) {\n if (excludeClientId && clientId === excludeClientId) {\n continue;\n }\n\n const client = this.clientManager.getClient({ clientId });\n if (!client?.ws || client.ws.readyState !== WebSocket.OPEN) {\n continue;\n }\n\n client.ws.send(JSON.stringify(data));\n }\n }\n\n /**\n * Broadcast a message to specific users\n * @param userIds - Array of user IDs to broadcast to\n * @param data - The data to broadcast\n */\n public broadcastToUsers({ userIds, data }: { userIds: (string | number)[]; data: { [key: string]: any } }): void {\n if (!this.server) {\n log('Server not started when broadcasting to users');\n return;\n }\n\n const userIdSet = new Set(userIds.map(id => String(id)));\n\n for (const client of this.server.clients) {\n if (client.readyState !== WebSocket.OPEN) {\n continue;\n }\n\n const clientId = this.clientManager.getClientId({ ws: client });\n const clientData = clientId ? this.clientManager.getClient({ clientId }) : null;\n\n if (!clientData?.user) {\n continue;\n }\n\n const clientUserId = String(clientData.user.id ?? clientData.user.userId);\n\n if (userIdSet.has(clientUserId)) {\n client.send(JSON.stringify(data));\n }\n }\n }\n\n /**\n * Broadcast a message to a specific client\n * @param clientId - The client ID to send to\n * @param data - The data to send\n */\n public broadcastToClient({ clientId, data }: { clientId: string; data: { [key: string]: any } }): void {\n const client = this.clientManager.getClient({ clientId });\n\n if (!client?.ws || client.ws.readyState !== WebSocket.OPEN) {\n log('Client not found or not connected when broadcasting to specific client', {\n clientId,\n });\n return;\n }\n\n client.ws.send(JSON.stringify(data));\n }\n\n public sendMessageError({ webSocketClientId, error }: { webSocketClientId: string; error: string }): void {\n const client = this.clientManager.getClient({\n clientId: webSocketClientId,\n });\n\n if (!client) {\n log('Client not found when sending message error', {\n 'Client ID': webSocketClientId || '-',\n Error: error,\n });\n\n return;\n } else if (!client.ws) {\n log('Client WebSocket not found when sending message error', {\n 'Client ID': webSocketClientId || '-',\n Error: error,\n });\n\n return;\n }\n\n this.sendClientMessage(client.ws, {\n type: 'error',\n action: 'message',\n data: {\n error,\n },\n });\n }\n\n // private getClientId({\n // client,\n // }: {\n // client: WebSocket;\n // }): string | undefined {\n // return [...this.connectedClients.entries()].find(\n // ([_, value]) => value.ws === client,\n // )?.[0];\n // }\n\n private onJoinRoom({ clientId, roomName, userData }: { clientId: string; roomName: string; userData: any }): void {\n const client = this.clientManager.getClient({\n clientId,\n });\n\n if (!client) {\n log('Client not found when joining room', {\n 'Client ID': clientId || '-',\n 'Room Name': roomName,\n });\n\n return;\n }\n\n // Check if client can join multiple rooms\n const canJoinMultipleRooms = this.options.rooms?.clientCanJoinMultipleRooms ?? true;\n\n if (!canJoinMultipleRooms && client.roomName) {\n // Remove client from current room before joining new one\n this.roomManager.removeClientFromRoom({\n roomName: client.roomName,\n clientId,\n broadcast: false, // Don't broadcast here, will broadcast after adding to new room\n });\n }\n\n // Update client with user in client manager\n this.clientManager.updateClient({\n clientId,\n key: 'user',\n data: userData,\n });\n\n this.roomManager.addClientToRoom({\n clientId,\n user: userData,\n roomName,\n });\n }\n\n public async joinRoom({\n ws,\n userId,\n userType,\n username,\n roomName,\n }: {\n ws: WebSocket;\n userId?: number;\n userType?: string;\n username?: string;\n roomName: string;\n }) {\n const clientId = this.clientManager.getClientId({ ws });\n\n if (!clientId) {\n // throw new Error('Client ID not found when joining room');\n\n logger.warn({\n message: 'Client ID not found when joining room',\n meta: {\n // 'WebSocket ID': ws?.id || '-',\n 'Room Name': roomName,\n },\n });\n\n return;\n }\n\n // Check if client is already in room\n const isClientInRoom = this.roomManager.isClientInRoom({\n clientId,\n roomName,\n });\n\n if (isClientInRoom) {\n // throw new Error('Client already in room when joining');\n\n logger.warn({\n message: 'Client already in room when joining',\n meta: {\n // 'WebSocket ID': ws?. || '-',\n 'Room Name': roomName,\n 'Client ID': clientId,\n },\n });\n\n return;\n }\n\n let userData: any = {};\n\n // // Get WebSocket client ID\n // const webSocketId = this.clientManager.getClientId({ ws });\n\n if (userId) {\n // Get user email from database\n const dbEntityManager = this.databaseInstance.getEntityManager();\n\n const getUserQuery = 'SELECT email FROM users WHERE id = ?';\n const getUserParams = [userId];\n\n const getUserResult = await dbEntityManager.execute(getUserQuery, getUserParams);\n\n if (!getUserResult || getUserResult.length === 0) {\n throw new Error('User not found in database');\n }\n\n const user = getUserResult[0];\n\n userData = {\n id: userId,\n ...user,\n };\n }\n\n // userData.uniqueId = webSocketId;\n\n if (username) {\n userData.username = username;\n }\n\n userData.userType = userType;\n\n // if user with same email is already connected, disconnect the previous connection\n // const existingClient =\n // this.clientManager.getClientByKey({\n // key: 'user.email',\n // value: user.email,\n // });\n\n // if (existingClient) {\n // if (existingClient.ws) {\n // this.clientManager.disconnectClient({\n // clientId: existingClient.clientId,\n // });\n // } else {\n // // Publish to Redis that we should disconnect this client\n // this.redisInstance.publisherClient.publish(\n // WebSocketRedisSubscriberEvent.DisconnectClient,\n // JSON.stringify({\n // clientId,\n // workerId: this.workerId,\n // }),\n // );\n // }\n // }\n\n this.onJoinRoom({\n clientId,\n roomName,\n userData,\n });\n\n // Let other workers know that the client has joined the room\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientJoinedRoom,\n JSON.stringify({\n clientId,\n user: userData,\n roomName,\n workerId: this.workerId,\n }),\n );\n\n return true;\n }\n\n public sendClientMessage = (ws: WebSocket, data: unknown, binary: boolean = false): void => {\n const webSocketMessage = JSON.stringify(data);\n\n ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = ({ data }: { data: unknown }): void => {\n const formattedData = {\n ...(data as object),\n workerId: this.workerId,\n };\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.SendMessage,\n JSON.stringify(formattedData),\n );\n };\n\n public sendMessageToAll = ({ data }: { data: unknown }): void => {\n const formattedData = {\n ...(data as object),\n workerId: this.workerId,\n };\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.SendMessageToAll,\n JSON.stringify(formattedData),\n );\n };\n\n public sendCustomMessage = ({ data }: { data: unknown }): void => {\n const formattedData = {\n ...(data as object),\n workerId: this.workerId,\n };\n\n this.redisInstance.publisherClient.publish(WebSocketRedisSubscriberEvent.Custom, JSON.stringify(formattedData));\n };\n\n public getClients({ userType }: { userType?: string }): any[] {\n return this.clientManager.getClients({ userType });\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { type RawData, WebSocketServer as WS, WebSocket } from 'ws';\nimport {\n type WebSocketOptions,\n WebSocketRedisSubscriberEvent,\n type WebSocketRoute,\n type WebSocketSubscriberDefinition,\n type WebSocketSubscriberHandlerContext,\n type WebSocketSubscriberMatcher,\n type WebSocketType,\n} from './websocket.interface.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type { WebSocketServerProps } from './websocket-server.interface.js';\nimport WebSocketClientManager from './websocket-client-manager.js';\nimport { generateClientId, log } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport { Logger } from '../logger/index.js';\nimport path from 'path';\nimport { type WebApplicationConfig, baseDir } from '../index.js';\nimport WebSocketRoomManager from './websocket-room-manager.js';\nimport logger from '../logger/logger.js';\nimport type { FastifyInstance } from 'fastify';\nimport { WebSocketAuthService } from './websocket-auth.js';\nimport { File, Loader } from '../util/index.js';\nimport { executeWithMiddleware } from './subscriber-middleware.js';\nimport { runWithContextAsync } from '../request-context/index.js';\n\nexport default class WebSocketServer extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'joinRoom',\n controllerName: 'system',\n },\n {\n type: 'system',\n action: 'leaveRoom',\n controllerName: 'system',\n },\n ];\n\n private server?: WS;\n\n private abortController = new AbortController();\n private workerId: number | null;\n private uniqueInstanceId: string;\n private applicationConfig: WebApplicationConfig;\n private options: WebSocketOptions;\n public clientManager = new WebSocketClientManager();\n private roomManager = new WebSocketRoomManager({\n clientManager: this.clientManager,\n });\n private authService: WebSocketAuthService;\n\n public get rooms() {\n return this.roomManager.rooms;\n }\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private subscriberHandlersByChannel: Map<string, WebSocketSubscriberDefinition[]> = new Map();\n private subscriberMatcherHandlers: WebSocketSubscriberDefinition[] = [];\n private wildcardSubscriberHandlers: WebSocketSubscriberDefinition[] = [];\n\n /** Redis subscriber events */\n private redisSubscriberEvents: string[] = [\n WebSocketRedisSubscriberEvent.ClientConnected,\n WebSocketRedisSubscriberEvent.ClientJoinedRoom,\n WebSocketRedisSubscriberEvent.ClientLeftRoom,\n WebSocketRedisSubscriberEvent.ClientDisconnected,\n WebSocketRedisSubscriberEvent.DisconnectClient,\n WebSocketRedisSubscriberEvent.SendMessage,\n WebSocketRedisSubscriberEvent.SendMessageToAll,\n WebSocketRedisSubscriberEvent.MessageError,\n WebSocketRedisSubscriberEvent.QueueJobCompleted,\n WebSocketRedisSubscriberEvent.QueueJobError,\n WebSocketRedisSubscriberEvent.Custom,\n ];\n\n constructor(props: WebSocketServerProps) {\n super();\n\n this.uniqueInstanceId = props.uniqueInstanceId;\n this.applicationConfig = props.applicationConfig;\n this.options = props.options;\n this.redisInstance = props.redisInstance;\n this.queueManager = props.queueManager;\n this.databaseInstance = props.databaseInstance;\n this.routes = props.routes;\n this.workerId = props.workerId;\n this.authService = new WebSocketAuthService(props.applicationConfig);\n }\n\n public get type(): WebSocketType {\n return 'server';\n }\n\n private async validateWebSocketAuth(\n url: string,\n ): Promise<{ userId: number; payload: Record<string, unknown> } | null> {\n return this.authService.validateAuth(url);\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'server');\n\n // Configure default routes\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n // Configure custom routes\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n\n await this.loadSubscriberHandlers();\n }\n\n private async loadSubscriberHandlers(): Promise<void> {\n this.subscriberHandlersByChannel.clear();\n this.subscriberMatcherHandlers = [];\n this.wildcardSubscriberHandlers = [];\n\n const config = this.options.subscriberHandlers;\n\n if (!config) {\n return;\n }\n\n const definitions: WebSocketSubscriberDefinition[] = [];\n\n if (config.directory) {\n const directoryExists = await File.pathExists(config.directory);\n\n if (!directoryExists) {\n logger.warn('WebSocket subscriber handlers directory not found', {\n Directory: config.directory,\n });\n } else {\n const modules = await Loader.loadModulesInDirectory<unknown>({\n directory: config.directory,\n extensions: ['.ts', '.js'],\n });\n\n for (const [moduleName, moduleExport] of Object.entries(modules)) {\n definitions.push(\n ...this.normalizeSubscriberExport(moduleExport, {\n source: 'file',\n moduleName,\n directory: config.directory,\n }),\n );\n }\n }\n }\n\n if (Array.isArray(config.handlers)) {\n for (const handler of config.handlers) {\n definitions.push(\n ...this.normalizeSubscriberExport(handler, {\n source: 'inline',\n }),\n );\n }\n }\n\n for (const definition of definitions) {\n this.registerSubscriberDefinition(definition);\n }\n\n if (definitions.length > 0) {\n logger.info('WebSocket subscriber handlers loaded', {\n Channels: Array.from(this.subscriberHandlersByChannel.keys()),\n Matchers: this.subscriberMatcherHandlers.length,\n Wildcards: this.wildcardSubscriberHandlers.length,\n });\n }\n }\n\n private normalizeSubscriberExport(\n value: unknown,\n metadata: { source: 'file' | 'inline'; moduleName?: string; directory?: string },\n ): WebSocketSubscriberDefinition[] {\n if (!value) {\n return [];\n }\n\n if (Array.isArray(value)) {\n return value.flatMap(entry => this.normalizeSubscriberExport(entry, metadata));\n }\n\n if (typeof value === 'function') {\n const moduleChannel = metadata.moduleName ?? value.name ?? 'anonymous';\n\n return [\n {\n name: metadata.moduleName ?? value.name,\n channels: [moduleChannel],\n handle: async context => {\n await value(context);\n },\n },\n ];\n }\n\n if (typeof value === 'object') {\n const definition = this.normalizeSubscriberObject(value as Record<string, unknown>, metadata);\n if (definition) {\n return [definition];\n }\n\n return Object.values(value as Record<string, unknown>).flatMap(entry =>\n this.normalizeSubscriberExport(entry, metadata),\n );\n }\n\n return [];\n }\n\n private normalizeSubscriberObject(\n value: Record<string, unknown>,\n metadata: { source: 'file' | 'inline'; moduleName?: string },\n ): WebSocketSubscriberDefinition | null {\n const handle = value.handle;\n\n if (typeof handle !== 'function') {\n return null;\n }\n\n let channelSource: unknown;\n if (Object.prototype.hasOwnProperty.call(value, 'channel')) {\n channelSource = value.channel;\n } else if (Object.prototype.hasOwnProperty.call(value, 'channels')) {\n channelSource = value.channels;\n }\n\n const channels = this.normalizeChannels(channelSource);\n\n let matcherSource: unknown;\n if (Object.prototype.hasOwnProperty.call(value, 'match')) {\n matcherSource = value.match;\n } else if (Object.prototype.hasOwnProperty.call(value, 'matcher')) {\n matcherSource = value.matcher;\n } else if (Object.prototype.hasOwnProperty.call(value, 'matchers')) {\n matcherSource = value.matchers;\n }\n\n const matchers = this.normalizeMatchers(matcherSource);\n\n if (channels.length === 0 && matchers.length === 0) {\n logger.warn('Skipping WebSocket subscriber handler without channels or matchers', {\n Source: metadata.source,\n Module: metadata.moduleName,\n });\n\n return null;\n }\n\n const definition: WebSocketSubscriberDefinition = {\n name: typeof value.name === 'string' ? value.name : metadata.moduleName,\n description: typeof value.description === 'string' ? value.description : undefined,\n priority: typeof value.priority === 'number' ? value.priority : undefined,\n channels,\n matchers,\n handle: handle as (context: WebSocketSubscriberHandlerContext) => unknown | Promise<unknown>,\n };\n\n return definition;\n }\n\n private normalizeChannels(input: unknown): string[] {\n if (typeof input === 'string') {\n const trimmed = input.trim();\n return trimmed.length > 0 ? [trimmed] : [];\n }\n\n if (Array.isArray(input)) {\n return input\n .filter((channel): channel is string => typeof channel === 'string')\n .map(channel => channel.trim())\n .filter(channel => channel.length > 0);\n }\n\n return [];\n }\n\n private normalizeMatchers(input: unknown): WebSocketSubscriberMatcher[] {\n if (!input) {\n return [];\n }\n\n const matchers: WebSocketSubscriberMatcher[] = [];\n const addMatcher = (matcher: unknown) => {\n if (matcher instanceof RegExp || typeof matcher === 'function') {\n matchers.push(matcher as WebSocketSubscriberMatcher);\n } else if (typeof matcher === 'string') {\n const trimmed = matcher.trim();\n if (trimmed.length > 0) {\n matchers.push(trimmed as WebSocketSubscriberMatcher);\n }\n }\n };\n\n if (Array.isArray(input)) {\n input.forEach(addMatcher);\n } else {\n addMatcher(input);\n }\n\n return matchers;\n }\n\n private registerSubscriberDefinition(definition: WebSocketSubscriberDefinition): void {\n const normalizedPriority = definition.priority ?? 0;\n const channels = definition.channels?.map(channel => channel.trim()).filter(Boolean) ?? [];\n\n const normalizedDefinition: WebSocketSubscriberDefinition = {\n ...definition,\n priority: normalizedPriority,\n channels,\n matchers: definition.matchers ?? [],\n };\n\n if (channels.length === 0 && normalizedDefinition.matchers?.length === 0) {\n logger.warn('Skipping WebSocket subscriber handler registration due to missing filters', {\n Handler: definition.name ?? '(anonymous)',\n });\n\n return;\n }\n\n if (channels.length > 0) {\n for (const channel of channels) {\n if (channel === '*') {\n this.wildcardSubscriberHandlers.push(normalizedDefinition);\n continue;\n }\n\n const channelHandlers = this.subscriberHandlersByChannel.get(channel) ?? [];\n channelHandlers.push(normalizedDefinition);\n this.subscriberHandlersByChannel.set(channel, channelHandlers);\n }\n }\n\n if (normalizedDefinition.matchers && normalizedDefinition.matchers.length > 0) {\n this.subscriberMatcherHandlers.push(normalizedDefinition);\n }\n }\n\n private doesDefinitionMatch(\n definition: WebSocketSubscriberDefinition,\n context: WebSocketSubscriberHandlerContext,\n ): boolean {\n if (!definition.matchers || definition.matchers.length === 0) {\n return false;\n }\n\n return definition.matchers.some(matcher => this.evaluateMatcher(matcher, context));\n }\n\n private evaluateMatcher(matcher: WebSocketSubscriberMatcher, context: WebSocketSubscriberHandlerContext): boolean {\n if (typeof matcher === 'string') {\n if (matcher === '*') {\n return true;\n }\n\n return matcher === context.channel;\n }\n\n if (matcher instanceof RegExp) {\n return matcher.test(context.channel);\n }\n\n try {\n return Boolean(matcher(context));\n } catch (error) {\n logger.error({\n error,\n message: 'WebSocket subscriber matcher threw an error',\n meta: {\n Channel: context.channel,\n Matcher: String(matcher),\n },\n });\n\n return false;\n }\n }\n\n private async executeSubscriberHandlers(channel: string, message: any): Promise<void> {\n if (\n this.subscriberHandlersByChannel.size === 0 &&\n this.subscriberMatcherHandlers.length === 0 &&\n this.wildcardSubscriberHandlers.length === 0\n ) {\n return;\n }\n\n const context: WebSocketSubscriberHandlerContext = {\n channel,\n message,\n webSocketServer: this,\n databaseInstance: this.databaseInstance,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n };\n\n const candidates = new Set<WebSocketSubscriberDefinition>();\n\n const channelHandlers = this.subscriberHandlersByChannel.get(channel);\n\n if (channelHandlers) {\n channelHandlers.forEach(handler => candidates.add(handler));\n }\n\n this.wildcardSubscriberHandlers.forEach(handler => candidates.add(handler));\n\n for (const definition of this.subscriberMatcherHandlers) {\n if (this.doesDefinitionMatch(definition, context)) {\n candidates.add(definition);\n }\n }\n\n if (candidates.size === 0) {\n return;\n }\n\n const orderedHandlers = Array.from(candidates).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n\n for (const handlerDef of orderedHandlers) {\n try {\n // Execute handler with middleware if available\n if (handlerDef.middleware && handlerDef.middleware.length > 0) {\n await executeWithMiddleware(handlerDef.handle, handlerDef.middleware, context);\n } else {\n await handlerDef.handle(context);\n }\n } catch (error) {\n logger.error({\n error,\n message: 'WebSocket subscriber handler failed',\n meta: {\n Handler: handlerDef.name ?? '(anonymous)',\n Channel: channel,\n },\n });\n }\n }\n }\n\n public async start({ fastifyServer }: { fastifyServer: FastifyInstance }): Promise<{ server: WS }> {\n return new Promise(resolve => {\n const server = new WS({\n noServer: true, // We're handling the server externally\n });\n\n this.server = server;\n\n // Ensure this is called after the server has been properly set up\n this.handleServerStart();\n\n fastifyServer.server.on('upgrade', async (request, socket, head) => {\n if (request.url?.startsWith('/ws')) {\n try {\n // Validate authentication token if provided\n const authenticatedUser = await this.validateWebSocketAuth(request.url);\n\n server.handleUpgrade(request, socket, head, ws => {\n server.emit('connection', ws, request, authenticatedUser);\n });\n } catch (error: any) {\n log('WebSocket authentication failed', { error: error.message });\n socket.write('HTTP/1.1 401 Unauthorized\\r\\n\\r\\n');\n socket.destroy();\n }\n } else {\n socket.destroy();\n }\n });\n\n server.on('error', this.handleServerError);\n\n server.on(\n 'connection',\n (ws: WebSocket, request: any, authenticatedUser: { userId: number; payload: any } | null) => {\n this.handleServerClientConnection(ws, authenticatedUser);\n },\n );\n\n // Resolve the promise with the server instance\n resolve({ server });\n });\n }\n\n public async stop(): Promise<void> {\n // Abort all ongoing operations (intervals, etc.)\n this.abortController.abort();\n\n // Clean up Redis subscriber listeners\n this.redisInstance.subscriberClient?.removeListener('message', this.handleSubscriberMessage);\n\n // Unsubscribe from all Redis events\n this.redisSubscriberEvents.forEach(subscriberEventName => {\n this.redisInstance.subscriberClient?.unsubscribe(subscriberEventName);\n });\n\n // Close all client connections and clean up\n if (this.server) {\n this.server.clients.forEach(client => {\n client.removeAllListeners();\n client.close();\n });\n\n this.server.removeAllListeners();\n this.server.close();\n }\n\n // Clean up client manager and room manager\n this.clientManager.cleanup();\n this.roomManager.cleanup();\n\n // Reset managers\n this.clientManager = new WebSocketClientManager();\n this.roomManager = new WebSocketRoomManager({\n clientManager: this.clientManager,\n });\n\n // Create new AbortController for potential restart\n this.abortController = new AbortController();\n\n log('Server stopped');\n }\n\n protected getControllerDependencies(): {\n webSocketServer: WebSocketServer;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n webSocketServer: this,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleServerStart = (): void => {\n if (!this.server) {\n throw new Error('WebSocket server not started');\n }\n\n if (this.options.disconnectInactiveClients?.enabled && this.options.disconnectInactiveClients.intervalCheckTime) {\n // Note: setInterval with signal option requires Node.js 15+\n // TypeScript types may not reflect this, so we use type assertion\n (setInterval as (fn: () => void, ms: number, options?: { signal: AbortSignal }) => NodeJS.Timeout)(\n () => this.checkInactiveClients(),\n this.options.disconnectInactiveClients.intervalCheckTime,\n { signal: this.abortController.signal },\n );\n }\n\n // Go through each event and subscribe to it\n this.redisSubscriberEvents.forEach(subscriberEventName => {\n // Subscribe to event\n this.redisInstance.subscriberClient?.subscribe(subscriberEventName);\n });\n\n // Handle subscriber message\n this.redisInstance.subscriberClient.on('message', this.handleSubscriberMessage);\n\n log('Server started', {\n Host: this.options.host,\n URL: this.options.url,\n });\n\n if (this.options.events?.onServerStarted) {\n this.options.events.onServerStarted({\n webSocketServer: this.server,\n });\n }\n };\n\n /**\n * Handle subscriber message.\n */\n private handleSubscriberMessage = async (channel: string, message: string): Promise<void> => {\n let parsedMessage: { [key: string]: any };\n\n try {\n parsedMessage = JSON.parse(message);\n } catch (error) {\n log('Failed to parse subscriber message', {\n Channel: channel,\n Message: message,\n Error: error,\n });\n\n return;\n }\n\n const includeSender = parsedMessage.includeSender === true;\n\n const isSameWorker = parsedMessage.workerId === this.workerId;\n\n // Check if message is from the same worker\n if (includeSender !== true && isSameWorker) {\n // Ignore the message if it's from the same worker\n return;\n }\n\n log('Incoming subscriber message', {\n Channel: channel,\n // 'Run Same Worker': parsedMessage.includeSender ? 'Yes' : 'No',\n 'Client ID': parsedMessage.clientId ?? '-',\n });\n\n switch (channel) {\n case WebSocketRedisSubscriberEvent.ClientConnected: {\n this.onClientConnect({\n clientId: parsedMessage.clientId,\n lastActivity: parsedMessage.lastActivity,\n user: parsedMessage.user,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.ClientDisconnected: {\n this.onClientDisconnect({\n clientId: parsedMessage.clientId,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.DisconnectClient: {\n const clientToDisconnect = this.clientManager.getClient({\n clientId: parsedMessage.clientId,\n // requireWs: true,\n });\n\n if (clientToDisconnect) {\n this.clientManager.disconnectClient({\n clientId: parsedMessage.clientId,\n });\n\n // Remove client from rooms\n this.roomManager.removeClientFromAllRooms({\n clientId: parsedMessage.clientId,\n });\n }\n\n break;\n }\n case WebSocketRedisSubscriberEvent.ClientJoinedRoom: {\n this.onJoinRoom({\n clientId: parsedMessage.clientId,\n roomName: parsedMessage.roomName,\n userData: parsedMessage.user,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.ClientLeftRoom: {\n this.roomManager.removeClientFromRoom({\n roomName: parsedMessage.room,\n clientId: parsedMessage.clientId,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.SendMessage: {\n break;\n }\n case WebSocketRedisSubscriberEvent.SendMessageToAll: {\n this.broadcastToAllClients({ data: parsedMessage });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.MessageError: {\n this.sendMessageError({\n webSocketClientId: parsedMessage.clientId,\n error: parsedMessage.error,\n });\n\n break;\n }\n case WebSocketRedisSubscriberEvent.QueueJobCompleted: {\n // const parsedMessage = JSON.parse(message);\n\n break;\n }\n case WebSocketRedisSubscriberEvent.QueueJobError: {\n // For queue job errors, merge error information into data field\n parsedMessage.data = {\n ...(parsedMessage.data ?? {}),\n error: parsedMessage.error,\n };\n\n break;\n }\n case WebSocketRedisSubscriberEvent.Custom: {\n // Custom logic is being handled in the app\n\n break;\n }\n default: {\n log('Unknown subscriber message received', {\n Channel: channel,\n Message: message,\n });\n }\n }\n\n await this.executeSubscriberHandlers(channel, parsedMessage);\n };\n\n private handleServerError = (error: Error): void => {\n Logger.error({ error });\n };\n\n private handleServerClientConnection = (\n ws: WebSocket,\n authenticatedUser?: { userId: number; payload: any } | null,\n ): void => {\n const clientId = generateClientId();\n\n const lastActivity = Date.now();\n\n ws.on('message', (message: RawData) => this.handleClientMessage(ws, message));\n\n ws.on('close', () => {\n this.handleServerClientDisconnection(clientId);\n this.clientManager.removeClient(clientId);\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n });\n\n try {\n this.clientManager.addClient({\n clientId,\n ws,\n lastActivity,\n user: authenticatedUser,\n });\n\n // Let other workers know that the client has connected\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientConnected,\n JSON.stringify({\n clientId,\n lastActivity,\n workerId: this.workerId,\n user: authenticatedUser,\n }),\n );\n\n // Send authentication success message if user is authenticated\n if (authenticatedUser) {\n this.sendClientMessage(ws, {\n type: 'auth',\n action: 'authenticated',\n data: {\n userId: authenticatedUser.userId,\n message: 'Authentication successful',\n },\n });\n }\n } catch (error) {\n logger.error({ error });\n }\n };\n\n public leaveRoom({ ws, roomName }: { ws: WebSocket; roomName: string }): void {\n const clientId = this.clientManager.getClientId({ ws });\n\n if (!clientId) {\n log('Client ID not found when removing client from room');\n\n return;\n }\n\n // Check if client is in room\n const clientInRoom = this.roomManager.isClientInRoom({\n clientId,\n roomName,\n });\n\n if (!clientInRoom) {\n log('Client not in room when removing client from room', {\n 'Client ID': clientId || '-',\n 'Room Name': roomName,\n });\n\n return;\n }\n\n this.roomManager.removeClientFromRoom({\n roomName,\n clientId,\n });\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientLeftRoom,\n JSON.stringify({\n clientId,\n room: roomName,\n workerId: this.workerId,\n }),\n );\n\n // Optionally send a message to the client\n this.sendClientMessage(ws, {\n type: 'user',\n action: 'leftRoom',\n data: {\n roomName,\n },\n });\n }\n\n private onClientConnect({\n clientId,\n lastActivity,\n user,\n }: {\n clientId: string;\n lastActivity: number;\n user?: { userId: number; payload: any } | null;\n }): void {\n this.clientManager.addClient({\n clientId,\n ws: null,\n lastActivity,\n user,\n });\n }\n\n private onClientDisconnect({ clientId }: { clientId: string }): void {\n // Set client as disconnected\n this.clientManager.removeClient(clientId);\n\n // Remove client from rooms\n this.roomManager.removeClientFromAllRooms({ clientId });\n }\n\n private handleServerClientDisconnection = (clientId: string): void => {\n const client = this.clientManager.getClient({\n clientId,\n });\n\n if (!client) {\n log('Client not found when handling server client disconnection', {\n 'Client ID': clientId || '-',\n });\n\n return;\n }\n\n this.onClientDisconnect({ clientId });\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientDisconnected,\n JSON.stringify({\n clientId,\n workerId: this.workerId,\n }),\n );\n\n // log('Client disconnected', { ID: clientId });\n };\n\n private handleClientMessage = async (ws: WebSocket, message: RawData): Promise<void> => {\n // Run without request context to prevent inheriting HTTP upgrade requestId\n return runWithContextAsync(undefined, async () => {\n try {\n const clientId = this.clientManager.getClientId({\n ws,\n });\n\n if (!clientId) {\n log('Client ID not found when handling server message');\n\n return;\n }\n\n // Handle server message\n const serverMessageResponse = await this.handleServerMessage(ws, message, clientId);\n\n if (serverMessageResponse) {\n this.sendClientMessage(ws, {\n type: serverMessageResponse.type,\n action: serverMessageResponse.action,\n response: serverMessageResponse?.response,\n });\n\n if (\n serverMessageResponse?.response &&\n typeof serverMessageResponse.response === 'object' &&\n 'error' in serverMessageResponse.response\n ) {\n // Log error but don't throw to prevent connection disruption\n Logger.error({\n error: serverMessageResponse.response.error,\n meta: {\n clientId,\n type: serverMessageResponse.type,\n action: serverMessageResponse.action,\n },\n });\n }\n }\n } catch (error) {\n Logger.error({ error });\n\n log('Error handling client message', {\n Error: error,\n });\n }\n });\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.MessageError,\n JSON.stringify({\n includeSender: true,\n clientId,\n error,\n }),\n );\n }\n\n /**\n * Check and disconnect inactive clients based on configuration\n * This helps prevent stale connections from accumulating\n */\n private checkInactiveClients(): void {\n const config = this.options.disconnectInactiveClients;\n\n if (!config?.enabled || !config.inactiveTime) {\n return;\n }\n\n if (config.log) {\n log('Checking inactive clients...');\n }\n\n const now = Date.now();\n const clients = this.clientManager.getClients();\n\n for (const client of clients) {\n const inactiveTime = now - client.lastActivity;\n\n if (inactiveTime > config.inactiveTime) {\n this.clientManager.disconnectClient(client.clientId);\n\n if (config.log) {\n log('Disconnected inactive client', {\n 'Client ID': client.clientId,\n 'Inactive Time': `${inactiveTime}ms`,\n });\n }\n }\n }\n }\n\n /**\n * Broadcast a message to all connected WebSocket clients\n * @param data - The data to broadcast (will be JSON stringified)\n * @param excludeClientId - Optional client ID to exclude from broadcast\n * @param predicate - Optional function to filter clients\n */\n public broadcastToAllClients({\n data,\n excludeClientId,\n predicate,\n }: {\n data: { [key: string]: any };\n excludeClientId?: string;\n predicate?: (clientData: { clientId: string; userData: any }) => boolean;\n }): void {\n if (!this.server) {\n log('Server not started when broadcasting to all clients');\n return;\n }\n\n for (const client of this.server.clients) {\n if (client.readyState !== WebSocket.OPEN) {\n continue;\n }\n\n const clientId = this.clientManager.getClientId({ ws: client });\n\n // Skip excluded client if specified\n if (excludeClientId && clientId === excludeClientId) {\n continue;\n }\n\n // Apply custom predicate filter\n if (predicate && clientId) {\n const clientData = this.clientManager.getClient({ clientId });\n if (!clientData || !predicate({ clientId, userData: clientData.user })) {\n continue;\n }\n }\n\n client.send(JSON.stringify(data));\n }\n }\n\n /**\n * Broadcast a message to all clients in a specific room\n * @param roomName - The room to broadcast to\n * @param data - The data to broadcast\n * @param excludeClientId - Optional client ID to exclude from broadcast\n */\n public broadcastToRoom({\n roomName,\n data,\n excludeClientId,\n }: {\n roomName: string;\n data: { [key: string]: any };\n excludeClientId?: string;\n }): void {\n if (!this.server) {\n log('Server not started when broadcasting to room', { roomName });\n return;\n }\n\n const room = this.roomManager.rooms.get(roomName);\n if (!room) {\n log('Room not found when broadcasting', { roomName });\n return;\n }\n\n for (const clientId of room) {\n if (excludeClientId && clientId === excludeClientId) {\n continue;\n }\n\n const client = this.clientManager.getClient({ clientId });\n if (!client?.ws || client.ws.readyState !== WebSocket.OPEN) {\n continue;\n }\n\n client.ws.send(JSON.stringify(data));\n }\n }\n\n /**\n * Broadcast a message to specific users\n * @param userIds - Array of user IDs to broadcast to\n * @param data - The data to broadcast\n */\n public broadcastToUsers({ userIds, data }: { userIds: (string | number)[]; data: { [key: string]: any } }): void {\n if (!this.server) {\n log('Server not started when broadcasting to users');\n return;\n }\n\n const userIdSet = new Set(userIds.map(id => String(id)));\n\n for (const client of this.server.clients) {\n if (client.readyState !== WebSocket.OPEN) {\n continue;\n }\n\n const clientId = this.clientManager.getClientId({ ws: client });\n const clientData = clientId ? this.clientManager.getClient({ clientId }) : null;\n\n if (!clientData?.user) {\n continue;\n }\n\n const clientUserId = String(clientData.user.id ?? clientData.user.userId);\n\n if (userIdSet.has(clientUserId)) {\n client.send(JSON.stringify(data));\n }\n }\n }\n\n /**\n * Broadcast a message to a specific client\n * @param clientId - The client ID to send to\n * @param data - The data to send\n */\n public broadcastToClient({ clientId, data }: { clientId: string; data: { [key: string]: any } }): void {\n const client = this.clientManager.getClient({ clientId });\n\n if (!client?.ws || client.ws.readyState !== WebSocket.OPEN) {\n log('Client not found or not connected when broadcasting to specific client', {\n clientId,\n });\n return;\n }\n\n client.ws.send(JSON.stringify(data));\n }\n\n public sendMessageError({ webSocketClientId, error }: { webSocketClientId: string; error: string }): void {\n const client = this.clientManager.getClient({\n clientId: webSocketClientId,\n });\n\n if (!client) {\n log('Client not found when sending message error', {\n 'Client ID': webSocketClientId || '-',\n Error: error,\n });\n\n return;\n } else if (!client.ws) {\n log('Client WebSocket not found when sending message error', {\n 'Client ID': webSocketClientId || '-',\n Error: error,\n });\n\n return;\n }\n\n this.sendClientMessage(client.ws, {\n type: 'error',\n action: 'message',\n data: {\n error,\n },\n });\n }\n\n // private getClientId({\n // client,\n // }: {\n // client: WebSocket;\n // }): string | undefined {\n // return [...this.connectedClients.entries()].find(\n // ([_, value]) => value.ws === client,\n // )?.[0];\n // }\n\n private onJoinRoom({ clientId, roomName, userData }: { clientId: string; roomName: string; userData: any }): void {\n const client = this.clientManager.getClient({\n clientId,\n });\n\n if (!client) {\n log('Client not found when joining room', {\n 'Client ID': clientId || '-',\n 'Room Name': roomName,\n });\n\n return;\n }\n\n // Check if client can join multiple rooms\n const canJoinMultipleRooms = this.options.rooms?.clientCanJoinMultipleRooms ?? true;\n\n if (!canJoinMultipleRooms && client.roomName) {\n // Remove client from current room before joining new one\n this.roomManager.removeClientFromRoom({\n roomName: client.roomName,\n clientId,\n broadcast: false, // Don't broadcast here, will broadcast after adding to new room\n });\n }\n\n // Update client with user in client manager\n this.clientManager.updateClient({\n clientId,\n key: 'user',\n data: userData,\n });\n\n this.roomManager.addClientToRoom({\n clientId,\n user: userData,\n roomName,\n });\n }\n\n public async joinRoom({\n ws,\n userId,\n userType,\n username,\n roomName,\n }: {\n ws: WebSocket;\n userId?: number;\n userType?: string;\n username?: string;\n roomName: string;\n }) {\n const clientId = this.clientManager.getClientId({ ws });\n\n if (!clientId) {\n // throw new Error('Client ID not found when joining room');\n\n logger.warn({\n message: 'Client ID not found when joining room',\n meta: {\n // 'WebSocket ID': ws?.id || '-',\n 'Room Name': roomName,\n },\n });\n\n return;\n }\n\n // Check if client is already in room\n const isClientInRoom = this.roomManager.isClientInRoom({\n clientId,\n roomName,\n });\n\n if (isClientInRoom) {\n // throw new Error('Client already in room when joining');\n\n logger.warn({\n message: 'Client already in room when joining',\n meta: {\n // 'WebSocket ID': ws?. || '-',\n 'Room Name': roomName,\n 'Client ID': clientId,\n },\n });\n\n return;\n }\n\n let userData: any = {};\n\n // // Get WebSocket client ID\n // const webSocketId = this.clientManager.getClientId({ ws });\n\n if (userId) {\n // Get user email from database\n const dbEntityManager = this.databaseInstance.getEntityManager();\n\n const getUserQuery = 'SELECT email FROM users WHERE id = ?';\n const getUserParams = [userId];\n\n const getUserResult = await dbEntityManager.execute(getUserQuery, getUserParams);\n\n if (!getUserResult || getUserResult.length === 0) {\n throw new Error('User not found in database');\n }\n\n const user = getUserResult[0];\n\n userData = {\n id: userId,\n ...user,\n };\n }\n\n // userData.uniqueId = webSocketId;\n\n if (username) {\n userData.username = username;\n }\n\n userData.userType = userType;\n\n // if user with same email is already connected, disconnect the previous connection\n // const existingClient =\n // this.clientManager.getClientByKey({\n // key: 'user.email',\n // value: user.email,\n // });\n\n // if (existingClient) {\n // if (existingClient.ws) {\n // this.clientManager.disconnectClient({\n // clientId: existingClient.clientId,\n // });\n // } else {\n // // Publish to Redis that we should disconnect this client\n // this.redisInstance.publisherClient.publish(\n // WebSocketRedisSubscriberEvent.DisconnectClient,\n // JSON.stringify({\n // clientId,\n // workerId: this.workerId,\n // }),\n // );\n // }\n // }\n\n this.onJoinRoom({\n clientId,\n roomName,\n userData,\n });\n\n // Let other workers know that the client has joined the room\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.ClientJoinedRoom,\n JSON.stringify({\n clientId,\n user: userData,\n roomName,\n workerId: this.workerId,\n }),\n );\n\n return true;\n }\n\n public sendClientMessage = (ws: WebSocket, data: unknown, binary: boolean = false): void => {\n const webSocketMessage = JSON.stringify(data);\n\n ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = ({ data }: { data: unknown }): void => {\n const formattedData = {\n ...(data as object),\n workerId: this.workerId,\n };\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.SendMessage,\n JSON.stringify(formattedData),\n );\n };\n\n public sendMessageToAll = ({ data }: { data: unknown }): void => {\n const formattedData = {\n ...(data as object),\n workerId: this.workerId,\n };\n\n this.redisInstance.publisherClient.publish(\n WebSocketRedisSubscriberEvent.SendMessageToAll,\n JSON.stringify(formattedData),\n );\n };\n\n public sendCustomMessage = ({ data }: { data: unknown }): void => {\n const formattedData = {\n ...(data as object),\n workerId: this.workerId,\n };\n\n this.redisInstance.publisherClient.publish(WebSocketRedisSubscriberEvent.Custom, JSON.stringify(formattedData));\n };\n\n public getClients({ userType }: { userType?: string }): any[] {\n return this.clientManager.getClients({ userType });\n }\n}\n"],
5
+ "mappings": ";;AAAA,SAAuB,mBAAmB,IAAI,iBAAiB;AAC/D;AAAA,EAEE;AAAA,OAMK;AAKP,OAAO,4BAA4B;AACnC,SAAS,kBAAkB,WAAW;AACtC,OAAO,mBAAmB;AAC1B,SAAS,cAAc;AACvB,OAAO,UAAU;AACjB,SAAoC,eAAe;AACnD,OAAO,0BAA0B;AACjC,OAAO,YAAY;AAEnB,SAAS,4BAA4B;AACrC,SAAS,MAAM,cAAc;AAC7B,SAAS,6BAA6B;AACtC,SAAS,2BAA2B;AAEpC,MAAO,wBAAsC,cAAc;AAAA,EA5B3D,OA4B2D;AAAA;AAAA;AAAA,EAC/C,gBAAkC;AAAA,IAC1C;AAAA,MACE,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,gBAAgB;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ;AAAA,EAEA,kBAAkB,IAAI,gBAAgB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACD,gBAAgB,IAAI,uBAAuB;AAAA,EAC1C,cAAc,IAAI,qBAAqB;AAAA,IAC7C,eAAe,KAAK;AAAA,EACtB,CAAC;AAAA,EACO;AAAA,EAER,IAAW,QAAQ;AACjB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA,EACQ;AAAA,EACA;AAAA,EACA;AAAA,EACA,8BAA4E,oBAAI,IAAI;AAAA,EACpF,4BAA6D,CAAC;AAAA,EAC9D,6BAA8D,CAAC;AAAA;AAAA,EAG/D,wBAAkC;AAAA,IACxC,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,IAC9B,8BAA8B;AAAA,EAChC;AAAA,EAEA,YAAY,OAA6B;AACvC,UAAM;AAEN,SAAK,mBAAmB,MAAM;AAC9B,SAAK,oBAAoB,MAAM;AAC/B,SAAK,UAAU,MAAM;AACrB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,eAAe,MAAM;AAC1B,SAAK,mBAAmB,MAAM;AAC9B,SAAK,SAAS,MAAM;AACpB,SAAK,WAAW,MAAM;AACtB,SAAK,cAAc,IAAI,qBAAqB,MAAM,iBAAiB;AAAA,EACrE;AAAA,EAEA,IAAW,OAAsB;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,sBACZ,KACsE;AACtE,WAAO,KAAK,YAAY,aAAa,GAAG;AAAA,EAC1C;AAAA,EAEA,MAAa,OAAsB;AACjC,UAAM,8BAA8B,KAAK,KAAK,SAAS,aAAa,eAAe,QAAQ;AAG3F,UAAM,KAAK,gBAAgB,KAAK,eAAe,2BAA2B;AAG1E,UAAM,KAAK,gBAAgB,KAAK,QAAQ,KAAK,QAAQ,oBAAoB;AAEzE,UAAM,KAAK,uBAAuB;AAAA,EACpC;AAAA,EAEA,MAAc,yBAAwC;AACpD,SAAK,4BAA4B,MAAM;AACvC,SAAK,4BAA4B,CAAC;AAClC,SAAK,6BAA6B,CAAC;AAEnC,UAAM,SAAS,KAAK,QAAQ;AAE5B,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,UAAM,cAA+C,CAAC;AAEtD,QAAI,OAAO,WAAW;AACpB,YAAM,kBAAkB,MAAM,KAAK,WAAW,OAAO,SAAS;AAE9D,UAAI,CAAC,iBAAiB;AACpB,eAAO,KAAK,qDAAqD;AAAA,UAC/D,WAAW,OAAO;AAAA,QACpB,CAAC;AAAA,MACH,OAAO;AACL,cAAM,UAAU,MAAM,OAAO,uBAAgC;AAAA,UAC3D,WAAW,OAAO;AAAA,UAClB,YAAY,CAAC,OAAO,KAAK;AAAA,QAC3B,CAAC;AAED,mBAAW,CAAC,YAAY,YAAY,KAAK,OAAO,QAAQ,OAAO,GAAG;AAChE,sBAAY;AAAA,YACV,GAAG,KAAK,0BAA0B,cAAc;AAAA,cAC9C,QAAQ;AAAA,cACR;AAAA,cACA,WAAW,OAAO;AAAA,YACpB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,MAAM,QAAQ,OAAO,QAAQ,GAAG;AAClC,iBAAW,WAAW,OAAO,UAAU;AACrC,oBAAY;AAAA,UACV,GAAG,KAAK,0BAA0B,SAAS;AAAA,YACzC,QAAQ;AAAA,UACV,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,eAAW,cAAc,aAAa;AACpC,WAAK,6BAA6B,UAAU;AAAA,IAC9C;AAEA,QAAI,YAAY,SAAS,GAAG;AAC1B,aAAO,KAAK,wCAAwC;AAAA,QAClD,UAAU,MAAM,KAAK,KAAK,4BAA4B,KAAK,CAAC;AAAA,QAC5D,UAAU,KAAK,0BAA0B;AAAA,QACzC,WAAW,KAAK,2BAA2B;AAAA,MAC7C,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,0BACN,OACA,UACiC;AACjC,QAAI,CAAC,OAAO;AACV,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAO,MAAM,QAAQ,WAAS,KAAK,0BAA0B,OAAO,QAAQ,CAAC;AAAA,IAC/E;AAEA,QAAI,OAAO,UAAU,YAAY;AAC/B,YAAM,gBAAgB,SAAS,cAAc,MAAM,QAAQ;AAE3D,aAAO;AAAA,QACL;AAAA,UACE,MAAM,SAAS,cAAc,MAAM;AAAA,UACnC,UAAU,CAAC,aAAa;AAAA,UACxB,QAAQ,8BAAM,YAAW;AACvB,kBAAM,MAAM,OAAO;AAAA,UACrB,GAFQ;AAAA,QAGV;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,aAAa,KAAK,0BAA0B,OAAkC,QAAQ;AAC5F,UAAI,YAAY;AACd,eAAO,CAAC,UAAU;AAAA,MACpB;AAEA,aAAO,OAAO,OAAO,KAAgC,EAAE;AAAA,QAAQ,WAC7D,KAAK,0BAA0B,OAAO,QAAQ;AAAA,MAChD;AAAA,IACF;AAEA,WAAO,CAAC;AAAA,EACV;AAAA,EAEQ,0BACN,OACA,UACsC;AACtC,UAAM,SAAS,MAAM;AAErB,QAAI,OAAO,WAAW,YAAY;AAChC,aAAO;AAAA,IACT;AAEA,QAAI;AACJ,QAAI,OAAO,UAAU,eAAe,KAAK,OAAO,SAAS,GAAG;AAC1D,sBAAgB,MAAM;AAAA,IACxB,WAAW,OAAO,UAAU,eAAe,KAAK,OAAO,UAAU,GAAG;AAClE,sBAAgB,MAAM;AAAA,IACxB;AAEA,UAAM,WAAW,KAAK,kBAAkB,aAAa;AAErD,QAAI;AACJ,QAAI,OAAO,UAAU,eAAe,KAAK,OAAO,OAAO,GAAG;AACxD,sBAAgB,MAAM;AAAA,IACxB,WAAW,OAAO,UAAU,eAAe,KAAK,OAAO,SAAS,GAAG;AACjE,sBAAgB,MAAM;AAAA,IACxB,WAAW,OAAO,UAAU,eAAe,KAAK,OAAO,UAAU,GAAG;AAClE,sBAAgB,MAAM;AAAA,IACxB;AAEA,UAAM,WAAW,KAAK,kBAAkB,aAAa;AAErD,QAAI,SAAS,WAAW,KAAK,SAAS,WAAW,GAAG;AAClD,aAAO,KAAK,sEAAsE;AAAA,QAChF,QAAQ,SAAS;AAAA,QACjB,QAAQ,SAAS;AAAA,MACnB,CAAC;AAED,aAAO;AAAA,IACT;AAEA,UAAM,aAA4C;AAAA,MAChD,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,SAAS;AAAA,MAC7D,aAAa,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc;AAAA,MACzE,UAAU,OAAO,MAAM,aAAa,WAAW,MAAM,WAAW;AAAA,MAChE;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,OAA0B;AAClD,QAAI,OAAO,UAAU,UAAU;AAC7B,YAAM,UAAU,MAAM,KAAK;AAC3B,aAAO,QAAQ,SAAS,IAAI,CAAC,OAAO,IAAI,CAAC;AAAA,IAC3C;AAEA,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAO,MACJ,OAAO,CAAC,YAA+B,OAAO,YAAY,QAAQ,EAClE,IAAI,aAAW,QAAQ,KAAK,CAAC,EAC7B,OAAO,aAAW,QAAQ,SAAS,CAAC;AAAA,IACzC;AAEA,WAAO,CAAC;AAAA,EACV;AAAA,EAEQ,kBAAkB,OAA8C;AACtE,QAAI,CAAC,OAAO;AACV,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,WAAyC,CAAC;AAChD,UAAM,aAAa,wBAAC,YAAqB;AACvC,UAAI,mBAAmB,UAAU,OAAO,YAAY,YAAY;AAC9D,iBAAS,KAAK,OAAqC;AAAA,MACrD,WAAW,OAAO,YAAY,UAAU;AACtC,cAAM,UAAU,QAAQ,KAAK;AAC7B,YAAI,QAAQ,SAAS,GAAG;AACtB,mBAAS,KAAK,OAAqC;AAAA,QACrD;AAAA,MACF;AAAA,IACF,GATmB;AAWnB,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAM,QAAQ,UAAU;AAAA,IAC1B,OAAO;AACL,iBAAW,KAAK;AAAA,IAClB;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,6BAA6B,YAAiD;AACpF,UAAM,qBAAqB,WAAW,YAAY;AAClD,UAAM,WAAW,WAAW,UAAU,IAAI,aAAW,QAAQ,KAAK,CAAC,EAAE,OAAO,OAAO,KAAK,CAAC;AAEzF,UAAM,uBAAsD;AAAA,MAC1D,GAAG;AAAA,MACH,UAAU;AAAA,MACV;AAAA,MACA,UAAU,WAAW,YAAY,CAAC;AAAA,IACpC;AAEA,QAAI,SAAS,WAAW,KAAK,qBAAqB,UAAU,WAAW,GAAG;AACxE,aAAO,KAAK,6EAA6E;AAAA,QACvF,SAAS,WAAW,QAAQ;AAAA,MAC9B,CAAC;AAED;AAAA,IACF;AAEA,QAAI,SAAS,SAAS,GAAG;AACvB,iBAAW,WAAW,UAAU;AAC9B,YAAI,YAAY,KAAK;AACnB,eAAK,2BAA2B,KAAK,oBAAoB;AACzD;AAAA,QACF;AAEA,cAAM,kBAAkB,KAAK,4BAA4B,IAAI,OAAO,KAAK,CAAC;AAC1E,wBAAgB,KAAK,oBAAoB;AACzC,aAAK,4BAA4B,IAAI,SAAS,eAAe;AAAA,MAC/D;AAAA,IACF;AAEA,QAAI,qBAAqB,YAAY,qBAAqB,SAAS,SAAS,GAAG;AAC7E,WAAK,0BAA0B,KAAK,oBAAoB;AAAA,IAC1D;AAAA,EACF;AAAA,EAEQ,oBACN,YACA,SACS;AACT,QAAI,CAAC,WAAW,YAAY,WAAW,SAAS,WAAW,GAAG;AAC5D,aAAO;AAAA,IACT;AAEA,WAAO,WAAW,SAAS,KAAK,aAAW,KAAK,gBAAgB,SAAS,OAAO,CAAC;AAAA,EACnF;AAAA,EAEQ,gBAAgB,SAAqC,SAAqD;AAChH,QAAI,OAAO,YAAY,UAAU;AAC/B,UAAI,YAAY,KAAK;AACnB,eAAO;AAAA,MACT;AAEA,aAAO,YAAY,QAAQ;AAAA,IAC7B;AAEA,QAAI,mBAAmB,QAAQ;AAC7B,aAAO,QAAQ,KAAK,QAAQ,OAAO;AAAA,IACrC;AAEA,QAAI;AACF,aAAO,QAAQ,QAAQ,OAAO,CAAC;AAAA,IACjC,SAAS,OAAO;AACd,aAAO,MAAM;AAAA,QACX;AAAA,QACA,SAAS;AAAA,QACT,MAAM;AAAA,UACJ,SAAS,QAAQ;AAAA,UACjB,SAAS,OAAO,OAAO;AAAA,QACzB;AAAA,MACF,CAAC;AAED,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,0BAA0B,SAAiB,SAA6B;AACpF,QACE,KAAK,4BAA4B,SAAS,KAC1C,KAAK,0BAA0B,WAAW,KAC1C,KAAK,2BAA2B,WAAW,GAC3C;AACA;AAAA,IACF;AAEA,UAAM,UAA6C;AAAA,MACjD;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,kBAAkB,KAAK;AAAA,MACvB,eAAe,KAAK;AAAA,MACpB,cAAc,KAAK;AAAA,IACrB;AAEA,UAAM,aAAa,oBAAI,IAAmC;AAE1D,UAAM,kBAAkB,KAAK,4BAA4B,IAAI,OAAO;AAEpE,QAAI,iBAAiB;AACnB,sBAAgB,QAAQ,aAAW,WAAW,IAAI,OAAO,CAAC;AAAA,IAC5D;AAEA,SAAK,2BAA2B,QAAQ,aAAW,WAAW,IAAI,OAAO,CAAC;AAE1E,eAAW,cAAc,KAAK,2BAA2B;AACvD,UAAI,KAAK,oBAAoB,YAAY,OAAO,GAAG;AACjD,mBAAW,IAAI,UAAU;AAAA,MAC3B;AAAA,IACF;AAEA,QAAI,WAAW,SAAS,GAAG;AACzB;AAAA,IACF;AAEA,UAAM,kBAAkB,MAAM,KAAK,UAAU,EAAE,KAAK,CAAC,GAAG,OAAO,EAAE,YAAY,MAAM,EAAE,YAAY,EAAE;AAEnG,eAAW,cAAc,iBAAiB;AACxC,UAAI;AAEF,YAAI,WAAW,cAAc,WAAW,WAAW,SAAS,GAAG;AAC7D,gBAAM,sBAAsB,WAAW,QAAQ,WAAW,YAAY,OAAO;AAAA,QAC/E,OAAO;AACL,gBAAM,WAAW,OAAO,OAAO;AAAA,QACjC;AAAA,MACF,SAAS,OAAO;AACd,eAAO,MAAM;AAAA,UACX;AAAA,UACA,SAAS;AAAA,UACT,MAAM;AAAA,YACJ,SAAS,WAAW,QAAQ;AAAA,YAC5B,SAAS;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAa,MAAM,EAAE,cAAc,GAAgE;AACjG,WAAO,IAAI,QAAQ,aAAW;AAC5B,YAAM,SAAS,IAAI,GAAG;AAAA,QACpB,UAAU;AAAA;AAAA,MACZ,CAAC;AAED,WAAK,SAAS;AAGd,WAAK,kBAAkB;AAEvB,oBAAc,OAAO,GAAG,WAAW,OAAO,SAAS,QAAQ,SAAS;AAClE,YAAI,QAAQ,KAAK,WAAW,KAAK,GAAG;AAClC,cAAI;AAEF,kBAAM,oBAAoB,MAAM,KAAK,sBAAsB,QAAQ,GAAG;AAEtE,mBAAO,cAAc,SAAS,QAAQ,MAAM,QAAM;AAChD,qBAAO,KAAK,cAAc,IAAI,SAAS,iBAAiB;AAAA,YAC1D,CAAC;AAAA,UACH,SAAS,OAAY;AACnB,gBAAI,mCAAmC,EAAE,OAAO,MAAM,QAAQ,CAAC;AAC/D,mBAAO,MAAM,mCAAmC;AAChD,mBAAO,QAAQ;AAAA,UACjB;AAAA,QACF,OAAO;AACL,iBAAO,QAAQ;AAAA,QACjB;AAAA,MACF,CAAC;AAED,aAAO,GAAG,SAAS,KAAK,iBAAiB;AAEzC,aAAO;AAAA,QACL;AAAA,QACA,CAAC,IAAe,SAAc,sBAA+D;AAC3F,eAAK,6BAA6B,IAAI,iBAAiB;AAAA,QACzD;AAAA,MACF;AAGA,cAAQ,EAAE,OAAO,CAAC;AAAA,IACpB,CAAC;AAAA,EACH;AAAA,EAEA,MAAa,OAAsB;AAEjC,SAAK,gBAAgB,MAAM;AAG3B,SAAK,cAAc,kBAAkB,eAAe,WAAW,KAAK,uBAAuB;AAG3F,SAAK,sBAAsB,QAAQ,yBAAuB;AACxD,WAAK,cAAc,kBAAkB,YAAY,mBAAmB;AAAA,IACtE,CAAC;AAGD,QAAI,KAAK,QAAQ;AACf,WAAK,OAAO,QAAQ,QAAQ,YAAU;AACpC,eAAO,mBAAmB;AAC1B,eAAO,MAAM;AAAA,MACf,CAAC;AAED,WAAK,OAAO,mBAAmB;AAC/B,WAAK,OAAO,MAAM;AAAA,IACpB;AAGA,SAAK,cAAc,QAAQ;AAC3B,SAAK,YAAY,QAAQ;AAGzB,SAAK,gBAAgB,IAAI,uBAAuB;AAChD,SAAK,cAAc,IAAI,qBAAqB;AAAA,MAC1C,eAAe,KAAK;AAAA,IACtB,CAAC;AAGD,SAAK,kBAAkB,IAAI,gBAAgB;AAE3C,QAAI,gBAAgB;AAAA,EACtB;AAAA,EAEU,4BAKR;AACA,WAAO;AAAA,MACL,iBAAiB;AAAA,MACjB,eAAe,KAAK;AAAA,MACpB,cAAc,KAAK;AAAA,MACnB,kBAAkB,KAAK;AAAA,IACzB;AAAA,EACF;AAAA,EAEU,oBAA6B;AACrC,WAAO,KAAK,QAAQ,OAAO,eAAe;AAAA,EAC5C;AAAA,EAEQ,oBAAoB,6BAAY;AACtC,QAAI,CAAC,KAAK,QAAQ;AAChB,YAAM,IAAI,MAAM,8BAA8B;AAAA,IAChD;AAEA,QAAI,KAAK,QAAQ,2BAA2B,WAAW,KAAK,QAAQ,0BAA0B,mBAAmB;AAG/G,MAAC;AAAA,QACC,MAAM,KAAK,qBAAqB;AAAA,QAChC,KAAK,QAAQ,0BAA0B;AAAA,QACvC,EAAE,QAAQ,KAAK,gBAAgB,OAAO;AAAA,MACxC;AAAA,IACF;AAGA,SAAK,sBAAsB,QAAQ,yBAAuB;AAExD,WAAK,cAAc,kBAAkB,UAAU,mBAAmB;AAAA,IACpE,CAAC;AAGD,SAAK,cAAc,iBAAiB,GAAG,WAAW,KAAK,uBAAuB;AAE9E,QAAI,kBAAkB;AAAA,MACpB,MAAM,KAAK,QAAQ;AAAA,MACnB,KAAK,KAAK,QAAQ;AAAA,IACpB,CAAC;AAED,QAAI,KAAK,QAAQ,QAAQ,iBAAiB;AACxC,WAAK,QAAQ,OAAO,gBAAgB;AAAA,QAClC,iBAAiB,KAAK;AAAA,MACxB,CAAC;AAAA,IACH;AAAA,EACF,GAlC4B;AAAA;AAAA;AAAA;AAAA,EAuCpB,0BAA0B,8BAAO,SAAiB,YAAmC;AAC3F,QAAI;AAEJ,QAAI;AACF,sBAAgB,KAAK,MAAM,OAAO;AAAA,IACpC,SAAS,OAAO;AACd,UAAI,sCAAsC;AAAA,QACxC,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,MACT,CAAC;AAED;AAAA,IACF;AAEA,UAAM,gBAAgB,cAAc,kBAAkB;AAEtD,UAAM,eAAe,cAAc,aAAa,KAAK;AAGrD,QAAI,kBAAkB,QAAQ,cAAc;AAE1C;AAAA,IACF;AAEA,QAAI,+BAA+B;AAAA,MACjC,SAAS;AAAA;AAAA,MAET,aAAa,cAAc,YAAY;AAAA,IACzC,CAAC;AAED,YAAQ,SAAS;AAAA,MACf,KAAK,8BAA8B,iBAAiB;AAClD,aAAK,gBAAgB;AAAA,UACnB,UAAU,cAAc;AAAA,UACxB,cAAc,cAAc;AAAA,UAC5B,MAAM,cAAc;AAAA,QACtB,CAAC;AAED;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,oBAAoB;AACrD,aAAK,mBAAmB;AAAA,UACtB,UAAU,cAAc;AAAA,QAC1B,CAAC;AAED;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,kBAAkB;AACnD,cAAM,qBAAqB,KAAK,cAAc,UAAU;AAAA,UACtD,UAAU,cAAc;AAAA;AAAA,QAE1B,CAAC;AAED,YAAI,oBAAoB;AACtB,eAAK,cAAc,iBAAiB;AAAA,YAClC,UAAU,cAAc;AAAA,UAC1B,CAAC;AAGD,eAAK,YAAY,yBAAyB;AAAA,YACxC,UAAU,cAAc;AAAA,UAC1B,CAAC;AAAA,QACH;AAEA;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,kBAAkB;AACnD,aAAK,WAAW;AAAA,UACd,UAAU,cAAc;AAAA,UACxB,UAAU,cAAc;AAAA,UACxB,UAAU,cAAc;AAAA,QAC1B,CAAC;AAED;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,gBAAgB;AACjD,aAAK,YAAY,qBAAqB;AAAA,UACpC,UAAU,cAAc;AAAA,UACxB,UAAU,cAAc;AAAA,QAC1B,CAAC;AAED;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,aAAa;AAC9C;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,kBAAkB;AACnD,aAAK,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAElD;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,cAAc;AAC/C,aAAK,iBAAiB;AAAA,UACpB,mBAAmB,cAAc;AAAA,UACjC,OAAO,cAAc;AAAA,QACvB,CAAC;AAED;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,mBAAmB;AAGpD;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,eAAe;AAEhD,sBAAc,OAAO;AAAA,UACnB,GAAI,cAAc,QAAQ,CAAC;AAAA,UAC3B,OAAO,cAAc;AAAA,QACvB;AAEA;AAAA,MACF;AAAA,MACA,KAAK,8BAA8B,QAAQ;AAGzC;AAAA,MACF;AAAA,MACA,SAAS;AACP,YAAI,uCAAuC;AAAA,UACzC,SAAS;AAAA,UACT,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,KAAK,0BAA0B,SAAS,aAAa;AAAA,EAC7D,GAhIkC;AAAA,EAkI1B,oBAAoB,wBAAC,UAAuB;AAClD,WAAO,MAAM,EAAE,MAAM,CAAC;AAAA,EACxB,GAF4B;AAAA,EAIpB,+BAA+B,wBACrC,IACA,sBACS;AACT,UAAM,WAAW,iBAAiB;AAElC,UAAM,eAAe,KAAK,IAAI;AAE9B,OAAG,GAAG,WAAW,CAAC,YAAqB,KAAK,oBAAoB,IAAI,OAAO,CAAC;AAE5E,OAAG,GAAG,SAAS,MAAM;AACnB,WAAK,gCAAgC,QAAQ;AAC7C,WAAK,cAAc,aAAa,QAAQ;AAGxC,SAAG,mBAAmB;AAAA,IACxB,CAAC;AAED,QAAI;AACF,WAAK,cAAc,UAAU;AAAA,QAC3B;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AAGD,WAAK,cAAc,gBAAgB;AAAA,QACjC,8BAA8B;AAAA,QAC9B,KAAK,UAAU;AAAA,UACb;AAAA,UACA;AAAA,UACA,UAAU,KAAK;AAAA,UACf,MAAM;AAAA,QACR,CAAC;AAAA,MACH;AAGA,UAAI,mBAAmB;AACrB,aAAK,kBAAkB,IAAI;AAAA,UACzB,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,MAAM;AAAA,YACJ,QAAQ,kBAAkB;AAAA,YAC1B,SAAS;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,SAAS,OAAO;AACd,aAAO,MAAM,EAAE,MAAM,CAAC;AAAA,IACxB;AAAA,EACF,GAnDuC;AAAA,EAqDhC,UAAU,EAAE,IAAI,SAAS,GAA8C;AAC5E,UAAM,WAAW,KAAK,cAAc,YAAY,EAAE,GAAG,CAAC;AAEtD,QAAI,CAAC,UAAU;AACb,UAAI,oDAAoD;AAExD;AAAA,IACF;AAGA,UAAM,eAAe,KAAK,YAAY,eAAe;AAAA,MACnD;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,CAAC,cAAc;AACjB,UAAI,qDAAqD;AAAA,QACvD,aAAa,YAAY;AAAA,QACzB,aAAa;AAAA,MACf,CAAC;AAED;AAAA,IACF;AAEA,SAAK,YAAY,qBAAqB;AAAA,MACpC;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,cAAc,gBAAgB;AAAA,MACjC,8BAA8B;AAAA,MAC9B,KAAK,UAAU;AAAA,QACb;AAAA,QACA,MAAM;AAAA,QACN,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAGA,SAAK,kBAAkB,IAAI;AAAA,MACzB,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,gBAAgB;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIS;AACP,SAAK,cAAc,UAAU;AAAA,MAC3B;AAAA,MACA,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAmB,EAAE,SAAS,GAA+B;AAEnE,SAAK,cAAc,aAAa,QAAQ;AAGxC,SAAK,YAAY,yBAAyB,EAAE,SAAS,CAAC;AAAA,EACxD;AAAA,EAEQ,kCAAkC,wBAAC,aAA2B;AACpE,UAAM,SAAS,KAAK,cAAc,UAAU;AAAA,MAC1C;AAAA,IACF,CAAC;AAED,QAAI,CAAC,QAAQ;AACX,UAAI,8DAA8D;AAAA,QAChE,aAAa,YAAY;AAAA,MAC3B,CAAC;AAED;AAAA,IACF;AAEA,SAAK,mBAAmB,EAAE,SAAS,CAAC;AAEpC,SAAK,cAAc,gBAAgB;AAAA,MACjC,8BAA8B;AAAA,MAC9B,KAAK,UAAU;AAAA,QACb;AAAA,QACA,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EAGF,GAxB0C;AAAA,EA0BlC,sBAAsB,8BAAO,IAAe,YAAoC;AAEtF,WAAO,oBAAoB,QAAW,YAAY;AAChD,UAAI;AACF,cAAM,WAAW,KAAK,cAAc,YAAY;AAAA,UAC9C;AAAA,QACF,CAAC;AAED,YAAI,CAAC,UAAU;AACb,cAAI,kDAAkD;AAEtD;AAAA,QACF;AAGA,cAAM,wBAAwB,MAAM,KAAK,oBAAoB,IAAI,SAAS,QAAQ;AAElF,YAAI,uBAAuB;AACzB,eAAK,kBAAkB,IAAI;AAAA,YACzB,MAAM,sBAAsB;AAAA,YAC5B,QAAQ,sBAAsB;AAAA,YAC9B,UAAU,uBAAuB;AAAA,UACnC,CAAC;AAED,cACE,uBAAuB,YACvB,OAAO,sBAAsB,aAAa,YAC1C,WAAW,sBAAsB,UACjC;AAEA,mBAAO,MAAM;AAAA,cACX,OAAO,sBAAsB,SAAS;AAAA,cACtC,MAAM;AAAA,gBACJ;AAAA,gBACA,MAAM,sBAAsB;AAAA,gBAC5B,QAAQ,sBAAsB;AAAA,cAChC;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,eAAO,MAAM,EAAE,MAAM,CAAC;AAEtB,YAAI,iCAAiC;AAAA,UACnC,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH,GAhD8B;AAAA,EAkDpB,mBAAmB,UAAkB,OAAqB;AAClE,SAAK,cAAc,gBAAgB;AAAA,MACjC,8BAA8B;AAAA,MAC9B,KAAK,UAAU;AAAA,QACb,eAAe;AAAA,QACf;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAA6B;AACnC,UAAM,SAAS,KAAK,QAAQ;AAE5B,QAAI,CAAC,QAAQ,WAAW,CAAC,OAAO,cAAc;AAC5C;AAAA,IACF;AAEA,QAAI,OAAO,KAAK;AACd,UAAI,8BAA8B;AAAA,IACpC;AAEA,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,UAAU,KAAK,cAAc,WAAW;AAE9C,eAAW,UAAU,SAAS;AAC5B,YAAM,eAAe,MAAM,OAAO;AAElC,UAAI,eAAe,OAAO,cAAc;AACtC,aAAK,cAAc,iBAAiB,OAAO,QAAQ;AAEnD,YAAI,OAAO,KAAK;AACd,cAAI,gCAAgC;AAAA,YAClC,aAAa,OAAO;AAAA,YACpB,iBAAiB,GAAG,YAAY;AAAA,UAClC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,sBAAsB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIS;AACP,QAAI,CAAC,KAAK,QAAQ;AAChB,UAAI,qDAAqD;AACzD;AAAA,IACF;AAEA,eAAW,UAAU,KAAK,OAAO,SAAS;AACxC,UAAI,OAAO,eAAe,UAAU,MAAM;AACxC;AAAA,MACF;AAEA,YAAM,WAAW,KAAK,cAAc,YAAY,EAAE,IAAI,OAAO,CAAC;AAG9D,UAAI,mBAAmB,aAAa,iBAAiB;AACnD;AAAA,MACF;AAGA,UAAI,aAAa,UAAU;AACzB,cAAM,aAAa,KAAK,cAAc,UAAU,EAAE,SAAS,CAAC;AAC5D,YAAI,CAAC,cAAc,CAAC,UAAU,EAAE,UAAU,UAAU,WAAW,KAAK,CAAC,GAAG;AACtE;AAAA,QACF;AAAA,MACF;AAEA,aAAO,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,gBAAgB;AAAA,IACrB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAIS;AACP,QAAI,CAAC,KAAK,QAAQ;AAChB,UAAI,gDAAgD,EAAE,SAAS,CAAC;AAChE;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,YAAY,MAAM,IAAI,QAAQ;AAChD,QAAI,CAAC,MAAM;AACT,UAAI,oCAAoC,EAAE,SAAS,CAAC;AACpD;AAAA,IACF;AAEA,eAAW,YAAY,MAAM;AAC3B,UAAI,mBAAmB,aAAa,iBAAiB;AACnD;AAAA,MACF;AAEA,YAAM,SAAS,KAAK,cAAc,UAAU,EAAE,SAAS,CAAC;AACxD,UAAI,CAAC,QAAQ,MAAM,OAAO,GAAG,eAAe,UAAU,MAAM;AAC1D;AAAA,MACF;AAEA,aAAO,GAAG,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,iBAAiB,EAAE,SAAS,KAAK,GAAyE;AAC/G,QAAI,CAAC,KAAK,QAAQ;AAChB,UAAI,+CAA+C;AACnD;AAAA,IACF;AAEA,UAAM,YAAY,IAAI,IAAI,QAAQ,IAAI,QAAM,OAAO,EAAE,CAAC,CAAC;AAEvD,eAAW,UAAU,KAAK,OAAO,SAAS;AACxC,UAAI,OAAO,eAAe,UAAU,MAAM;AACxC;AAAA,MACF;AAEA,YAAM,WAAW,KAAK,cAAc,YAAY,EAAE,IAAI,OAAO,CAAC;AAC9D,YAAM,aAAa,WAAW,KAAK,cAAc,UAAU,EAAE,SAAS,CAAC,IAAI;AAE3E,UAAI,CAAC,YAAY,MAAM;AACrB;AAAA,MACF;AAEA,YAAM,eAAe,OAAO,WAAW,KAAK,MAAM,WAAW,KAAK,MAAM;AAExE,UAAI,UAAU,IAAI,YAAY,GAAG;AAC/B,eAAO,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOO,kBAAkB,EAAE,UAAU,KAAK,GAA6D;AACrG,UAAM,SAAS,KAAK,cAAc,UAAU,EAAE,SAAS,CAAC;AAExD,QAAI,CAAC,QAAQ,MAAM,OAAO,GAAG,eAAe,UAAU,MAAM;AAC1D,UAAI,0EAA0E;AAAA,QAC5E;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAEA,WAAO,GAAG,KAAK,KAAK,UAAU,IAAI,CAAC;AAAA,EACrC;AAAA,EAEO,iBAAiB,EAAE,mBAAmB,MAAM,GAAuD;AACxG,UAAM,SAAS,KAAK,cAAc,UAAU;AAAA,MAC1C,UAAU;AAAA,IACZ,CAAC;AAED,QAAI,CAAC,QAAQ;AACX,UAAI,+CAA+C;AAAA,QACjD,aAAa,qBAAqB;AAAA,QAClC,OAAO;AAAA,MACT,CAAC;AAED;AAAA,IACF,WAAW,CAAC,OAAO,IAAI;AACrB,UAAI,yDAAyD;AAAA,QAC3D,aAAa,qBAAqB;AAAA,QAClC,OAAO;AAAA,MACT,CAAC;AAED;AAAA,IACF;AAEA,SAAK,kBAAkB,OAAO,IAAI;AAAA,MAChC,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,MAAM;AAAA,QACJ;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,WAAW,EAAE,UAAU,UAAU,SAAS,GAAgE;AAChH,UAAM,SAAS,KAAK,cAAc,UAAU;AAAA,MAC1C;AAAA,IACF,CAAC;AAED,QAAI,CAAC,QAAQ;AACX,UAAI,sCAAsC;AAAA,QACxC,aAAa,YAAY;AAAA,QACzB,aAAa;AAAA,MACf,CAAC;AAED;AAAA,IACF;AAGA,UAAM,uBAAuB,KAAK,QAAQ,OAAO,8BAA8B;AAE/E,QAAI,CAAC,wBAAwB,OAAO,UAAU;AAE5C,WAAK,YAAY,qBAAqB;AAAA,QACpC,UAAU,OAAO;AAAA,QACjB;AAAA,QACA,WAAW;AAAA;AAAA,MACb,CAAC;AAAA,IACH;AAGA,SAAK,cAAc,aAAa;AAAA,MAC9B;AAAA,MACA,KAAK;AAAA,MACL,MAAM;AAAA,IACR,CAAC;AAED,SAAK,YAAY,gBAAgB;AAAA,MAC/B;AAAA,MACA,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAa,SAAS;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAMG;AACD,UAAM,WAAW,KAAK,cAAc,YAAY,EAAE,GAAG,CAAC;AAEtD,QAAI,CAAC,UAAU;AAGb,aAAO,KAAK;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA;AAAA,UAEJ,aAAa;AAAA,QACf;AAAA,MACF,CAAC;AAED;AAAA,IACF;AAGA,UAAM,iBAAiB,KAAK,YAAY,eAAe;AAAA,MACrD;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,gBAAgB;AAGlB,aAAO,KAAK;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA;AAAA,UAEJ,aAAa;AAAA,UACb,aAAa;AAAA,QACf;AAAA,MACF,CAAC;AAED;AAAA,IACF;AAEA,QAAI,WAAgB,CAAC;AAKrB,QAAI,QAAQ;AAEV,YAAM,kBAAkB,KAAK,iBAAiB,iBAAiB;AAE/D,YAAM,eAAe;AACrB,YAAM,gBAAgB,CAAC,MAAM;AAE7B,YAAM,gBAAgB,MAAM,gBAAgB,QAAQ,cAAc,aAAa;AAE/E,UAAI,CAAC,iBAAiB,cAAc,WAAW,GAAG;AAChD,cAAM,IAAI,MAAM,4BAA4B;AAAA,MAC9C;AAEA,YAAM,OAAO,cAAc,CAAC;AAE5B,iBAAW;AAAA,QACT,IAAI;AAAA,QACJ,GAAG;AAAA,MACL;AAAA,IACF;AAIA,QAAI,UAAU;AACZ,eAAS,WAAW;AAAA,IACtB;AAEA,aAAS,WAAW;AA0BpB,SAAK,WAAW;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAGD,SAAK,cAAc,gBAAgB;AAAA,MACjC,8BAA8B;AAAA,MAC9B,KAAK,UAAU;AAAA,QACb;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA,UAAU,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,oBAAoB,wBAAC,IAAe,MAAe,SAAkB,UAAgB;AAC1F,UAAM,mBAAmB,KAAK,UAAU,IAAI;AAE5C,OAAG,KAAK,kBAAkB,EAAE,OAAO,CAAC;AAAA,EACtC,GAJ2B;AAAA,EAMpB,cAAc,wBAAC,EAAE,KAAK,MAA+B;AAC1D,UAAM,gBAAgB;AAAA,MACpB,GAAI;AAAA,MACJ,UAAU,KAAK;AAAA,IACjB;AAEA,SAAK,cAAc,gBAAgB;AAAA,MACjC,8BAA8B;AAAA,MAC9B,KAAK,UAAU,aAAa;AAAA,IAC9B;AAAA,EACF,GAVqB;AAAA,EAYd,mBAAmB,wBAAC,EAAE,KAAK,MAA+B;AAC/D,UAAM,gBAAgB;AAAA,MACpB,GAAI;AAAA,MACJ,UAAU,KAAK;AAAA,IACjB;AAEA,SAAK,cAAc,gBAAgB;AAAA,MACjC,8BAA8B;AAAA,MAC9B,KAAK,UAAU,aAAa;AAAA,IAC9B;AAAA,EACF,GAV0B;AAAA,EAYnB,oBAAoB,wBAAC,EAAE,KAAK,MAA+B;AAChE,UAAM,gBAAgB;AAAA,MACpB,GAAI;AAAA,MACJ,UAAU,KAAK;AAAA,IACjB;AAEA,SAAK,cAAc,gBAAgB,QAAQ,8BAA8B,QAAQ,KAAK,UAAU,aAAa,CAAC;AAAA,EAChH,GAP2B;AAAA,EASpB,WAAW,EAAE,SAAS,GAAiC;AAC5D,WAAO,KAAK,cAAc,WAAW,EAAE,SAAS,CAAC;AAAA,EACnD;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scpxl/nodejs-framework",
3
- "version": "1.0.43",
3
+ "version": "1.0.45",
4
4
  "description": "PXL Node.js Framework",
5
5
  "repository": {
6
6
  "type": "git",