Lazily load sockets
All checks were successful
armco-org/node-starter-kit/pipeline/head This commit looks good
All checks were successful
armco-org/node-starter-kit/pipeline/head This commit looks good
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user