@scpxl/nodejs-framework 1.0.49 → 1.0.50

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 (41) hide show
  1. package/dist/application/base-application.d.ts.map +1 -1
  2. package/dist/application/base-application.js +6 -0
  3. package/dist/application/base-application.js.map +2 -2
  4. package/dist/lifecycle/lifecycle-manager.d.ts +6 -0
  5. package/dist/lifecycle/lifecycle-manager.d.ts.map +1 -1
  6. package/dist/lifecycle/lifecycle-manager.js +28 -0
  7. package/dist/lifecycle/lifecycle-manager.js.map +2 -2
  8. package/dist/queue/manager.d.ts +6 -0
  9. package/dist/queue/manager.d.ts.map +1 -1
  10. package/dist/queue/manager.js +39 -4
  11. package/dist/queue/manager.js.map +2 -2
  12. package/dist/queue/worker.d.ts +5 -0
  13. package/dist/queue/worker.d.ts.map +1 -1
  14. package/dist/queue/worker.js +8 -0
  15. package/dist/queue/worker.js.map +2 -2
  16. package/dist/redis/index.d.ts +1 -1
  17. package/dist/redis/index.d.ts.map +1 -1
  18. package/dist/redis/index.js +3 -2
  19. package/dist/redis/index.js.map +2 -2
  20. package/dist/redis/instance.js +1 -1
  21. package/dist/redis/instance.js.map +2 -2
  22. package/dist/redis/manager.d.ts +5 -0
  23. package/dist/redis/manager.d.ts.map +1 -1
  24. package/dist/redis/manager.js +13 -0
  25. package/dist/redis/manager.js.map +2 -2
  26. package/dist/util/file.d.ts +13 -2
  27. package/dist/util/file.d.ts.map +1 -1
  28. package/dist/util/file.js.map +2 -2
  29. package/dist/webserver/controller/entity.d.ts +1 -0
  30. package/dist/webserver/controller/entity.d.ts.map +1 -1
  31. package/dist/webserver/controller/entity.js +7 -0
  32. package/dist/webserver/controller/entity.js.map +2 -2
  33. package/dist/websocket/websocket-client-manager.d.ts +2 -0
  34. package/dist/websocket/websocket-client-manager.d.ts.map +1 -1
  35. package/dist/websocket/websocket-client-manager.js +8 -1
  36. package/dist/websocket/websocket-client-manager.js.map +2 -2
  37. package/dist/websocket/websocket-client.d.ts +5 -0
  38. package/dist/websocket/websocket-client.d.ts.map +1 -1
  39. package/dist/websocket/websocket-client.js +22 -0
  40. package/dist/websocket/websocket-client.js.map +2 -2
  41. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/websocket/websocket-client-manager.ts"],
