Lazily load sockets
All checks were successful
armco-org/node-starter-kit/pipeline/head This commit looks good

This commit is contained in:
2025-12-17 21:11:03 +05:30
parent e3acc20cb6
commit fcd0aa10c3
3 changed files with 58 additions and 17 deletions

View File

@@ -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",

View File

@@ -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<void> {
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<ServerOptions> = {
...(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

View File

@@ -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<void>
/**
* Get the Socket.IO server instance