@scpxl/nodejs-framework 1.0.42 → 1.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/cli/index.js +4 -2
  2. package/dist/cli/index.js.map +2 -2
  3. package/dist/webserver/webserver.d.ts.map +1 -1
  4. package/dist/webserver/webserver.interface.d.ts +2 -0
  5. package/dist/webserver/webserver.interface.d.ts.map +1 -1
  6. package/dist/webserver/webserver.interface.js.map +1 -1
  7. package/dist/webserver/webserver.js +3 -1
  8. package/dist/webserver/webserver.js.map +2 -2
  9. package/dist/websocket/define-subscriber.d.ts +8 -1
  10. package/dist/websocket/define-subscriber.d.ts.map +1 -1
  11. package/dist/websocket/define-subscriber.js +2 -1
  12. package/dist/websocket/define-subscriber.js.map +2 -2
  13. package/dist/websocket/index.d.ts +4 -0
  14. package/dist/websocket/index.d.ts.map +1 -1
  15. package/dist/websocket/index.js +43 -1
  16. package/dist/websocket/index.js.map +2 -2
  17. package/dist/websocket/subscriber-middleware.d.ts +52 -0
  18. package/dist/websocket/subscriber-middleware.d.ts.map +1 -0
  19. package/dist/websocket/subscriber-middleware.js +200 -0
  20. package/dist/websocket/subscriber-middleware.js.map +7 -0
  21. package/dist/websocket/subscriber-utils.d.ts +88 -0
  22. package/dist/websocket/subscriber-utils.d.ts.map +1 -0
  23. package/dist/websocket/subscriber-utils.js +227 -0
  24. package/dist/websocket/subscriber-utils.js.map +7 -0
  25. package/dist/websocket/websocket-server.d.ts +41 -1
  26. package/dist/websocket/websocket-server.d.ts.map +1 -1
  27. package/dist/websocket/websocket-server.js +90 -7
  28. package/dist/websocket/websocket-server.js.map +2 -2
  29. package/dist/websocket/websocket.interface.d.ts +7 -0
  30. package/dist/websocket/websocket.interface.d.ts.map +1 -1
  31. package/dist/websocket/websocket.interface.js.map +2 -2
  32. package/package.json +1 -1
@@ -14,6 +14,7 @@ import WebSocketRoomManager from "./websocket-room-manager.js";
14
14
  import logger from "../logger/logger.js";
15
15
  import { WebSocketAuthService } from "./websocket-auth.js";
16
16
  import { File, Loader } from "../util/index.js";
