@morojs/moro 1.2.1 → 1.4.0

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 (92) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +61 -7
  3. package/dist/core/config/file-loader.js +31 -25
  4. package/dist/core/config/file-loader.js.map +1 -1
  5. package/dist/core/config/schema.d.ts +2 -2
  6. package/dist/core/config/schema.js +1 -1
  7. package/dist/core/config/schema.js.map +1 -1
  8. package/dist/core/config/types.d.ts +147 -0
  9. package/dist/core/config/types.js +124 -0
  10. package/dist/core/config/types.js.map +1 -0
  11. package/dist/core/config/typescript-loader.d.ts +6 -0
  12. package/dist/core/config/typescript-loader.js +268 -0
  13. package/dist/core/config/typescript-loader.js.map +1 -0
  14. package/dist/core/config/validation.d.ts +18 -0
  15. package/dist/core/config/validation.js +134 -0
  16. package/dist/core/config/validation.js.map +1 -0
  17. package/dist/core/docs/openapi-generator.js +6 -6
  18. package/dist/core/docs/openapi-generator.js.map +1 -1
  19. package/dist/core/docs/schema-to-openapi.d.ts +7 -0
  20. package/dist/core/docs/schema-to-openapi.js +124 -0
  21. package/dist/core/docs/schema-to-openapi.js.map +1 -0
  22. package/dist/core/docs/zod-to-openapi.d.ts +2 -0
  23. package/dist/core/docs/zod-to-openapi.js.map +1 -1
  24. package/dist/core/events/event-bus.js +4 -0
  25. package/dist/core/events/event-bus.js.map +1 -1
  26. package/dist/core/framework.d.ts +29 -6
  27. package/dist/core/framework.js +117 -18
  28. package/dist/core/framework.js.map +1 -1
  29. package/dist/core/http/http-server.d.ts +33 -0
  30. package/dist/core/http/http-server.js +329 -28
  31. package/dist/core/http/http-server.js.map +1 -1
  32. package/dist/core/networking/adapters/index.d.ts +3 -0
  33. package/dist/core/networking/adapters/index.js +10 -0
  34. package/dist/core/networking/adapters/index.js.map +1 -0
  35. package/dist/core/networking/adapters/socketio-adapter.d.ts +16 -0
  36. package/dist/core/networking/adapters/socketio-adapter.js +244 -0
  37. package/dist/core/networking/adapters/socketio-adapter.js.map +1 -0
  38. package/dist/core/networking/adapters/ws-adapter.d.ts +54 -0
  39. package/dist/core/networking/adapters/ws-adapter.js +383 -0
  40. package/dist/core/networking/adapters/ws-adapter.js.map +1 -0
  41. package/dist/core/networking/websocket-adapter.d.ts +171 -0
  42. package/dist/core/networking/websocket-adapter.js +5 -0
  43. package/dist/core/networking/websocket-adapter.js.map +1 -0
  44. package/dist/core/networking/websocket-manager.d.ts +53 -17
  45. package/dist/core/networking/websocket-manager.js +166 -108
  46. package/dist/core/networking/websocket-manager.js.map +1 -1
  47. package/dist/core/routing/index.d.ts +13 -13
  48. package/dist/core/routing/index.js.map +1 -1
  49. package/dist/core/utilities/container.d.ts +1 -0
  50. package/dist/core/utilities/container.js +11 -1
  51. package/dist/core/utilities/container.js.map +1 -1
  52. package/dist/core/validation/adapters.d.ts +51 -0
  53. package/dist/core/validation/adapters.js +135 -0
  54. package/dist/core/validation/adapters.js.map +1 -0
  55. package/dist/core/validation/index.d.ts +14 -11
  56. package/dist/core/validation/index.js +37 -26
  57. package/dist/core/validation/index.js.map +1 -1
  58. package/dist/core/validation/schema-interface.d.ts +36 -0
  59. package/dist/core/validation/schema-interface.js +68 -0
  60. package/dist/core/validation/schema-interface.js.map +1 -0
  61. package/dist/index.d.ts +6 -1
  62. package/dist/index.js +14 -3
  63. package/dist/index.js.map +1 -1
  64. package/dist/moro.d.ts +8 -0
  65. package/dist/moro.js +339 -14
  66. package/dist/moro.js.map +1 -1
  67. package/dist/types/core.d.ts +17 -0
  68. package/package.json +42 -14
  69. package/src/core/config/file-loader.ts +34 -25
  70. package/src/core/config/schema.ts +1 -1
  71. package/src/core/config/types.ts +277 -0
  72. package/src/core/config/typescript-loader.ts +571 -0
  73. package/src/core/config/validation.ts +145 -0
  74. package/src/core/docs/openapi-generator.ts +7 -6
  75. package/src/core/docs/schema-to-openapi.ts +148 -0
  76. package/src/core/docs/zod-to-openapi.ts +2 -0
  77. package/src/core/events/event-bus.ts +5 -0
  78. package/src/core/framework.ts +121 -28
  79. package/src/core/http/http-server.ts +377 -28
  80. package/src/core/networking/adapters/index.ts +16 -0
  81. package/src/core/networking/adapters/socketio-adapter.ts +252 -0
  82. package/src/core/networking/adapters/ws-adapter.ts +425 -0
  83. package/src/core/networking/websocket-adapter.ts +217 -0
  84. package/src/core/networking/websocket-manager.ts +185 -127
  85. package/src/core/routing/index.ts +13 -13
  86. package/src/core/utilities/container.ts +14 -1
  87. package/src/core/validation/adapters.ts +147 -0
  88. package/src/core/validation/index.ts +60 -38
  89. package/src/core/validation/schema-interface.ts +100 -0
  90. package/src/index.ts +25 -2
  91. package/src/moro.ts +405 -15
  92. package/src/types/core.ts +18 -0