4
- "sourcesContent": ["import WebSocket from 'ws';\nimport { log } from './utils.js';\nimport type { WebSocketClientData } from './websocket-client-manager.interface.js';\nimport { Helper, Time } from '../util/index.js';\nimport cluster from 'cluster';\nimport { safeSerializeError } from '../error/error-reporter.js';\n\nexport default class WebSocketClientManager {\n private clients: Map<string, WebSocketClientData> = new Map();\n\n public addClient({\n clientId,\n ws,\n lastActivity,\n user,\n }: {\n clientId: string;\n ws: WebSocket | null;\n lastActivity: number;\n user?: { userId: number; payload: any } | null;\n }) {\n this.clients.set(clientId, {\n ws,\n lastActivity,\n user,\n });\n\n this.broadcastClientList('addClient');\n\n log('Client connected', {\n ID: clientId,\n UserId: user?.userId ?? 'unauthenticated',\n });\n\n this.printClients();\n }\n\n public getClientId({ ws }: { ws: WebSocket }): string | undefined {\n return [...this.clients.entries()].find(([_, value]) => value.ws === ws)?.[0];\n }\n\n public getClient({\n clientId,\n requireWs,\n }: {\n clientId: string;\n requireWs?: boolean;\n }): WebSocketClientData | undefined {\n const client = this.clients.get(clientId);\n\n if (requireWs && !client?.ws) {\n return undefined;\n }\n\n return client;\n }\n\n public updateClient({\n clientId,\n key,\n data,\n broadcastClientList,\n }: {\n clientId: string;\n key: string;\n data: any;\n broadcastClientList?: boolean;\n }) {\n const client = this.clients.get(clientId);\n\n if (!client) {\n return;\n }\n\n // Prevent prototype pollution attacks\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n log('Blocked attempt to modify dangerous property', { Property: key });\n return;\n }\n\n // Define allowed client properties to prevent unauthorized modifications\n const allowedClientProperties = [\n 'id',\n 'ws',\n 'room',\n 'userId',\n 'username',\n 'metadata',\n 'connectedAt',\n 'lastActivity',\n 'status',\n 'permissions',\n ];\n\n if (!allowedClientProperties.includes(key)) {\n log('Blocked attempt to modify unauthorized property', { Property: key });\n return;\n }\n\n Reflect.set(client, key, data);\n\n this.clients.set(clientId, client);\n\n if (broadcastClientList !== false) {\n this.broadcastClientList('updateClient');\n }\n\n this.printClients();\n }\n\n public removeClient(clientId: string) {\n const client = this.clients.get(clientId);\n\n // Clean up WebSocket connection if it exists\n if (client?.ws) {\n try {\n client.ws.removeAllListeners();\n if (client.ws.readyState === WebSocket.OPEN) {\n client.ws.close();\n }\n } catch (error) {\n log('Error cleaning up WebSocket connection', {\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n }\n\n this.clients.delete(clientId);\n this.broadcastClientList('removeClient');\n this.printClients();\n }\n\n public getClientList() {\n const clientList: {\n clientId: string;\n [key: string]: any;\n }[] = [];\n\n this.clients.forEach((clientData, clientId) => {\n clientList.push({\n clientId,\n ...clientData,\n });\n });\n\n return clientList;\n }\n\n public getClientByKey({\n key,\n value,\n requireWs,\n userType,\n }: {\n key: string;\n value: string;\n requireWs?: boolean;\n userType?: string;\n }) {\n const clients = [...this.clients.entries()];\n\n const client = clients.find(([_, clientData]) => {\n const deepKeyValue = Helper.getValueFromObject(clientData, key);\n\n const isValueMatching = deepKeyValue === value;\n\n if (userType && clientData.user?.userType !== userType) {\n return false;\n }\n\n return isValueMatching;\n });\n\n const formattedClient = client\n ? {\n clientId: client[0],\n ...client[1],\n }\n : undefined;\n\n if (requireWs && !formattedClient?.ws) {\n return undefined;\n }\n\n return formattedClient;\n }\n\n public getClients({ userType }: { userType?: string } = {}) {\n const clients: WebSocketClientData[] = [];\n\n this.clients.forEach((clientData, clientId) => {\n if (userType && clientData.user?.userType !== userType) {\n return;\n }\n\n clientData.clientId = clientId;\n\n clients.push(clientData);\n });\n\n return clients;\n }\n\n public disconnectClient({ clientId }: { clientId: string }) {\n const clientInfo = this.clients.get(clientId);\n\n if (clientInfo?.ws) {\n const connectedTime = Date.now() - clientInfo.lastActivity;\n\n clientInfo.ws.close();\n\n log('WebSocket client was disconnected due to inactivity', {\n ID: clientId,\n 'Time Connected': Time.formatTime({\n time: connectedTime,\n format: 's',\n }),\n });\n }\n\n this.removeClient(clientId);\n\n log('Client disconnected', { ID: clientId });\n\n this.printClients();\n }\n\n public printClients() {\n const numClients = this.clients.size;\n\n const workerId = cluster.isWorker && cluster.worker ? cluster.worker.id : null;\n\n let logOutput = '\\n-------------------------------------------------------\\n';\n logOutput += `Connected clients (Count: ${numClients}${workerId ? ` | Worker: ${workerId}` : ''}):\\n`;\n logOutput += '-------------------------------------------------------\\n';\n\n if (numClients > 0) {\n this.clients.forEach((client, clientId) => {\n logOutput += `ID: ${clientId} | Username: ${client?.user?.username ?? '-'} | User Type: ${client?.user?.userType ?? '-'} | Email: ${client.user?.email ?? '-'}\\n`;\n });\n } else {\n logOutput += 'No clients';\n }\n\n logOutput += '\\n';\n\n log(logOutput, undefined, {\n muteWorker: true,\n });\n }\n\n public broadcastClientList(type: string) {\n const clientList = this.getClientList();\n\n this.clients.forEach(({ ws }) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n try {\n ws.send(\n JSON.stringify({\n type: 'system',\n action: 'clientList',\n clientListType: type,\n data: clientList,\n }),\n );\n } catch (error) {\n // Handle send errors (e.g., connection closed)\n log('Error broadcasting client list', {\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n });\n }\n\n public cleanup(): void {\n // Clean up all client connections\n this.clients.forEach((client, clientId) => {\n if (client.ws) {\n try {\n client.ws.removeAllListeners();\n if (client.ws.readyState === WebSocket.OPEN) {\n client.ws.close();\n }\n } catch (error) {\n log('Error cleaning up client connection', {\n clientId,\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n }\n });\n\n // Clear all clients\n this.clients.clear();\n log('WebSocket client manager cleaned up');\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import WebSocket from 'ws';\nimport { log } from './utils.js';\nimport type { WebSocketClientData } from './websocket-client-manager.interface.js';\nimport { Helper, Time } from '../util/index.js';\nimport cluster from 'cluster';\nimport { safeSerializeError } from '../error/error-reporter.js';\n\nexport default class WebSocketClientManager {\n private clients: Map<string, WebSocketClientData> = new Map();\n /** Reverse lookup map for O(1) clientId lookup by WebSocket instance */\n private wsToClientId: Map<WebSocket, string> = new Map();\n\n public addClient({\n clientId,\n ws,\n lastActivity,\n user,\n }: {\n clientId: string;\n ws: WebSocket | null;\n lastActivity: number;\n user?: { userId: number; payload: any } | null;\n }) {\n this.clients.set(clientId, {\n ws,\n lastActivity,\n user,\n });\n\n // Maintain reverse lookup map for O(1) clientId lookups\n if (ws) {\n this.wsToClientId.set(ws, clientId);\n }\n\n this.broadcastClientList('addClient');\n\n log('Client connected', {\n ID: clientId,\n UserId: user?.userId ?? 'unauthenticated',\n });\n\n this.printClients();\n }\n\n public getClientId({ ws }: { ws: WebSocket }): string | undefined {\n // O(1) lookup using reverse map instead of O(n) iteration\n return this.wsToClientId.get(ws);\n }\n\n public getClient({\n clientId,\n requireWs,\n }: {\n clientId: string;\n requireWs?: boolean;\n }): WebSocketClientData | undefined {\n const client = this.clients.get(clientId);\n\n if (requireWs && !client?.ws) {\n return undefined;\n }\n\n return client;\n }\n\n public updateClient({\n clientId,\n key,\n data,\n broadcastClientList,\n }: {\n clientId: string;\n key: string;\n data: any;\n broadcastClientList?: boolean;\n }) {\n const client = this.clients.get(clientId);\n\n if (!client) {\n return;\n }\n\n // Prevent prototype pollution attacks\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') {\n log('Blocked attempt to modify dangerous property', { Property: key });\n return;\n }\n\n // Define allowed client properties to prevent unauthorized modifications\n const allowedClientProperties = [\n 'id',\n 'ws',\n 'room',\n 'userId',\n 'username',\n 'metadata',\n 'connectedAt',\n 'lastActivity',\n 'status',\n 'permissions',\n ];\n\n if (!allowedClientProperties.includes(key)) {\n log('Blocked attempt to modify unauthorized property', { Property: key });\n return;\n }\n\n Reflect.set(client, key, data);\n\n this.clients.set(clientId, client);\n\n if (broadcastClientList !== false) {\n this.broadcastClientList('updateClient');\n }\n\n this.printClients();\n }\n\n public removeClient(clientId: string) {\n const client = this.clients.get(clientId);\n\n // Clean up WebSocket connection if it exists\n if (client?.ws) {\n // Remove from reverse lookup map\n this.wsToClientId.delete(client.ws);\n\n try {\n client.ws.removeAllListeners();\n if (client.ws.readyState === WebSocket.OPEN) {\n client.ws.close();\n }\n } catch (error) {\n log('Error cleaning up WebSocket connection', {\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n }\n\n this.clients.delete(clientId);\n this.broadcastClientList('removeClient');\n this.printClients();\n }\n\n public getClientList() {\n const clientList: {\n clientId: string;\n [key: string]: any;\n }[] = [];\n\n this.clients.forEach((clientData, clientId) => {\n clientList.push({\n clientId,\n ...clientData,\n });\n });\n\n return clientList;\n }\n\n public getClientByKey({\n key,\n value,\n requireWs,\n userType,\n }: {\n key: string;\n value: string;\n requireWs?: boolean;\n userType?: string;\n }) {\n const clients = [...this.clients.entries()];\n\n const client = clients.find(([_, clientData]) => {\n const deepKeyValue = Helper.getValueFromObject(clientData, key);\n\n const isValueMatching = deepKeyValue === value;\n\n if (userType && clientData.user?.userType !== userType) {\n return false;\n }\n\n return isValueMatching;\n });\n\n const formattedClient = client\n ? {\n clientId: client[0],\n ...client[1],\n }\n : undefined;\n\n if (requireWs && !formattedClient?.ws) {\n return undefined;\n }\n\n return formattedClient;\n }\n\n public getClients({ userType }: { userType?: string } = {}) {\n const clients: WebSocketClientData[] = [];\n\n this.clients.forEach((clientData, clientId) => {\n if (userType && clientData.user?.userType !== userType) {\n return;\n }\n\n clientData.clientId = clientId;\n\n clients.push(clientData);\n });\n\n return clients;\n }\n\n public disconnectClient({ clientId }: { clientId: string }) {\n const clientInfo = this.clients.get(clientId);\n\n if (clientInfo?.ws) {\n const connectedTime = Date.now() - clientInfo.lastActivity;\n\n clientInfo.ws.close();\n\n log('WebSocket client was disconnected due to inactivity', {\n ID: clientId,\n 'Time Connected': Time.formatTime({\n time: connectedTime,\n format: 's',\n }),\n });\n }\n\n this.removeClient(clientId);\n\n log('Client disconnected', { ID: clientId });\n\n this.printClients();\n }\n\n public printClients() {\n const numClients = this.clients.size;\n\n const workerId = cluster.isWorker && cluster.worker ? cluster.worker.id : null;\n\n let logOutput = '\\n-------------------------------------------------------\\n';\n logOutput += `Connected clients (Count: ${numClients}${workerId ? ` | Worker: ${workerId}` : ''}):\\n`;\n logOutput += '-------------------------------------------------------\\n';\n\n if (numClients > 0) {\n this.clients.forEach((client, clientId) => {\n logOutput += `ID: ${clientId} | Username: ${client?.user?.username ?? '-'} | User Type: ${client?.user?.userType ?? '-'} | Email: ${client.user?.email ?? '-'}\\n`;\n });\n } else {\n logOutput += 'No clients';\n }\n\n logOutput += '\\n';\n\n log(logOutput, undefined, {\n muteWorker: true,\n });\n }\n\n public broadcastClientList(type: string) {\n const clientList = this.getClientList();\n\n this.clients.forEach(({ ws }) => {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n return;\n }\n\n try {\n ws.send(\n JSON.stringify({\n type: 'system',\n action: 'clientList',\n clientListType: type,\n data: clientList,\n }),\n );\n } catch (error) {\n // Handle send errors (e.g., connection closed)\n log('Error broadcasting client list', {\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n });\n }\n\n public cleanup(): void {\n // Clean up all client connections\n this.clients.forEach((client, clientId) => {\n if (client.ws) {\n try {\n client.ws.removeAllListeners();\n if (client.ws.readyState === WebSocket.OPEN) {\n client.ws.close();\n }\n } catch (error) {\n log('Error cleaning up client connection', {\n clientId,\n error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n }\n }\n });\n\n // Clear all maps\n this.clients.clear();\n this.wsToClientId.clear();\n log('WebSocket client manager cleaned up');\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -60,5 +60,10 @@ export default class WebSocketClient extends WebSocketBase {
60
60
  reconnectAttempts: number;
61
61
  autoReconnectEnabled: boolean;
62
62
  };
