From fcd0aa10c353630fd3892ccb33eaa6adf8492e25 Mon Sep 17 00:00:00 2001 From: mohiit1502 Date: Wed, 17 Dec 2025 21:11:03 +0530 Subject: [PATCH] Lazily load sockets --- package.json | 8 ++-- v2/plugins/socket/SocketIOAdapter.ts | 61 +++++++++++++++++++++++----- v2/types/Socket.ts | 6 +-- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/package.json b/package.json index 5473056..f3672db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@armco/node-starter-kit", - "version": "2.0.5", + "version": "2.0.6", "description": "Modern plugin-based starter kit for Node.js applications with TypeScript, security, and observability", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -30,7 +30,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/ReStruct-Corporate-Advantage/node-starter-kit.git" + "url": "git+https://gitea.armco.dev/ReStruct-Corporate-Advantage/node-starter-kit.git" }, "keywords": [ "starter", @@ -42,9 +42,9 @@ "author": "Mohit Nagar (mohit.nagar@armco.tech)", "license": "ISC", "bugs": { - "url": "https://github.com/ReStruct-Corporate-Advantage/node-starter-kit/issues" + "url": "https://gitea.armco.dev/ReStruct-Corporate-Advantage/node-starter-kit/issues" }, - "homepage": "https://github.com/ReStruct-Corporate-Advantage/node-starter-kit#readme", + "homepage": "https://gitea.armco.dev/ReStruct-Corporate-Advantage/node-starter-kit#readme", "peerDependencies": { "cors": "^2.8.5", "express": "^4.18.2", diff --git a/v2/plugins/socket/SocketIOAdapter.ts b/v2/plugins/socket/SocketIOAdapter.ts index 27d5efb..4cfa8fb 100644 --- a/v2/plugins/socket/SocketIOAdapter.ts +++ b/v2/plugins/socket/SocketIOAdapter.ts @@ -1,10 +1,7 @@ import { Server as HttpServer } from 'http' -import { Server as SocketServer, Socket as SocketIOSocket, ServerOptions } from 'socket.io' -import { createAdapter as createRedisAdapter } from '@socket.io/redis-adapter' -import { createClient } from 'redis' -import { SocketAdapter, SocketConfig } from '../../types/Socket' -import { Logger } from '../../types/Logger' -import { verify } from 'jsonwebtoken' +import type { Server as SocketServer, Socket as SocketIOSocket, ServerOptions } from 'socket.io' +import type { SocketAdapter, SocketConfig } from '../../types/Socket' +import type { Logger } from '../../types/Logger' /** * Socket.IO adapter implementation @@ -30,6 +27,16 @@ export class SocketIOAdapter implements SocketAdapter { private logger?: Logger private redisPublishClient: any = null private redisSubscribeClient: any = null + + // Lazy-loaded deps cache + private libs: + | null + | { + SocketServer: any + createRedisAdapter: any + createClient: any + verifyJwt: any + } = null /** * Create a new Socket.IO adapter @@ -43,6 +50,37 @@ export class SocketIOAdapter implements SocketAdapter { this.config = config this.logger = logger } + + private async ensureLibsLoaded(): Promise { + if (this.libs) { + return + } + + try { + const socketIoMod: any = await import('socket.io') + const redisAdapterMod: any = await import('@socket.io/redis-adapter') + const redisMod: any = await import('redis') + const jwtMod: any = await import('jsonwebtoken') + + const SocketServerCtor = socketIoMod.Server || socketIoMod + const createRedisAdapter = redisAdapterMod.createAdapter || redisAdapterMod.default || redisAdapterMod + const createClient = redisMod.createClient || redisMod.default || redisMod + const verifyJwt = jwtMod.verify || jwtMod.default || jwtMod + + this.libs = { + SocketServer: SocketServerCtor, + createRedisAdapter, + createClient, + verifyJwt, + } + } catch (error) { + throw new Error( + `Failed to load Socket.IO dependencies. Please ensure these are installed:\n` + + `socket.io, redis, @socket.io/redis-adapter, jsonwebtoken\n\n` + + `Error: ${error}` + ) + } + } /** * Initialize the Socket.IO server @@ -54,6 +92,8 @@ export class SocketIOAdapter implements SocketAdapter { this.logger?.warn('Socket.IO server already initialized') return } + + await this.ensureLibsLoaded() const mergedOptions: Partial = { ...(this.config.options ?? {}), @@ -75,7 +115,7 @@ export class SocketIOAdapter implements SocketAdapter { const serverOptions = mergedOptions as ServerOptions - this.io = new SocketServer(this.httpServer, serverOptions) + this.io = new this.libs!.SocketServer(this.httpServer, serverOptions) // Set up Redis adapter if enabled if (this.config.redis?.enabled && this.config.redis.uri) { @@ -286,8 +326,9 @@ export class SocketIOAdapter implements SocketAdapter { this.logger?.info('Setting up Redis adapter for Socket.IO') try { + await this.ensureLibsLoaded() // Create Redis clients - this.redisPublishClient = createClient({ + this.redisPublishClient = this.libs!.createClient({ url: this.config.redis.uri, ...this.config.redis.options, }) @@ -308,7 +349,7 @@ export class SocketIOAdapter implements SocketAdapter { await this.redisSubscribeClient.connect() // Create and set the Redis adapter - const adapter = createRedisAdapter( + const adapter = this.libs!.createRedisAdapter( this.redisPublishClient, this.redisSubscribeClient ) @@ -346,7 +387,7 @@ export class SocketIOAdapter implements SocketAdapter { return next(new Error('Authentication error: Server misconfiguration')) } - const decoded = verify(token, secret) + const decoded = this.libs!.verifyJwt(token, secret) // Attach user data to socket socket.data.user = decoded diff --git a/v2/types/Socket.ts b/v2/types/Socket.ts index 14feace..d26b856 100644 --- a/v2/types/Socket.ts +++ b/v2/types/Socket.ts @@ -1,5 +1,5 @@ -import { Server as SocketServer, Socket as SocketIOSocket, ServerOptions } from 'socket.io' -import { Logger } from './Logger' +import type { Server as SocketServer, Socket as SocketIOSocket, ServerOptions } from 'socket.io' +import type { Logger } from './Logger' /** * Socket.IO adapter interface @@ -13,7 +13,7 @@ export interface SocketAdapter { * * @param options - Socket.IO server options */ - initialize(options?: ServerOptions): void + initialize(options?: ServerOptions): Promise /** * Get the Socket.IO server instance