@@ -0,0 +1,217 @@
1
+ // WebSocket Adapter Interface for Moro Framework
2
+ // Provides a common interface for different WebSocket implementations
3
+
4
+ export interface WebSocketAdapterOptions {
5
+ compression?: boolean;
6
+ cors?: {
7
+ origin?: string | string[] | boolean;
8
+ methods?: string[];
9
+ credentials?: boolean;
10
+ };
11
+ path?: string;
12
+ maxPayloadLength?: number;
13
+ idleTimeout?: number;
14
+ [key: string]: any; // Allow adapter-specific options
15
+ }
16
+
17
+ /**
18
+ * Abstract WebSocket adapter interface
19
+ * Allows the framework to work with different WebSocket implementations
20
+ */
21
+ export interface WebSocketAdapter {
22
+ /**
23
+ * Initialize the WebSocket server with the given HTTP server
24
+ */
25
+ initialize(httpServer: any, options?: WebSocketAdapterOptions): Promise<void>;
26
+
27
+ /**
28
+ * Create a namespace for organizing WebSocket connections
29
+ */
30
+ createNamespace(namespace: string): WebSocketNamespace;
31
+
32
+ /**
33
+ * Get the default namespace (usually '/')
34
+ */
35
+ getDefaultNamespace(): WebSocketNamespace;
36
+
37
+ /**
38
+ * Close the WebSocket server and all connections
39
+ */
40
+ close(): Promise<void>;
41
+
42
+ /**
43
+ * Set compression configuration
44
+ */
45
+ setCompression(enabled: boolean, options?: any): void;
46
+
47
+ /**
48
+ * Set custom ID generator for connections
49
+ */
50
+ setCustomIdGenerator(generator: () => string): void;
51
+
52
+ /**
53
+ * Get adapter name/type
54
+ */
55
+ getAdapterName(): string;
56
+
57
+ /**
58
+ * Get connection count across all namespaces
59
+ */
60
+ getConnectionCount(): number;
61
+ }
62
+
63
+ /**
64
+ * WebSocket namespace interface
65
+ * Represents a logical grouping of WebSocket connections
66
+ */
67
+ export interface WebSocketNamespace {
68
+ /**
69
+ * Listen for connection events
70
+ */
71
+ on(event: 'connection', handler: (socket: WebSocketConnection) => void): void;
72
+
73
+ /**
74
+ * Emit event to all connected sockets in this namespace
75
+ */
76
+ emit(event: string, data: any): void;
77
+
78
+ /**
79
+ * Emit to specific room(s)
80
+ */
81
+ to(room: string | string[]): WebSocketEmitter;
82
+
83
+ /**
84
+ * Emit to sockets except those in specified room(s)
85
+ */
86
+ except(room: string | string[]): WebSocketEmitter;
87
+
88
+ /**
89
+ * Get all connected sockets
90
+ */
91
+ getSockets(): WebSocketConnection[];
92
+
93
+ /**
94
+ * Get connection count for this namespace
95
+ */
96
+ getConnectionCount(): number;
97
+
98
+ /**
99
+ * Use middleware for this namespace
100
+ */
101
+ use(middleware: (socket: WebSocketConnection, next: (err?: Error) => void) => void): void;
102
+ }
103
+
104
+ /**
105
+ * WebSocket connection interface
106
+ * Represents an individual client connection
107
+ */
108
+ export interface WebSocketConnection {
109
+ /** Unique connection ID */
110
+ id: string;
111
+
112
+ /** Client IP address */
113
+ ip?: string;
114
+
115
+ /** Connection headers */
116
+ headers?: Record<string, string>;
117
+
118
+ /** Custom data storage */
119
+ data: Record<string, any>;
120
+
121
+ /**
122
+ * Listen for events from this socket
123
+ */
124
+ on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void;
125
+
126
+ /**
127
+ * Listen for any event from this socket
128
+ */
129
+ onAny(handler: (event: string, ...args: any[]) => void): void;
130
+
131
+ /**
132
+ * Emit event to this socket
133
+ */
134
+ emit(event: string, data: any): void;
135
+
136
+ /**
137
+ * Emit with compression
138
+ */
139
+ compressedEmit?(event: string, data: any): void;
140
+
141
+ /**
142
+ * Join a room
143
+ */
144
+ join(room: string | string[]): void;
145
+
146
+ /**
147
+ * Leave a room
148
+ */
149
+ leave(room: string | string[]): void;
150
+
151
+ /**
152
+ * Emit to specific room(s)
153
+ */
154
+ to(room: string | string[]): WebSocketEmitter;
155
+
156
+ /**
157
+ * Emit to all sockets except this one
158
+ */
159
+ broadcast: WebSocketEmitter;
160
+
161
+ /**
162
+ * Get rooms this socket has joined
163
+ */
164
+ getRooms(): Set<string>;
165
+
166
+ /**
167
+ * Disconnect this socket
168
+ */
169
+ disconnect(close?: boolean): void;
170
+
171
+ /**
172
+ * Check if socket is connected
173
+ */
174
+ connected: boolean;
175
+ }
176
+
177
+ /**
178
+ * WebSocket emitter interface for chaining operations
179
+ */
180
+ export interface WebSocketEmitter {
181
+ /**
182
+ * Emit to target sockets
183
+ */
184
+ emit(event: string, data: any): void;
185
+
186
+ /**
187
+ * Target specific room(s)
188
+ */
189
+ to(room: string | string[]): WebSocketEmitter;
190
+
191
+ /**
192
+ * Exclude specific room(s)
193
+ */
194
+ except(room: string | string[]): WebSocketEmitter;
195
+
196
+ /**
197
+ * Use compression for this emit
198
+ */
199
+ compress(compress: boolean): WebSocketEmitter;
200
+ }
201
+
202
+ /**
203
+ * WebSocket middleware function type
204
+ */
205
+ export type WebSocketMiddleware = (
206
+ socket: WebSocketConnection,
207
+ next: (err?: Error) => void
208
+ ) => void;
209
+
210
+ /**
211
+ * WebSocket event handler type
212
+ */
213
+ export type WebSocketEventHandler = (
214
+ socket: WebSocketConnection,
215
+ data: any,
216
+ callback?: (response?: any) => void
217
+ ) => void | Promise<void>;
@@ -1,115 +1,114 @@
1
- // src/core/websocket-manager.ts
2
- import { Server as SocketIOServer, Socket, Namespace } from 'socket.io';
1
+ // WebSocket Manager for Moro Framework
2
+ // Manages WebSocket connections using pluggable adapters
3
3
  import { Container } from '../utilities';