63
+ /**
64
+ * Destroy the client and clean up all resources.
65
+ * This should be called when the client is no longer needed to prevent memory leaks.
66
+ */
67
+ destroy(): void;
63
68
  }
64
69
  //# sourceMappingURL=websocket-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-client.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,cAAc,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAMhD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,aAAa;IACxD,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,CAMvC;IAEF,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,EAAE,CAAC,CAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,oBAAoB,CAAc;IAC1C,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,eAAe,CAAiB;gBAE5B,KAAK,EAAE,oBAAoB;IAWvC,IAAW,IAAI,IAAI,aAAa,CAE/B;IAEY,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IA+E7C,SAAS,CAAC,yBAAyB,IAAI;QACrC,WAAW,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QACrC,aAAa,EAAE,aAAa,CAAC;QAC7B,YAAY,EAAE,YAAY,CAAC;QAC3B,gBAAgB,EAAE,gBAAgB,CAAC;KACpC;IAQD,SAAS,CAAC,iBAAiB,IAAI,OAAO;IAItC,OAAO,CAAC,qBAAqB,CAqB3B;IAEF,SAAS,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5D,iBAAiB,GAAI,MAAM,OAAO,EAAE,SAAQ,OAAe,KAAG,IAAI,CAUvE;IAEK,WAAW,GAAI,MAAM,OAAO,KAAG,IAAI,CAExC;IAEK,UAAU,IAAI,IAAI;IAoBlB,iBAAiB,IAAI,OAAO;IAInC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAqCzB;;OAEG;YACW,gBAAgB;IA4B9B;;OAEG;IACI,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,oBAAoB,IAAI,IAAI;IASnC;;OAEG;IACI,mBAAmB,IAAI;QAC5B,WAAW,EAAE,OAAO,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,oBAAoB,EAAE,OAAO,CAAC;KAC/B;CAOF"}