17
+ import { executeWithMiddleware } from "./subscriber-middleware.js";
17
18
  class WebSocketServer extends WebSocketBase {
18
19
  static {
19
20
  __name(this, "WebSocketServer");
@@ -326,15 +327,19 @@ class WebSocketServer extends WebSocketBase {
326
327
  return;
327
328
  }
328
329
  const orderedHandlers = Array.from(candidates).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
329
- for (const handler of orderedHandlers) {
330
+ for (const handlerDef of orderedHandlers) {
330
331
  try {
331
- await handler.handle(context);
332
+ if (handlerDef.middleware && handlerDef.middleware.length > 0) {
333
+ await executeWithMiddleware(handlerDef.handle, handlerDef.middleware, context);
334
+ } else {
335
+ await handlerDef.handle(context);
336
+ }
332
337
  } catch (error) {
333
338
  logger.error({
334
339
  error,
335
340
  message: "WebSocket subscriber handler failed",
336
341
  meta: {
337
- Handler: handler.name ?? "(anonymous)",
342
+ Handler: handlerDef.name ?? "(anonymous)",
338
343
  Channel: channel
339
344
  }
340
345
  });
@@ -729,10 +734,12 @@ class WebSocketServer extends WebSocketBase {
729
734
  * Broadcast a message to all connected WebSocket clients
730
735
  * @param data - The data to broadcast (will be JSON stringified)
731
736
  * @param excludeClientId - Optional client ID to exclude from broadcast
737
+ * @param predicate - Optional function to filter clients
732
738
  */
733
739
  broadcastToAllClients({
734
740
  data,
735
- excludeClientId
741
+ excludeClientId,
742
+ predicate
736
743
  }) {
737
744
  if (!this.server) {
738
745
  log("Server not started when broadcasting to all clients");
@@ -742,15 +749,91 @@ class WebSocketServer extends WebSocketBase {
742
749
  if (client.readyState !== WebSocket.OPEN) {
743
750
  continue;
744
751
  }
745
- if (excludeClientId) {
746
- const clientId = this.clientManager.getClientId({ ws: client });
747
- if (clientId === excludeClientId) {
752
+ const clientId = this.clientManager.getClientId({ ws: client });
753
+ if (excludeClientId && clientId === excludeClientId) {
754
+ continue;
755
+ }
756
+ if (predicate && clientId) {
757
+ const clientData = this.clientManager.getClient({ clientId });
758
+ if (!clientData || !predicate({ clientId, userData: clientData.user })) {
748
759
  continue;
749
760
  }
750
761
  }
751
762
  client.send(JSON.stringify(data));
752
763
  }
753
764
  }
765
+ /**
766
+ * Broadcast a message to all clients in a specific room
767
+ * @param roomName - The room to broadcast to
768
+ * @param data - The data to broadcast
769
+ * @param excludeClientId - Optional client ID to exclude from broadcast
770
+ */
771
+ broadcastToRoom({
772
+ roomName,
773
+ data,
774
+ excludeClientId
775
+ }) {
776
+ if (!this.server) {
777
+ log("Server not started when broadcasting to room", { roomName });
778
+ return;
779
+ }
780
+ const room = this.roomManager.rooms.get(roomName);
781
+ if (!room) {
782
+ log("Room not found when broadcasting", { roomName });
783
+ return;
784
+ }
785
+ for (const clientId of room) {
786
+ if (excludeClientId && clientId === excludeClientId) {
787
+ continue;
788
+ }
789
+ const client = this.clientManager.getClient({ clientId });
790
+ if (!client?.ws || client.ws.readyState !== WebSocket.OPEN) {
791
+ continue;
792
+ }
793
+ client.ws.send(JSON.stringify(data));
794
+ }
795
+ }
796
+ /**
797
+ * Broadcast a message to specific users
798
+ * @param userIds - Array of user IDs to broadcast to
799
+ * @param data - The data to broadcast
800
+ */
801
+ broadcastToUsers({ userIds, data }) {
802
+ if (!this.server) {
803
+ log("Server not started when broadcasting to users");
804
+ return;
805
+ }
806
+ const userIdSet = new Set(userIds.map((id) => String(id)));
807
+ for (const client of this.server.clients) {
808
+ if (client.readyState !== WebSocket.OPEN) {
809
+ continue;
810
+ }
811
+ const clientId = this.clientManager.getClientId({ ws: client });
812
+ const clientData = clientId ? this.clientManager.getClient({ clientId }) : null;
813
+ if (!clientData?.user) {
814
+ continue;
815
+ }
816
+ const clientUserId = String(clientData.user.id ?? clientData.user.userId);
817
+ if (userIdSet.has(clientUserId)) {
818
+ client.send(JSON.stringify(data));
819
+ }
820
+ }
821
+ }
822
+ /**
823
+ * Broadcast a message to a specific client
824
+ * @param clientId - The client ID to send to
825
+ * @param data - The data to send
826
+ */
827
+ broadcastToClient({ clientId, data }) {
828
+ const client = this.clientManager.getClient({ clientId });
829
+ if (!client?.ws || client.ws.readyState !== WebSocket.OPEN) {
830
+ log("Client not found or not connected when broadcasting to specific client", {
831
+ clientId
832
+ });
833
+ return;
834
+ }
835
+ client.ws.send(JSON.stringify(data));
836
+ }
754
837
  sendMessageError({ webSocketClientId, error }) {
755
838
  const client = this.clientManager.getClient({
756
839
  clientId: webSocketClientId
@@ -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';\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 handler of orderedHandlers) {\n try {\n await handler.handle(context);\n } catch (error) {\n logger.error({\n error,\n message: 'WebSocket subscriber handler failed',\n meta: {\n Handler: handler.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 */\n public broadcastToAllClients({\n data,\n excludeClientId,\n }: {\n data: { [key: string]: any };\n excludeClientId?: string;\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 // Skip excluded client if specified\n if (excludeClientId) {\n const clientId = this.clientManager.getClientId({ ws: client });\n if (clientId === excludeClientId) {\n continue;\n }\n }\n\n client.send(JSON.stringify(data));\n }\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';\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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",
6
6
  "names": []
7
7
  }
@@ -35,6 +35,13 @@ export interface WebSocketSubscriberDefinition<TMessage = any> {
35
35
  matchers?: WebSocketSubscriberMatcher<TMessage>[];
36
36
  /** Handler that will be invoked when the message is matched */
37
37
  handle: WebSocketSubscriberHandler<TMessage>;
38
+ /** Optional middleware to apply to this handler */
39
+ middleware?: Array<{
40
+ name: string;
41
+ onBefore?: (context: WebSocketSubscriberHandlerContext<TMessage>) => boolean | Promise<boolean>;
42
+ onAfter?: (context: WebSocketSubscriberHandlerContext<TMessage>, result: unknown) => void | Promise<void>;
43
+ onError?: (context: WebSocketSubscriberHandlerContext<TMessage>, error: Error) => boolean | Promise<boolean>;
44
+ }>;
38
45
  }
39
46
  export interface WebSocketSubscriberHandlersConfig {
40
47
  /** Directory that contains subscriber handler modules */
@@ -1 +1 @@
1
- {"version":3,"file":"websocket.interface.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket.interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket.interface.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket.interface.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/websocket/websocket.interface.ts"],
4
- "sourcesContent": ["import type { WebSocketServer as NativeWebSocketServer, WebSocket } from 'ws';\nimport type WebSocketServerInstance from './websocket-server.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type { WebSocketServerBaseControllerType } from './controller/server/base.interface.js';\nimport type { WebSocketClientBaseControllerType } from './controller/client/base.interface.js';\n\nexport type WebSocketType = 'server' | 'client';\n\nexport interface WebSocketSubscriberHandlerContext<TMessage = any> {\n /** Redis channel that emitted the message */\n channel: string;\n\n /** Parsed message payload */\n message: TMessage;\n\n /** Running WebSocket server instance */\n webSocketServer: WebSocketServerInstance;\n\n /** Database instance bound to the application */\n databaseInstance: DatabaseInstance;\n\n /** Redis instance used by the framework */\n redisInstance: RedisInstance;\n\n /** Queue manager instance used by the framework */\n queueManager: QueueManager;\n}\n\nexport type WebSocketSubscriberHandler<TMessage = any> = (\n context: WebSocketSubscriberHandlerContext<TMessage>,\n) => unknown | Promise<unknown>;\n\nexport type WebSocketSubscriberMatcher<TMessage = any> =\n | string\n | RegExp\n | ((context: WebSocketSubscriberHandlerContext<TMessage>) => boolean);\n\nexport interface WebSocketSubscriberDefinition<TMessage = any> {\n /** Optional identifier, used for logging and debugging */\n name?: string;\n\n /** Optional description to document the handler */\n description?: string;\n\n /** Optional priority to control execution order (higher runs first) */\n priority?: number;\n\n /** Optional explicit channel filters */\n channels?: string[];\n\n /** Optional matchers that allow advanced filtering */\n matchers?: WebSocketSubscriberMatcher<TMessage>[];\n\n /** Handler that will be invoked when the message is matched */\n handle: WebSocketSubscriberHandler<TMessage>;\n}\n\nexport interface WebSocketSubscriberHandlersConfig {\n /** Directory that contains subscriber handler modules */\n directory?: string;\n\n /** Additional handlers defined inline */\n handlers?: WebSocketSubscriberDefinition[];\n}\n\nexport interface WebSocketDebugOptions {\n printRoutes?: boolean;\n printConnectedClients?: 'simple' | 'table';\n}\n\nexport interface WebSocketMessage<TData = unknown> {\n type: string;\n action: string;\n data: TData;\n}\n\nexport interface WebSocketEventsConfig {\n onServerStarted?: ({ webSocketServer }: { webSocketServer: NativeWebSocketServer }) => void;\n onConnected?: ({\n ws,\n clientId,\n joinRoom,\n }: {\n ws: WebSocket;\n clientId: string;\n joinRoom({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username?: string;\n roomName: string;\n }): void;\n }) => void;\n onDisconnected?: ({ clientId }: { clientId?: string }) => void;\n onError?: ({ error }: { error: Error }) => void;\n onMessage?: <TData = unknown>({\n ws,\n clientId,\n data,\n redisInstance,\n queueManager,\n databaseInstance,\n }: {\n ws: WebSocket;\n clientId: string;\n data: WebSocketMessage<TData>;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n }) => void;\n /** Fired when attempting to reconnect */\n onReconnecting?: ({ attempt, delay }: { attempt: number; delay: number }) => void;\n /** Fired when reconnection is successful */\n onReconnected?: ({ clientId }: { clientId?: string }) => void;\n /** Fired when max reconnection attempts are reached */\n onReconnectFailed?: ({ attempts }: { attempts: number }) => void;\n}\n\nexport interface WebSocketOptions {\n /** WebSocket type */\n type: WebSocketType;\n\n /** WebSocket host */\n host?: string;\n\n /** WebSocket URL */\n url: string;\n\n /** WebSocket controllers directory */\n controllersDirectory: string;\n\n /** Disconnect inactive WebSocket clients configuration */\n disconnectInactiveClients?: {\n /** Whether to enable disconnection of inactive WebSocket clients */\n enabled?: boolean;\n\n /** Interval check time in milliseconds */\n intervalCheckTime?: number;\n\n /** Inactive time in milliseconds */\n inactiveTime?: number;\n\n /** Whether to log disconnection of inactive WebSocket clients */\n log?: boolean;\n };\n\n rooms?: {\n enabled?: boolean;\n clientCanJoinMultipleRooms?: boolean;\n };\n\n /** WebSocket debug options */\n debug?: WebSocketDebugOptions;\n\n /** WebSocket events */\n events?: WebSocketEventsConfig;\n\n /** WebSocket subscriber handlers configuration */\n subscriberHandlers?: WebSocketSubscriberHandlersConfig;\n}\n\nexport interface WebSocketRoute {\n /** WebSocket route type */\n type: string;\n\n /** WebSocket route controller name */\n controllerName: string;\n\n /** WebSocket route controller */\n controller?: WebSocketServerBaseControllerType | WebSocketClientBaseControllerType;\n\n /** WebSocket route action */\n action: string;\n}\n\nexport interface WebSocketConstructorParams {\n /** WebSocket options */\n options: WebSocketOptions;\n\n /** WebSocket routes */\n routes: WebSocketRoute[];\n\n /** Redis instance */\n redisInstance: RedisInstance;\n\n /** Queue manager */\n queueManager: QueueManager;\n\n /** Database instance */\n databaseInstance: DatabaseInstance;\n}\n\nexport interface WebSocketConnectedClientData {\n /** WebSocket client */\n ws: WebSocket | null;\n\n /** Last activity time */\n lastActivity: number;\n\n /** Client username */\n username?: string;\n}\n\nexport interface WebSocketMessageResponse {\n error?: string;\n}\n\nexport interface WebSocketMessageHandler<TData = unknown, TResponse = WebSocketMessageResponse> {\n (ws: WebSocket, clientId: string, data: TData): Promise<TResponse> | TResponse;\n}\n\nexport enum WebSocketRedisSubscriberEvent {\n ClientConnected = 'clientConnected',\n ClientDisconnected = 'clientDisconnected',\n DisconnectClient = 'disconnectClient',\n ClientJoinedRoom = 'clientJoinedRoom',\n ClientLeftRoom = 'clientLeftRoom',\n SendMessage = 'sendMessage',\n SendMessageToAll = 'sendMessageToAll',\n MessageError = 'messageError',\n QueueJobCompleted = 'queueJobCompleted',\n QueueJobError = 'queueJobError',\n Custom = 'custom',\n}\n"],
5
- "mappings": "AAyNO,IAAK,gCAAL,kBAAKA,mCAAL;AACL,EAAAA,+BAAA,qBAAkB;AAClB,EAAAA,+BAAA,wBAAqB;AACrB,EAAAA,+BAAA,sBAAmB;AACnB,EAAAA,+BAAA,sBAAmB;AACnB,EAAAA,+BAAA,oBAAiB;AACjB,EAAAA,+BAAA,iBAAc;AACd,EAAAA,+BAAA,sBAAmB;AACnB,EAAAA,+BAAA,kBAAe;AACf,EAAAA,+BAAA,uBAAoB;AACpB,EAAAA,+BAAA,mBAAgB;AAChB,EAAAA,+BAAA,YAAS;AAXC,SAAAA;AAAA,GAAA;",
4
+ "sourcesContent": ["import type { WebSocketServer as NativeWebSocketServer, WebSocket } from 'ws';\nimport type WebSocketServerInstance from './websocket-server.js';\nimport type DatabaseInstance from '../database/instance.js';\nimport type QueueManager from '../queue/manager.js';\nimport type RedisInstance from '../redis/instance.js';\nimport type { WebSocketServerBaseControllerType } from './controller/server/base.interface.js';\nimport type { WebSocketClientBaseControllerType } from './controller/client/base.interface.js';\n\nexport type WebSocketType = 'server' | 'client';\n\nexport interface WebSocketSubscriberHandlerContext<TMessage = any> {\n /** Redis channel that emitted the message */\n channel: string;\n\n /** Parsed message payload */\n message: TMessage;\n\n /** Running WebSocket server instance */\n webSocketServer: WebSocketServerInstance;\n\n /** Database instance bound to the application */\n databaseInstance: DatabaseInstance;\n\n /** Redis instance used by the framework */\n redisInstance: RedisInstance;\n\n /** Queue manager instance used by the framework */\n queueManager: QueueManager;\n}\n\nexport type WebSocketSubscriberHandler<TMessage = any> = (\n context: WebSocketSubscriberHandlerContext<TMessage>,\n) => unknown | Promise<unknown>;\n\nexport type WebSocketSubscriberMatcher<TMessage = any> =\n | string\n | RegExp\n | ((context: WebSocketSubscriberHandlerContext<TMessage>) => boolean);\n\nexport interface WebSocketSubscriberDefinition<TMessage = any> {\n /** Optional identifier, used for logging and debugging */\n name?: string;\n\n /** Optional description to document the handler */\n description?: string;\n\n /** Optional priority to control execution order (higher runs first) */\n priority?: number;\n\n /** Optional explicit channel filters */\n channels?: string[];\n\n /** Optional matchers that allow advanced filtering */\n matchers?: WebSocketSubscriberMatcher<TMessage>[];\n\n /** Handler that will be invoked when the message is matched */\n handle: WebSocketSubscriberHandler<TMessage>;\n\n /** Optional middleware to apply to this handler */\n middleware?: Array<{\n name: string;\n onBefore?: (context: WebSocketSubscriberHandlerContext<TMessage>) => boolean | Promise<boolean>;\n onAfter?: (context: WebSocketSubscriberHandlerContext<TMessage>, result: unknown) => void | Promise<void>;\n onError?: (context: WebSocketSubscriberHandlerContext<TMessage>, error: Error) => boolean | Promise<boolean>;\n }>;\n}\n\nexport interface WebSocketSubscriberHandlersConfig {\n /** Directory that contains subscriber handler modules */\n directory?: string;\n\n /** Additional handlers defined inline */\n handlers?: WebSocketSubscriberDefinition[];\n}\n\nexport interface WebSocketDebugOptions {\n printRoutes?: boolean;\n printConnectedClients?: 'simple' | 'table';\n}\n\nexport interface WebSocketMessage<TData = unknown> {\n type: string;\n action: string;\n data: TData;\n}\n\nexport interface WebSocketEventsConfig {\n onServerStarted?: ({ webSocketServer }: { webSocketServer: NativeWebSocketServer }) => void;\n onConnected?: ({\n ws,\n clientId,\n joinRoom,\n }: {\n ws: WebSocket;\n clientId: string;\n joinRoom({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username?: string;\n roomName: string;\n }): void;\n }) => void;\n onDisconnected?: ({ clientId }: { clientId?: string }) => void;\n onError?: ({ error }: { error: Error }) => void;\n onMessage?: <TData = unknown>({\n ws,\n clientId,\n data,\n redisInstance,\n queueManager,\n databaseInstance,\n }: {\n ws: WebSocket;\n clientId: string;\n data: WebSocketMessage<TData>;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n }) => void;\n /** Fired when attempting to reconnect */\n onReconnecting?: ({ attempt, delay }: { attempt: number; delay: number }) => void;\n /** Fired when reconnection is successful */\n onReconnected?: ({ clientId }: { clientId?: string }) => void;\n /** Fired when max reconnection attempts are reached */\n onReconnectFailed?: ({ attempts }: { attempts: number }) => void;\n}\n\nexport interface WebSocketOptions {\n /** WebSocket type */\n type: WebSocketType;\n\n /** WebSocket host */\n host?: string;\n\n /** WebSocket URL */\n url: string;\n\n /** WebSocket controllers directory */\n controllersDirectory: string;\n\n /** Disconnect inactive WebSocket clients configuration */\n disconnectInactiveClients?: {\n /** Whether to enable disconnection of inactive WebSocket clients */\n enabled?: boolean;\n\n /** Interval check time in milliseconds */\n intervalCheckTime?: number;\n\n /** Inactive time in milliseconds */\n inactiveTime?: number;\n\n /** Whether to log disconnection of inactive WebSocket clients */\n log?: boolean;\n };\n\n rooms?: {\n enabled?: boolean;\n clientCanJoinMultipleRooms?: boolean;\n };\n\n /** WebSocket debug options */\n debug?: WebSocketDebugOptions;\n\n /** WebSocket events */\n events?: WebSocketEventsConfig;\n\n /** WebSocket subscriber handlers configuration */\n subscriberHandlers?: WebSocketSubscriberHandlersConfig;\n}\n\nexport interface WebSocketRoute {\n /** WebSocket route type */\n type: string;\n\n /** WebSocket route controller name */\n controllerName: string;\n\n /** WebSocket route controller */\n controller?: WebSocketServerBaseControllerType | WebSocketClientBaseControllerType;\n\n /** WebSocket route action */\n action: string;\n}\n\nexport interface WebSocketConstructorParams {\n /** WebSocket options */\n options: WebSocketOptions;\n\n /** WebSocket routes */\n routes: WebSocketRoute[];\n\n /** Redis instance */\n redisInstance: RedisInstance;\n\n /** Queue manager */\n queueManager: QueueManager;\n\n /** Database instance */\n databaseInstance: DatabaseInstance;\n}\n\nexport interface WebSocketConnectedClientData {\n /** WebSocket client */\n ws: WebSocket | null;\n\n /** Last activity time */\n lastActivity: number;\n\n /** Client username */\n username?: string;\n}\n\nexport interface WebSocketMessageResponse {\n error?: string;\n}\n\nexport interface WebSocketMessageHandler<TData = unknown, TResponse = WebSocketMessageResponse> {\n (ws: WebSocket, clientId: string, data: TData): Promise<TResponse> | TResponse;\n}\n\nexport enum WebSocketRedisSubscriberEvent {\n ClientConnected = 'clientConnected',\n ClientDisconnected = 'clientDisconnected',\n DisconnectClient = 'disconnectClient',\n ClientJoinedRoom = 'clientJoinedRoom',\n ClientLeftRoom = 'clientLeftRoom',\n SendMessage = 'sendMessage',\n SendMessageToAll = 'sendMessageToAll',\n MessageError = 'messageError',\n QueueJobCompleted = 'queueJobCompleted',\n QueueJobError = 'queueJobError',\n Custom = 'custom',\n}\n"],
5
+ "mappings": "AAiOO,IAAK,gCAAL,kBAAKA,mCAAL;AACL,EAAAA,+BAAA,qBAAkB;AAClB,EAAAA,+BAAA,wBAAqB;AACrB,EAAAA,+BAAA,sBAAmB;AACnB,EAAAA,+BAAA,sBAAmB;AACnB,EAAAA,+BAAA,oBAAiB;AACjB,EAAAA,+BAAA,iBAAc;AACd,EAAAA,+BAAA,sBAAmB;AACnB,EAAAA,+BAAA,kBAAe;AACf,EAAAA,+BAAA,uBAAoB;AACpB,EAAAA,+BAAA,mBAAgB;AAChB,EAAAA,+BAAA,YAAS;AAXC,SAAAA;AAAA,GAAA;",
6
6
  "names": ["WebSocketRedisSubscriberEvent"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scpxl/nodejs-framework",
3
- "version": "1.0.42",
3
+ "version": "1.0.44",
4
4
  "description": "PXL Node.js Framework",
5
5
  "repository": {
6
6
  "type": "git",