@onebun/core 0.1.1 → 0.1.2
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.
- package/README.md +233 -0
- package/package.json +1 -1
- package/src/application.test.ts +119 -0
- package/src/application.ts +112 -5
- package/src/docs-examples.test.ts +753 -0
- package/src/index.ts +96 -0
- package/src/module.ts +10 -4
- package/src/redis-client.ts +502 -0
- package/src/shared-redis.ts +231 -0
- package/src/types.ts +50 -0
- package/src/ws-base-gateway.test.ts +479 -0
- package/src/ws-base-gateway.ts +514 -0
- package/src/ws-client.test.ts +511 -0
- package/src/ws-client.ts +628 -0
- package/src/ws-client.types.ts +129 -0
- package/src/ws-decorators.test.ts +331 -0
- package/src/ws-decorators.ts +417 -0
- package/src/ws-guards.test.ts +334 -0
- package/src/ws-guards.ts +298 -0
- package/src/ws-handler.ts +658 -0
- package/src/ws-integration.test.ts +517 -0
- package/src/ws-pattern-matcher.test.ts +152 -0
- package/src/ws-pattern-matcher.ts +240 -0
- package/src/ws-service-definition.ts +223 -0
- package/src/ws-socketio-protocol.test.ts +344 -0
- package/src/ws-socketio-protocol.ts +567 -0
- package/src/ws-storage-memory.test.ts +246 -0
- package/src/ws-storage-memory.ts +222 -0
- package/src/ws-storage-redis.ts +302 -0
- package/src/ws-storage.ts +210 -0
- package/src/ws.types.ts +342 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Client Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the typed WebSocket client.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { WsServiceDefinition, WsGatewayDefinition } from './ws-service-definition';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Options for WebSocket client
|
|
11
|
+
*/
|
|
12
|
+
export interface WsClientOptions {
|
|
13
|
+
/** WebSocket server URL */
|
|
14
|
+
url: string;
|
|
15
|
+
/** Authentication options */
|
|
16
|
+
auth?: {
|
|
17
|
+
/** Bearer token */
|
|
18
|
+
token?: string;
|
|
19
|
+
/** Custom auth payload getter */
|
|
20
|
+
getAuth?: () => Record<string, unknown>;
|
|
21
|
+
};
|
|
22
|
+
/** Enable automatic reconnection */
|
|
23
|
+
reconnect?: boolean;
|
|
24
|
+
/** Reconnection interval in milliseconds */
|
|
25
|
+
reconnectInterval?: number;
|
|
26
|
+
/** Maximum reconnection attempts */
|
|
27
|
+
maxReconnectAttempts?: number;
|
|
28
|
+
/** Timeout for requests in milliseconds */
|
|
29
|
+
timeout?: number;
|
|
30
|
+
/** Socket.IO specific: transports to use */
|
|
31
|
+
transports?: ('websocket' | 'polling')[];
|
|
32
|
+
/** Namespace to connect to */
|
|
33
|
+
namespace?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Connection state
|
|
38
|
+
*/
|
|
39
|
+
export enum WsConnectionState {
|
|
40
|
+
DISCONNECTED = 'disconnected',
|
|
41
|
+
CONNECTING = 'connecting',
|
|
42
|
+
CONNECTED = 'connected',
|
|
43
|
+
RECONNECTING = 'reconnecting',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Event listener type
|
|
48
|
+
*/
|
|
49
|
+
export type WsEventListener<T = unknown> = (data: T, params?: Record<string, string>) => void;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Client event types
|
|
53
|
+
*/
|
|
54
|
+
export type WsClientEvent =
|
|
55
|
+
| 'connect'
|
|
56
|
+
| 'disconnect'
|
|
57
|
+
| 'error'
|
|
58
|
+
| 'reconnect'
|
|
59
|
+
| 'reconnect_attempt'
|
|
60
|
+
| 'reconnect_failed';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Client event listener types
|
|
64
|
+
*/
|
|
65
|
+
export interface WsClientEventListeners {
|
|
66
|
+
connect: () => void;
|
|
67
|
+
disconnect: (reason: string) => void;
|
|
68
|
+
error: (error: Error) => void;
|
|
69
|
+
reconnect: (attempt: number) => void;
|
|
70
|
+
reconnect_attempt: (attempt: number) => void;
|
|
71
|
+
reconnect_failed: () => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Gateway client interface
|
|
76
|
+
*/
|
|
77
|
+
export interface WsGatewayClient {
|
|
78
|
+
/** Send an event and wait for acknowledgement */
|
|
79
|
+
emit<T = unknown>(event: string, data?: unknown): Promise<T>;
|
|
80
|
+
/** Subscribe to events */
|
|
81
|
+
on<T = unknown>(event: string, listener: WsEventListener<T>): void;
|
|
82
|
+
/** Unsubscribe from events */
|
|
83
|
+
off(event: string, listener?: WsEventListener): void;
|
|
84
|
+
/** Send event without waiting for response */
|
|
85
|
+
send(event: string, data?: unknown): void;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Main WebSocket client interface
|
|
90
|
+
*/
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
92
|
+
export interface WsClient<TDef extends WsServiceDefinition = WsServiceDefinition> {
|
|
93
|
+
/** Connect to WebSocket server */
|
|
94
|
+
connect(): Promise<void>;
|
|
95
|
+
/** Disconnect from WebSocket server */
|
|
96
|
+
disconnect(): void;
|
|
97
|
+
/** Check if connected */
|
|
98
|
+
isConnected(): boolean;
|
|
99
|
+
/** Get current connection state */
|
|
100
|
+
getState(): WsConnectionState;
|
|
101
|
+
/** Subscribe to client events */
|
|
102
|
+
on<E extends WsClientEvent>(event: E, listener: WsClientEventListeners[E]): void;
|
|
103
|
+
/** Unsubscribe from client events */
|
|
104
|
+
off<E extends WsClientEvent>(event: E, listener?: WsClientEventListeners[E]): void;
|
|
105
|
+
/** Access gateway by name */
|
|
106
|
+
[gatewayName: string]: WsGatewayClient | unknown;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Extract gateway names from service definition
|
|
111
|
+
*/
|
|
112
|
+
export type ExtractGatewayNames<TDef extends WsServiceDefinition> =
|
|
113
|
+
TDef['_gateways'] extends Map<infer K, WsGatewayDefinition> ? K : never;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Typed service client
|
|
117
|
+
*/
|
|
118
|
+
export type TypedWsClient<TDef extends WsServiceDefinition> = WsClient<TDef> & {
|
|
119
|
+
[K in ExtractGatewayNames<TDef> & string]: WsGatewayClient;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Pending request for acknowledgement
|
|
124
|
+
*/
|
|
125
|
+
export interface PendingRequest {
|
|
126
|
+
resolve: (value: unknown) => void;
|
|
127
|
+
reject: (error: Error) => void;
|
|
128
|
+
timeout: ReturnType<typeof setTimeout>;
|
|
129
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Decorators Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
describe,
|
|
7
|
+
it,
|
|
8
|
+
expect,
|
|
9
|
+
} from 'bun:test';
|
|
10
|
+
|
|
11
|
+
import { BaseWebSocketGateway } from './ws-base-gateway';
|
|
12
|
+
import {
|
|
13
|
+
WebSocketGateway,
|
|
14
|
+
OnConnect,
|
|
15
|
+
OnDisconnect,
|
|
16
|
+
OnJoinRoom,
|
|
17
|
+
OnLeaveRoom,
|
|
18
|
+
OnMessage,
|
|
19
|
+
Client,
|
|
20
|
+
Socket,
|
|
21
|
+
MessageData,
|
|
22
|
+
RoomName,
|
|
23
|
+
PatternParams,
|
|
24
|
+
WsServer,
|
|
25
|
+
getGatewayMetadata,
|
|
26
|
+
isWebSocketGateway,
|
|
27
|
+
getWsHandlers,
|
|
28
|
+
getWsParamMetadata,
|
|
29
|
+
} from './ws-decorators';
|
|
30
|
+
import { WsHandlerType, WsParamType } from './ws.types';
|
|
31
|
+
|
|
32
|
+
describe('ws-decorators', () => {
|
|
33
|
+
describe('@WebSocketGateway', () => {
|
|
34
|
+
it('should mark class as WebSocket gateway', () => {
|
|
35
|
+
@WebSocketGateway()
|
|
36
|
+
class TestGateway extends BaseWebSocketGateway {}
|
|
37
|
+
|
|
38
|
+
expect(isWebSocketGateway(TestGateway)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('should store path option', () => {
|
|
42
|
+
@WebSocketGateway({ path: '/ws' })
|
|
43
|
+
class TestGateway extends BaseWebSocketGateway {}
|
|
44
|
+
|
|
45
|
+
const metadata = getGatewayMetadata(TestGateway);
|
|
46
|
+
expect(metadata?.path).toBe('/ws');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should store namespace option', () => {
|
|
50
|
+
@WebSocketGateway({ path: '/ws', namespace: 'chat' })
|
|
51
|
+
class TestGateway extends BaseWebSocketGateway {}
|
|
52
|
+
|
|
53
|
+
const metadata = getGatewayMetadata(TestGateway);
|
|
54
|
+
expect(metadata?.namespace).toBe('chat');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should use default path if not provided', () => {
|
|
58
|
+
@WebSocketGateway()
|
|
59
|
+
class TestGateway extends BaseWebSocketGateway {}
|
|
60
|
+
|
|
61
|
+
const metadata = getGatewayMetadata(TestGateway);
|
|
62
|
+
expect(metadata?.path).toBe('/');
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('method decorators', () => {
|
|
67
|
+
describe('@OnConnect', () => {
|
|
68
|
+
it('should register connect handler', () => {
|
|
69
|
+
@WebSocketGateway()
|
|
70
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
71
|
+
@OnConnect()
|
|
72
|
+
handleConnect() {}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const handlers = getWsHandlers(TestGateway);
|
|
76
|
+
const connectHandler = handlers.find((h) => h.type === WsHandlerType.CONNECT);
|
|
77
|
+
|
|
78
|
+
expect(connectHandler).toBeDefined();
|
|
79
|
+
expect(connectHandler?.handler).toBe('handleConnect');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('@OnDisconnect', () => {
|
|
84
|
+
it('should register disconnect handler', () => {
|
|
85
|
+
@WebSocketGateway()
|
|
86
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
87
|
+
@OnDisconnect()
|
|
88
|
+
handleDisconnect() {}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const handlers = getWsHandlers(TestGateway);
|
|
92
|
+
const handler = handlers.find((h) => h.type === WsHandlerType.DISCONNECT);
|
|
93
|
+
|
|
94
|
+
expect(handler).toBeDefined();
|
|
95
|
+
expect(handler?.handler).toBe('handleDisconnect');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('@OnJoinRoom', () => {
|
|
100
|
+
it('should register join room handler without pattern', () => {
|
|
101
|
+
@WebSocketGateway()
|
|
102
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
103
|
+
@OnJoinRoom()
|
|
104
|
+
handleJoin() {}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const handlers = getWsHandlers(TestGateway);
|
|
108
|
+
const handler = handlers.find((h) => h.type === WsHandlerType.JOIN_ROOM);
|
|
109
|
+
|
|
110
|
+
expect(handler).toBeDefined();
|
|
111
|
+
expect(handler?.pattern).toBeUndefined();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should register join room handler with pattern', () => {
|
|
115
|
+
@WebSocketGateway()
|
|
116
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
117
|
+
@OnJoinRoom('room:{roomId}')
|
|
118
|
+
handleJoin() {}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const handlers = getWsHandlers(TestGateway);
|
|
122
|
+
const handler = handlers.find((h) => h.type === WsHandlerType.JOIN_ROOM);
|
|
123
|
+
|
|
124
|
+
expect(handler?.pattern).toBe('room:{roomId}');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('@OnLeaveRoom', () => {
|
|
129
|
+
it('should register leave room handler', () => {
|
|
130
|
+
@WebSocketGateway()
|
|
131
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
132
|
+
@OnLeaveRoom('room:*')
|
|
133
|
+
handleLeave() {}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const handlers = getWsHandlers(TestGateway);
|
|
137
|
+
const handler = handlers.find((h) => h.type === WsHandlerType.LEAVE_ROOM);
|
|
138
|
+
|
|
139
|
+
expect(handler).toBeDefined();
|
|
140
|
+
expect(handler?.pattern).toBe('room:*');
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
describe('@OnMessage', () => {
|
|
145
|
+
it('should register message handler with pattern', () => {
|
|
146
|
+
@WebSocketGateway()
|
|
147
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
148
|
+
@OnMessage('chat:message')
|
|
149
|
+
handleMessage() {}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const handlers = getWsHandlers(TestGateway);
|
|
153
|
+
const handler = handlers.find((h) => h.type === WsHandlerType.MESSAGE);
|
|
154
|
+
|
|
155
|
+
expect(handler).toBeDefined();
|
|
156
|
+
expect(handler?.pattern).toBe('chat:message');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should support wildcard patterns', () => {
|
|
160
|
+
@WebSocketGateway()
|
|
161
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
162
|
+
@OnMessage('chat:*')
|
|
163
|
+
handleMessage() {}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const handlers = getWsHandlers(TestGateway);
|
|
167
|
+
const handler = handlers.find((h) => h.type === WsHandlerType.MESSAGE);
|
|
168
|
+
|
|
169
|
+
expect(handler?.pattern).toBe('chat:*');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should support parameterized patterns', () => {
|
|
173
|
+
@WebSocketGateway()
|
|
174
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
175
|
+
@OnMessage('chat:{roomId}:message')
|
|
176
|
+
handleMessage() {}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const handlers = getWsHandlers(TestGateway);
|
|
180
|
+
const handler = handlers.find((h) => h.type === WsHandlerType.MESSAGE);
|
|
181
|
+
|
|
182
|
+
expect(handler?.pattern).toBe('chat:{roomId}:message');
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('parameter decorators', () => {
|
|
188
|
+
it('should register @Client parameter', () => {
|
|
189
|
+
@WebSocketGateway()
|
|
190
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
191
|
+
@OnMessage('test')
|
|
192
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
193
|
+
handleMessage(@Client() client: unknown) {}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleMessage');
|
|
197
|
+
const clientParam = params.find((p) => p.type === WsParamType.CLIENT);
|
|
198
|
+
|
|
199
|
+
expect(clientParam).toBeDefined();
|
|
200
|
+
expect(clientParam?.index).toBe(0);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should register @Socket parameter', () => {
|
|
204
|
+
@WebSocketGateway()
|
|
205
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
206
|
+
@OnMessage('test')
|
|
207
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
208
|
+
handleMessage(@Socket() socket: unknown) {}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleMessage');
|
|
212
|
+
const socketParam = params.find((p) => p.type === WsParamType.SOCKET);
|
|
213
|
+
|
|
214
|
+
expect(socketParam).toBeDefined();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('should register @MessageData parameter', () => {
|
|
218
|
+
@WebSocketGateway()
|
|
219
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
220
|
+
@OnMessage('test')
|
|
221
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
222
|
+
handleMessage(@MessageData() data: unknown) {}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleMessage');
|
|
226
|
+
const dataParam = params.find((p) => p.type === WsParamType.MESSAGE_DATA);
|
|
227
|
+
|
|
228
|
+
expect(dataParam).toBeDefined();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('should register @MessageData with property path', () => {
|
|
232
|
+
@WebSocketGateway()
|
|
233
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
234
|
+
@OnMessage('test')
|
|
235
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
236
|
+
handleMessage(@MessageData('text') text: string) {}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleMessage');
|
|
240
|
+
const dataParam = params.find((p) => p.type === WsParamType.MESSAGE_DATA);
|
|
241
|
+
|
|
242
|
+
expect(dataParam?.property).toBe('text');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should register @RoomName parameter', () => {
|
|
246
|
+
@WebSocketGateway()
|
|
247
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
248
|
+
@OnJoinRoom()
|
|
249
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
250
|
+
handleJoin(@RoomName() room: string) {}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleJoin');
|
|
254
|
+
const roomParam = params.find((p) => p.type === WsParamType.ROOM_NAME);
|
|
255
|
+
|
|
256
|
+
expect(roomParam).toBeDefined();
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('should register @PatternParams parameter', () => {
|
|
260
|
+
@WebSocketGateway()
|
|
261
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
262
|
+
@OnMessage('chat:{roomId}')
|
|
263
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
264
|
+
handleMessage(@PatternParams() params: { roomId: string }) {}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleMessage');
|
|
268
|
+
const patternParam = params.find((p) => p.type === WsParamType.PATTERN_PARAMS);
|
|
269
|
+
|
|
270
|
+
expect(patternParam).toBeDefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should register @WsServer parameter', () => {
|
|
274
|
+
@WebSocketGateway()
|
|
275
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
276
|
+
@OnMessage('test')
|
|
277
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
278
|
+
handleMessage(@WsServer() server: unknown) {}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleMessage');
|
|
282
|
+
const serverParam = params.find((p) => p.type === WsParamType.SERVER);
|
|
283
|
+
|
|
284
|
+
expect(serverParam).toBeDefined();
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should register multiple parameters in correct order', () => {
|
|
288
|
+
@WebSocketGateway()
|
|
289
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
290
|
+
@OnMessage('chat:{roomId}')
|
|
291
|
+
handleMessage(
|
|
292
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
293
|
+
@Client() client: unknown,
|
|
294
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
295
|
+
@MessageData() data: unknown,
|
|
296
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
297
|
+
@PatternParams() params: unknown,
|
|
298
|
+
) {}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const params = getWsParamMetadata(TestGateway.prototype, 'handleMessage');
|
|
302
|
+
|
|
303
|
+
expect(params).toHaveLength(3);
|
|
304
|
+
expect(params.find((p) => p.index === 0)?.type).toBe(WsParamType.CLIENT);
|
|
305
|
+
expect(params.find((p) => p.index === 1)?.type).toBe(WsParamType.MESSAGE_DATA);
|
|
306
|
+
expect(params.find((p) => p.index === 2)?.type).toBe(WsParamType.PATTERN_PARAMS);
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
describe('multiple handlers', () => {
|
|
311
|
+
it('should support multiple handlers in one gateway', () => {
|
|
312
|
+
@WebSocketGateway()
|
|
313
|
+
class TestGateway extends BaseWebSocketGateway {
|
|
314
|
+
@OnConnect()
|
|
315
|
+
handleConnect() {}
|
|
316
|
+
|
|
317
|
+
@OnDisconnect()
|
|
318
|
+
handleDisconnect() {}
|
|
319
|
+
|
|
320
|
+
@OnMessage('chat:*')
|
|
321
|
+
handleChat() {}
|
|
322
|
+
|
|
323
|
+
@OnMessage('admin:*')
|
|
324
|
+
handleAdmin() {}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const handlers = getWsHandlers(TestGateway);
|
|
328
|
+
expect(handlers).toHaveLength(4);
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
});
|