1
+ {"version":3,"file":"websocket-client.d.ts","sourceRoot":"","sources":["../../src/websocket/websocket-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoB,cAAc,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,KAAK,aAAa,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,YAAY,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,gBAAgB,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5E,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAMhD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,aAAa;IACxD,SAAS,CAAC,aAAa,EAAE,cAAc,EAAE,CAMvC;IAEF,OAAO,CAAC,iBAAiB,CAAoB;IAC7C,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,gBAAgB,CAAmB;IAC3C,OAAO,CAAC,EAAE,CAAC,CAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAS;IAC1B,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,oBAAoB,CAAc;IAC1C,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,eAAe,CAAiB;gBAE5B,KAAK,EAAE,oBAAoB;IAWvC,IAAW,IAAI,IAAI,aAAa,CAE/B;IAEY,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IA+E7C,SAAS,CAAC,yBAAyB,IAAI;QACrC,WAAW,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;QACrC,aAAa,EAAE,aAAa,CAAC;QAC7B,YAAY,EAAE,YAAY,CAAC;QAC3B,gBAAgB,EAAE,gBAAgB,CAAC;KACpC;IAQD,SAAS,CAAC,iBAAiB,IAAI,OAAO;IAItC,OAAO,CAAC,qBAAqB,CAqB3B;IAEF,SAAS,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAI5D,iBAAiB,GAAI,MAAM,OAAO,EAAE,SAAQ,OAAe,KAAG,IAAI,CAUvE;IAEK,WAAW,GAAI,MAAM,OAAO,KAAG,IAAI,CAExC;IAEK,UAAU,IAAI,IAAI;IAoBlB,iBAAiB,IAAI,OAAO;IAInC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAqCzB;;OAEG;YACW,gBAAgB;IA4B9B;;OAEG;IACI,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,oBAAoB,IAAI,IAAI;IASnC;;OAEG;IACI,mBAAmB,IAAI;QAC5B,WAAW,EAAE,OAAO,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,oBAAoB,EAAE,OAAO,CAAC;KAC/B;IAQD;;;OAGG;IACI,OAAO,IAAI,IAAI;CAyBvB"}
@@ -245,6 +245,28 @@ class WebSocketClient extends WebSocketBase {
245
245
  autoReconnectEnabled: this.shouldReconnect
246
246
  };
247
247
  }