4
4
  import { CircuitBreaker } from '../utilities';
5
5
  import { ModuleConfig, WebSocketDefinition } from '../../types/module';
6
+ import { WebSocketAdapter, WebSocketNamespace, WebSocketConnection } from './websocket-adapter';
7
+ import { createFrameworkLogger } from '../logger';
6
8
 
7
9
  export class WebSocketManager {
8
10
  private circuitBreakers = new Map<string, CircuitBreaker>();
9
11
  private rateLimiters = new Map<string, Map<string, { count: number; resetTime: number }>>();
10
- private compressionEnabled = true;
11
- private customIdGenerator?: () => string;
12
+ private logger = createFrameworkLogger('WebSocketManager');
12
13
 
13
14
  constructor(
14
- private io: SocketIOServer,
15
+ private adapter: WebSocketAdapter,
15
16
  private container: Container
16
17
  ) {
17
- this.setupAdvancedFeatures();
18
+ this.logger.info(`Initialized with ${adapter.getAdapterName()} adapter`, 'AdapterInit');
18
19
  }
19
20
 
20
- private setupAdvancedFeatures() {
21
- // Enable compression for WebSocket messages
22
- if (this.compressionEnabled) {
23
- (this.io.engine as any).compression = true;
24
- (this.io.engine as any).perMessageDeflate = {
25
- threshold: 1024,
26
- concurrencyLimit: 10,
27
- memLevel: 8,
28
- };
29
- }
30
-
31
- // Custom session ID generation if provided
32
- if (this.customIdGenerator) {
33
- (this.io.engine as any).generateId = this.customIdGenerator;
34
- }
35
-
36
- // Global WebSocket middleware for advanced features
37
- this.io.use((socket, next) => {
38
- // Add binary message handling
39
- socket.onAny((event, ...args) => {
40
- // Handle binary frames efficiently
41
- args.forEach((arg, index) => {
42
- if (Buffer.isBuffer(arg)) {
43
- // Process binary data with optimizations
44
- args[index] = this.processBinaryData(arg);
45
- }
46
- });
47
- });
48
-
49
- // Add compression per message
50
- (socket as any).compressedEmit = (event: string, data: any) => {
51
- if (this.compressionEnabled && this.shouldCompress(data)) {
52
- socket.compress(true).emit(event, data);
53
- } else {
54
- socket.emit(event, data);
55
- }
56
- };
57
-
58
- // Add heartbeat mechanism
59
- (socket as any).heartbeat = () => {
60
- socket.emit('heartbeat', { timestamp: Date.now() });
61
- };
62
-
63
- next();
64
- });
21
+ /**
22
+ * Set custom ID generator for the adapter
23
+ */
24
+ setCustomIdGenerator(generator: () => string): void {
25
+ this.adapter.setCustomIdGenerator(generator);
65
26
  }
66
27
 
67
- setCustomIdGenerator(generator: () => string) {
68
- this.customIdGenerator = generator;
69
- (this.io.engine as any).generateId = generator;
28
+ /**
29
+ * Enable compression for the adapter
30
+ */
31
+ enableCompression(options?: any): void {
32
+ this.adapter.setCompression(true, options);
70
33
  }
71
34
 
72
- enableCompression(options?: {
73
- threshold?: number;
74
- concurrencyLimit?: number;
75
- memLevel?: number;
76
- }) {
77
- this.compressionEnabled = true;
78
- if (options) {
79
- (this.io.engine as any).perMessageDeflate = {
80
- threshold: options.threshold || 1024,
81
- concurrencyLimit: options.concurrencyLimit || 10,
82
- memLevel: options.memLevel || 8,
83
- };
84
- }
35
+ /**
36
+ * Get the underlying adapter
37
+ */
38
+ getAdapter(): WebSocketAdapter {
39
+ return this.adapter;
85
40
  }
86
41
 
87
- private processBinaryData(buffer: Buffer): Buffer {
88
- // Optimize binary data processing
89
- // Could add compression, validation, etc.
90
- return buffer;
42
+ /**
43
+ * Get connection count across all namespaces
44
+ */
45
+ getConnectionCount(): number {
46
+ return this.adapter.getConnectionCount();
91
47
  }
92
48
 
93
- private shouldCompress(data: any): boolean {
94
- // Determine if data should be compressed
95
- const serialized = JSON.stringify(data);
96
- return serialized.length > 1024; // Compress if larger than 1KB
49
+ /**
50
+ * Create or get a namespace
51
+ */
52
+ getNamespace(namespace: string): WebSocketNamespace {
53
+ return this.adapter.createNamespace(namespace);
97
54
  }
98
55
 
56
+ /**
57
+ * Register WebSocket handlers for a module
58
+ */
99
59
  async registerHandler(
100
- namespace: Namespace,
60
+ namespace: WebSocketNamespace,
101
61
  wsConfig: WebSocketDefinition,
102
62
  moduleConfig: ModuleConfig
103
63
  ): Promise<void> {
104
- namespace.on('connection', (socket: Socket) => {
105
- console.log(`WebSocket connected to /${moduleConfig.name}: ${socket.id}`);
106
- this.setupSocketHandlers(socket, wsConfig, moduleConfig);
64
+ namespace.on('connection', (socket: WebSocketConnection) => {
65
+ this.logger.debug(`New connection: ${socket.id}`, 'Connection', {
66
+ namespace: namespace.constructor.name,
67
+ module: moduleConfig.name,
68
+ });
69
+
107
70
  this.setupSocketMiddleware(socket, moduleConfig.name);
71
+ this.setupSocketHandlers(socket, wsConfig, moduleConfig);
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Setup socket-specific middleware
77
+ */
78
+ private setupSocketMiddleware(socket: WebSocketConnection, moduleName: string): void {
79
+ // Add module context to socket data
80
+ socket.data.module = moduleName;
81
+ socket.data.connectedAt = Date.now();
82
+
83
+ // Setup heartbeat if supported
84
+ if (socket.compressedEmit) {
85
+ const heartbeatInterval = setInterval(() => {
86
+ if (socket.connected) {
87
+ socket.emit('heartbeat', { timestamp: Date.now() });
88
+ } else {
89
+ clearInterval(heartbeatInterval);
90
+ }
91
+ }, 30000); // 30 seconds
92
+
93
+ socket.on('disconnect', () => {
94
+ clearInterval(heartbeatInterval);
95
+ });
96
+ }
97
+
98
+ // Log disconnection
99
+ socket.on('disconnect', () => {
100
+ this.logger.debug(`Socket disconnected: ${socket.id}`, 'Disconnect', {
101
+ module: moduleName,
102
+ duration: Date.now() - socket.data.connectedAt,
103
+ });
108
104
  });
109
105
  }
110
106
 
107
+ /**
108
+ * Setup handlers for a specific WebSocket configuration
109
+ */
111
110
  private setupSocketHandlers(
112
- socket: Socket,
111
+ socket: WebSocketConnection,
113
112
  wsConfig: WebSocketDefinition,
114
113
  moduleConfig: ModuleConfig
115
114
  ): void {
@@ -129,7 +128,7 @@ export class WebSocketManager {
129
128
  return;
130
129
  }
131
130
 
132
- // Validation (Zod-only)
131
+ // Validation using Zod
133
132
  if (wsConfig.validation) {
134
133
  try {
135
134
  data = wsConfig.validation.parse(data);
@@ -163,42 +162,56 @@ export class WebSocketManager {
163
162
  // Handle response
164
163
  if (callback) {
165
164
  callback({ success: true, data: result });
166
- } else if (wsConfig.broadcast && result?.event) {
167
- socket.broadcast.emit(result.event, result.data);
168
- } else if (result) {
169
- socket.emit(`${wsConfig.event}:response`, result);
165
+ } else if (result !== undefined) {
166
+ socket.emit(`${wsConfig.event}:response`, { success: true, data: result });
167
+ }
168
+
169
+ // Handle room operations
170
+ if (wsConfig.rooms) {
171
+ wsConfig.rooms.forEach(room => socket.join(room));
172
+ }
173
+
174
+ // Handle broadcasting
175
+ if (wsConfig.broadcast && result !== undefined) {
176
+ socket.broadcast.emit(wsConfig.event, { success: true, data: result });
170
177
  }
171
178
  } catch (error) {
172
- const errorMessage = error instanceof Error ? error.message : String(error);
173
- const errorCode = (error as any)?.code || 'INTERNAL_ERROR';
174
- console.error(`WebSocket error in ${handlerKey}:`, errorMessage);
179
+ this.logger.error('WebSocket handler error', 'HandlerError', {
180
+ handler: handlerKey,
181
+ error: error instanceof Error ? error.message : String(error),
182
+ socketId: socket.id,
183
+ });
175
184
 
176
185
  const errorResponse = {
177
186
  success: false,
178
- error: errorMessage,
179
- code: errorCode,
187
+ error: 'Internal server error',
188
+ code: 'HANDLER_ERROR',
180
189
  };
181
190
 
182
- if (callback) {
183
- callback(errorResponse);
184
- } else {
185
- socket.emit('error', errorResponse);
186
- }
191
+ if (callback) callback(errorResponse);
192
+ else socket.emit('error', errorResponse);
187
193
  }
188
194
  });
189
195
  }
190
196
 
191
- private setupSocketMiddleware(socket: Socket, moduleName: string): void {
192
- socket.on('disconnect', reason => {
193
- console.log(`WebSocket disconnected from /${moduleName}: ${socket.id} (${reason})`);
194
- this.cleanup(socket.id);
195
- });
196
-
197
- socket.on('ping', () => {
198
- socket.emit('pong');
199
- });
197
+ /**
198
+ * Get or create circuit breaker for handler
199
+ */
200
+ private getCircuitBreaker(handlerKey: string): CircuitBreaker {
201
+ if (!this.circuitBreakers.has(handlerKey)) {
202
+ const circuitBreaker = new CircuitBreaker({
203
+ failureThreshold: 5,
204
+ resetTimeout: 60000,
205
+ monitoringPeriod: 10000,
206
+ });
207
+ this.circuitBreakers.set(handlerKey, circuitBreaker);
208
+ }
209
+ return this.circuitBreakers.get(handlerKey)!;
200
210
  }
201
211
 
212
+ /**
213
+ * Check rate limit for socket and handler
214
+ */
202
215
  private checkRateLimit(
203
216
  socketId: string,
204
217
  handlerKey: string,
@@ -210,41 +223,86 @@ export class WebSocketManager {
210
223
 
211
224
  const handlerLimiter = this.rateLimiters.get(handlerKey)!;
212
225
  const now = Date.now();
213
- const socketLimit = handlerLimiter.get(socketId);
226
+ const windowStart = now - rateLimit.window;
214
227
 
215
- if (!socketLimit || now > socketLimit.resetTime) {
216
- handlerLimiter.set(socketId, {
217
- count: 1,
218
- resetTime: now + rateLimit.window,
219
- });
228
+ // Clean old entries
229
+ for (const [id, data] of handlerLimiter.entries()) {
230
+ if (data.resetTime < windowStart) {
231
+ handlerLimiter.delete(id);
232
+ }
233
+ }
234
+
235
+ // Check current socket
236
+ const socketData = handlerLimiter.get(socketId);
237
+ if (!socketData) {
238
+ handlerLimiter.set(socketId, { count: 1, resetTime: now });
220
239
  return true;
221
240
  }
222
241
 
223
- if (socketLimit.count >= rateLimit.requests) {
242
+ if (socketData.resetTime < windowStart) {
243
+ socketData.count = 1;
244
+ socketData.resetTime = now;
245
+ return true;
246
+ }
247
+
248
+ if (socketData.count >= rateLimit.requests) {
224
249
  return false;
225
250
  }
226
251
 
227
- socketLimit.count++;
252
+ socketData.count++;
228
253
  return true;
229
254
  }
230
255
 
231
- private getCircuitBreaker(key: string): CircuitBreaker {
232
- if (!this.circuitBreakers.has(key)) {
233
- this.circuitBreakers.set(
234
- key,
235
- new CircuitBreaker({
236
- failureThreshold: 5,
237
- resetTimeout: 30000,
238
- monitoringPeriod: 10000,
239
- })
240
- );
256
+ /**
257
+ * Process binary data efficiently
258
+ */
259
+ private processBinaryData(buffer: Buffer): any {
260
+ // Example binary processing - can be extended based on needs
261
+ if (buffer.length === 0) return buffer;
262
+
263
+ // Simple compression check
264
+ if (buffer[0] === 0x1f && buffer[1] === 0x8b) {
265
+ // This is gzipped data
266
+ try {
267
+ const zlib = require('zlib');
268
+ return zlib.gunzipSync(buffer);
269
+ } catch {
270
+ return buffer;
271
+ }
241
272
  }
242
- return this.circuitBreakers.get(key)!;
273
+
274
+ return buffer;
243
275
  }
244
276
 
245
- private cleanup(socketId: string): void {
246
- this.rateLimiters.forEach(limiter => {
247
- limiter.delete(socketId);
248
- });
277
+ /**
278
+ * Check if data should be compressed
279
+ */
280
+ private shouldCompress(data: any): boolean {
281
+ if (typeof data === 'string') {
282
+ return data.length > 1024;
283
+ }
284
+ if (Buffer.isBuffer(data)) {
285
+ return data.length > 1024;
286
+ }
287
+ if (typeof data === 'object') {
288
+ return JSON.stringify(data).length > 1024;
289
+ }
290
+ return false;
291
+ }
292
+
293
+ /**
294
+ * Close the WebSocket manager and underlying adapter
295
+ */
296
+ async close(): Promise<void> {
297
+ this.logger.info('Closing WebSocket manager', 'Shutdown');
298
+
299
+ // Clear rate limiters
300
+ this.rateLimiters.clear();
301
+
302
+ // Clear circuit breakers
303
+ this.circuitBreakers.clear();
304
+
305
+ // Close adapter
306
+ await this.adapter.close();
249
307
  }
250
308
  }
@@ -1,7 +1,7 @@
1
1
  // Intelligent Routing System for Moro Framework
2
2
  // Schema-first with automatic middleware ordering and chainable API
3
3
 
4
- import { z, ZodSchema } from 'zod';
4
+ import { ValidationSchema } from '../validation/schema-interface';
5
5
  import { HttpRequest, HttpResponse } from '../http';
6
6
  import { createFrameworkLogger } from '../logger';
7
7
 
@@ -18,10 +18,10 @@ export type Middleware = (
18
18
 
19
19
  // Configuration interfaces
20
20
  export interface ValidationConfig {
21
- body?: ZodSchema;
22
- query?: ZodSchema;
23
- params?: ZodSchema;
24
- headers?: ZodSchema;
21
+ body?: ValidationSchema;
22
+ query?: ValidationSchema;
23
+ params?: ValidationSchema;
24
+ headers?: ValidationSchema;
25
25
  }
26
26
 
27
27
  export interface AuthConfig {
@@ -98,10 +98,10 @@ export interface ValidatedRequest<T = any> extends HttpRequest {
98
98
  export interface RouteBuilder {
99
99
  // Validation methods
100
100
  validate(config: ValidationConfig): RouteBuilder;
101
- body<T>(schema: ZodSchema<T>): RouteBuilder;
102
- query<T>(schema: ZodSchema<T>): RouteBuilder;
103
- params<T>(schema: ZodSchema<T>): RouteBuilder;
104
- headers<T>(schema: ZodSchema<T>): RouteBuilder;
101
+ body<T>(schema: ValidationSchema<T>): RouteBuilder;
102
+ query<T>(schema: ValidationSchema<T>): RouteBuilder;
103
+ params<T>(schema: ValidationSchema<T>): RouteBuilder;
104
+ headers<T>(schema: ValidationSchema<T>): RouteBuilder;
105
105
 
106
106
  // Security/Auth methods
107
107
  auth(config: AuthConfig): RouteBuilder;
@@ -148,25 +148,25 @@ export class IntelligentRouteBuilder implements RouteBuilder {
148
148
  return this;
149
149
  }
150
150
 
151
- body<T>(schema: ZodSchema<T>): RouteBuilder {
151
+ body<T>(schema: ValidationSchema<T>): RouteBuilder {
152
152
  if (!this.schema.validation) this.schema.validation = {};
153
153
  this.schema.validation.body = schema;
154
154
  return this;
155
155
  }
156
156
 
157
- query<T>(schema: ZodSchema<T>): RouteBuilder {
157
+ query<T>(schema: ValidationSchema<T>): RouteBuilder {
158
158
  if (!this.schema.validation) this.schema.validation = {};
159
159
  this.schema.validation.query = schema;
160
160
  return this;
161
161
  }
162
162
 
163
- params<T>(schema: ZodSchema<T>): RouteBuilder {
163
+ params<T>(schema: ValidationSchema<T>): RouteBuilder {
164
164
  if (!this.schema.validation) this.schema.validation = {};
165
165
  this.schema.validation.params = schema;
166
166
  return this;
167
167
  }
168
168
 
169
- headers<T>(schema: ZodSchema<T>): RouteBuilder {
169
+ headers<T>(schema: ValidationSchema<T>): RouteBuilder {
170
170
  if (!this.schema.validation) this.schema.validation = {};
171
171
  this.schema.validation.headers = schema;
172
172
  return this;