248
+ /**
249
+ * Destroy the client and clean up all resources.
250
+ * This should be called when the client is no longer needed to prevent memory leaks.
251
+ */
252
+ destroy() {
253
+ if (this.reconnectTimer) {
254
+ clearTimeout(this.reconnectTimer);
255
+ this.reconnectTimer = void 0;
256
+ }
257
+ this.shouldReconnect = false;
258
+ if (this.ws) {
259
+ this.ws.removeAllListeners();
260
+ if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {
261
+ this.ws.close();
262
+ }
263
+ this.ws = void 0;
264
+ }
265
+ this.clientId = void 0;
266
+ this.isConnected = false;
267
+ this.reconnectAttempts = 0;
268
+ log("WebSocket client destroyed");
269
+ }
248
270
  }
249
271
  export {
250
272
  WebSocketClient as default
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/websocket/websocket-client.ts"],
4
- "sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } 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 { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { safeSerializeError } from '../error/error-reporter.js';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = 10;\n private reconnectDelay: number = 1000; // Start with 1 second\n private reconnectTimer?: NodeJS.Timeout;\n private shouldReconnect: boolean = true;\n\n constructor(props: WebSocketClientProps) {\n super();\n\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 }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close', code => {\n this.isConnected = false;\n log('Connection to server closed', { Code: code });\n\n if (this.options.events?.onDisconnected) {\n this.options.events.onDisconnected({ clientId: this.clientId });\n }\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n this.ws = undefined;\n this.clientId = undefined;\n\n // Attempt to reconnect if not manually disconnected\n if (this.shouldReconnect) {\n this.scheduleReconnect();\n }\n });\n\n ws.on('error', error => {\n log('WebSocket error', { error: error.message });\n\n if (this.options.events?.onError) {\n this.options.events.onError({ error });\n }\n });\n\n this.ws = ws;\n });\n }\n\n protected getControllerDependencies(): {\n sendMessage: (data: unknown) => void;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n sendMessage: this.sendMessage,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleIncomingMessage = async (message: RawData): Promise<void> => {\n if (!this.ws || !this.clientId) {\n log('WebSocket not initialized or client ID not set');\n\n return;\n }\n\n if (this.options.events?.onMessage) {\n const parsedMessage = parseServerMessage(message);\n\n this.options.events.onMessage({\n ws: this.ws,\n clientId: this.clientId,\n data: parsedMessage as { type: string; action: string; data: unknown },\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n }\n\n await this.handleServerMessage(this.ws, message, this.clientId);\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n log(error);\n }\n\n public sendClientMessage = (data: unknown, binary: boolean = false): void => {\n if (!this.ws) {\n log('WebSocket not initialized');\n\n return;\n }\n\n const webSocketMessage = JSON.stringify(data);\n\n this.ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = (data: unknown): void => {\n this.sendClientMessage(data);\n };\n\n public disconnect(): void {\n // Disable auto-reconnect on manual disconnect\n this.shouldReconnect = false;\n\n // Clear any pending reconnect timer\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.ws && this.isConnected) {\n this.ws.removeAllListeners();\n this.ws.close();\n this.ws = undefined;\n this.clientId = undefined;\n this.isConnected = false;\n log('WebSocket client disconnected');\n }\n }\n\n public isClientConnected(): boolean {\n return this.isConnected && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff\n */\n private scheduleReconnect(): void {\n // Don't reconnect if we've exceeded max attempts\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n log('Max reconnection attempts reached', {\n Attempts: this.reconnectAttempts,\n });\n\n if (this.options.events?.onReconnectFailed) {\n this.options.events.onReconnectFailed({\n attempts: this.reconnectAttempts,\n });\n }\n\n return;\n }\n\n // Calculate delay with exponential backoff (max 30 seconds)\n const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts), 30000);\n this.reconnectAttempts++;\n\n log('Scheduling reconnection', {\n Attempt: this.reconnectAttempts,\n Delay: `${delay}ms`,\n });\n\n if (this.options.events?.onReconnecting) {\n this.options.events.onReconnecting({\n attempt: this.reconnectAttempts,\n delay,\n });\n }\n\n this.reconnectTimer = setTimeout(() => {\n this.attemptReconnect();\n }, delay);\n }\n\n /**\n * Attempt to reconnect to the server\n */\n private async attemptReconnect(): Promise<void> {\n try {\n log('Attempting to reconnect...', {\n Attempt: this.reconnectAttempts,\n });\n\n await this.connectToServer();\n\n // Reset reconnect attempts on successful connection\n this.reconnectAttempts = 0;\n\n log('Reconnection successful');\n\n if (this.options.events?.onReconnected) {\n this.options.events.onReconnected({\n clientId: this.clientId,\n });\n }\n } catch (error) {\n log('Reconnection failed', {\n Error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n\n // Schedule next attempt\n this.scheduleReconnect();\n }\n }\n\n /**\n * Enable auto-reconnection\n */\n public enableAutoReconnect(): void {\n this.shouldReconnect = true;\n }\n\n /**\n * Disable auto-reconnection\n */\n public disableAutoReconnect(): void {\n this.shouldReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n /**\n * Get connection status\n */\n public getConnectionStatus(): {\n isConnected: boolean;\n reconnectAttempts: number;\n autoReconnectEnabled: boolean;\n } {\n return {\n isConnected: this.isConnected,\n reconnectAttempts: this.reconnectAttempts,\n autoReconnectEnabled: this.shouldReconnect,\n };\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import WebSocket, { type RawData } from 'ws';\nimport type { WebSocketOptions, WebSocketRoute, WebSocketType } 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 { WebSocketClientProps } from './websocket-client.interface.js';\nimport { generateClientId, log, parseServerMessage } from './utils.js';\nimport WebSocketBase from './websocket-base.js';\nimport type { ApplicationConfig } from '../application/base-application.interface.js';\nimport path from 'path';\nimport { safeSerializeError } from '../error/error-reporter.js';\nimport { baseDir } from '../index.js';\n\nexport default class WebSocketClient extends WebSocketBase {\n protected defaultRoutes: WebSocketRoute[] = [\n {\n type: 'system',\n action: 'clientList',\n controllerName: 'system',\n },\n ];\n\n private applicationConfig: ApplicationConfig;\n private options: WebSocketOptions;\n private redisInstance: RedisInstance;\n private queueManager: QueueManager;\n private databaseInstance: DatabaseInstance;\n private ws?: WebSocket;\n private clientId?: string;\n private isConnected: boolean = false;\n private reconnectAttempts: number = 0;\n private maxReconnectAttempts: number = 10;\n private reconnectDelay: number = 1000; // Start with 1 second\n private reconnectTimer?: NodeJS.Timeout;\n private shouldReconnect: boolean = true;\n\n constructor(props: WebSocketClientProps) {\n super();\n\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 }\n\n public get type(): WebSocketType {\n return 'client';\n }\n\n public async load(): Promise<void> {\n const libraryControllersDirectory = path.join(baseDir, 'websocket', 'controllers', 'client');\n\n await this.configureRoutes(this.defaultRoutes, libraryControllersDirectory);\n\n await this.configureRoutes(this.routes, this.options.controllersDirectory);\n }\n\n public async connectToServer(): Promise<void> {\n const url = this.options.url;\n // const host = this.options.host;\n // const port = this.options.port;\n\n return new Promise(resolve => {\n const ws = new WebSocket(url);\n\n ws.on('open', () => {\n this.clientId = generateClientId();\n this.isConnected = true;\n\n log('Connected to server', { ID: this.clientId });\n\n if (this.options.events?.onConnected) {\n this.options.events.onConnected({\n ws,\n clientId: this.clientId,\n joinRoom: ({\n userId,\n userType,\n username,\n roomName,\n }: {\n userId?: string;\n userType?: string;\n username: string;\n roomName: string;\n }) => {\n this.sendClientMessage({\n type: 'system',\n action: 'joinRoom',\n data: {\n userId,\n userType,\n username,\n roomName,\n },\n });\n },\n });\n }\n\n resolve();\n });\n\n ws.on('message', this.handleIncomingMessage);\n\n ws.on('close', code => {\n this.isConnected = false;\n log('Connection to server closed', { Code: code });\n\n if (this.options.events?.onDisconnected) {\n this.options.events.onDisconnected({ clientId: this.clientId });\n }\n\n // Clean up event listeners to prevent memory leaks\n ws.removeAllListeners();\n this.ws = undefined;\n this.clientId = undefined;\n\n // Attempt to reconnect if not manually disconnected\n if (this.shouldReconnect) {\n this.scheduleReconnect();\n }\n });\n\n ws.on('error', error => {\n log('WebSocket error', { error: error.message });\n\n if (this.options.events?.onError) {\n this.options.events.onError({ error });\n }\n });\n\n this.ws = ws;\n });\n }\n\n protected getControllerDependencies(): {\n sendMessage: (data: unknown) => void;\n redisInstance: RedisInstance;\n queueManager: QueueManager;\n databaseInstance: DatabaseInstance;\n } {\n return {\n sendMessage: this.sendMessage,\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n };\n }\n protected shouldPrintRoutes(): boolean {\n return this.options.debug?.printRoutes ?? false;\n }\n\n private handleIncomingMessage = async (message: RawData): Promise<void> => {\n if (!this.ws || !this.clientId) {\n log('WebSocket not initialized or client ID not set');\n\n return;\n }\n\n if (this.options.events?.onMessage) {\n const parsedMessage = parseServerMessage(message);\n\n this.options.events.onMessage({\n ws: this.ws,\n clientId: this.clientId,\n data: parsedMessage as { type: string; action: string; data: unknown },\n redisInstance: this.redisInstance,\n queueManager: this.queueManager,\n databaseInstance: this.databaseInstance,\n });\n }\n\n await this.handleServerMessage(this.ws, message, this.clientId);\n };\n\n protected handleMessageError(clientId: string, error: string): void {\n log(error);\n }\n\n public sendClientMessage = (data: unknown, binary: boolean = false): void => {\n if (!this.ws) {\n log('WebSocket not initialized');\n\n return;\n }\n\n const webSocketMessage = JSON.stringify(data);\n\n this.ws.send(webSocketMessage, { binary });\n };\n\n public sendMessage = (data: unknown): void => {\n this.sendClientMessage(data);\n };\n\n public disconnect(): void {\n // Disable auto-reconnect on manual disconnect\n this.shouldReconnect = false;\n\n // Clear any pending reconnect timer\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n if (this.ws && this.isConnected) {\n this.ws.removeAllListeners();\n this.ws.close();\n this.ws = undefined;\n this.clientId = undefined;\n this.isConnected = false;\n log('WebSocket client disconnected');\n }\n }\n\n public isClientConnected(): boolean {\n return this.isConnected && this.ws?.readyState === WebSocket.OPEN;\n }\n\n /**\n * Schedule a reconnection attempt with exponential backoff\n */\n private scheduleReconnect(): void {\n // Don't reconnect if we've exceeded max attempts\n if (this.reconnectAttempts >= this.maxReconnectAttempts) {\n log('Max reconnection attempts reached', {\n Attempts: this.reconnectAttempts,\n });\n\n if (this.options.events?.onReconnectFailed) {\n this.options.events.onReconnectFailed({\n attempts: this.reconnectAttempts,\n });\n }\n\n return;\n }\n\n // Calculate delay with exponential backoff (max 30 seconds)\n const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts), 30000);\n this.reconnectAttempts++;\n\n log('Scheduling reconnection', {\n Attempt: this.reconnectAttempts,\n Delay: `${delay}ms`,\n });\n\n if (this.options.events?.onReconnecting) {\n this.options.events.onReconnecting({\n attempt: this.reconnectAttempts,\n delay,\n });\n }\n\n this.reconnectTimer = setTimeout(() => {\n this.attemptReconnect();\n }, delay);\n }\n\n /**\n * Attempt to reconnect to the server\n */\n private async attemptReconnect(): Promise<void> {\n try {\n log('Attempting to reconnect...', {\n Attempt: this.reconnectAttempts,\n });\n\n await this.connectToServer();\n\n // Reset reconnect attempts on successful connection\n this.reconnectAttempts = 0;\n\n log('Reconnection successful');\n\n if (this.options.events?.onReconnected) {\n this.options.events.onReconnected({\n clientId: this.clientId,\n });\n }\n } catch (error) {\n log('Reconnection failed', {\n Error: error instanceof Error ? error.message : safeSerializeError(error),\n });\n\n // Schedule next attempt\n this.scheduleReconnect();\n }\n }\n\n /**\n * Enable auto-reconnection\n */\n public enableAutoReconnect(): void {\n this.shouldReconnect = true;\n }\n\n /**\n * Disable auto-reconnection\n */\n public disableAutoReconnect(): void {\n this.shouldReconnect = false;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n }\n\n /**\n * Get connection status\n */\n public getConnectionStatus(): {\n isConnected: boolean;\n reconnectAttempts: number;\n autoReconnectEnabled: boolean;\n } {\n return {\n isConnected: this.isConnected,\n reconnectAttempts: this.reconnectAttempts,\n autoReconnectEnabled: this.shouldReconnect,\n };\n }\n\n /**\n * Destroy the client and clean up all resources.\n * This should be called when the client is no longer needed to prevent memory leaks.\n */\n public destroy(): void {\n // Ensure all timers are cleared\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = undefined;\n }\n\n // Disable reconnection\n this.shouldReconnect = false;\n\n // Clean up WebSocket connection\n if (this.ws) {\n this.ws.removeAllListeners();\n if (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING) {\n this.ws.close();\n }\n this.ws = undefined;\n }\n\n this.clientId = undefined;\n this.isConnected = false;\n this.reconnectAttempts = 0;\n\n log('WebSocket client destroyed');\n }\n}\n"],
5
+ "mappings": "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",
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.49",
3
+ "version": "1.0.50",
4
4
  "description": "PXL Node.js Framework",
5
5
  "repository": {
6
6
  "type": "git",