@hazeljs/websocket 0.2.0-beta.1

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 (45) hide show
  1. package/README.md +530 -0
  2. package/dist/decorators/realtime.decorator.d.ts +113 -0
  3. package/dist/decorators/realtime.decorator.d.ts.map +1 -0
  4. package/dist/decorators/realtime.decorator.js +202 -0
  5. package/dist/index.d.ts +10 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +32 -0
  8. package/dist/room/room.manager.d.ts +81 -0
  9. package/dist/room/room.manager.d.ts.map +1 -0
  10. package/dist/room/room.manager.js +209 -0
  11. package/dist/src/decorators/realtime.decorator.d.ts +113 -0
  12. package/dist/src/decorators/realtime.decorator.d.ts.map +1 -0
  13. package/dist/src/decorators/realtime.decorator.js +202 -0
  14. package/dist/src/index.d.ts +10 -0
  15. package/dist/src/index.d.ts.map +1 -0
  16. package/dist/src/index.js +32 -0
  17. package/dist/src/room/room.manager.d.ts +81 -0
  18. package/dist/src/room/room.manager.d.ts.map +1 -0
  19. package/dist/src/room/room.manager.js +209 -0
  20. package/dist/src/sse/sse.handler.d.ts +61 -0
  21. package/dist/src/sse/sse.handler.d.ts.map +1 -0
  22. package/dist/src/sse/sse.handler.js +209 -0
  23. package/dist/src/websocket.gateway.d.ts +94 -0
  24. package/dist/src/websocket.gateway.d.ts.map +1 -0
  25. package/dist/src/websocket.gateway.js +309 -0
  26. package/dist/src/websocket.module.d.ts +57 -0
  27. package/dist/src/websocket.module.d.ts.map +1 -0
  28. package/dist/src/websocket.module.js +88 -0
  29. package/dist/src/websocket.types.d.ts +258 -0
  30. package/dist/src/websocket.types.d.ts.map +1 -0
  31. package/dist/src/websocket.types.js +2 -0
  32. package/dist/sse/sse.handler.d.ts +61 -0
  33. package/dist/sse/sse.handler.d.ts.map +1 -0
  34. package/dist/sse/sse.handler.js +209 -0
  35. package/dist/tsconfig.tsbuildinfo +1 -0
  36. package/dist/websocket.gateway.d.ts +79 -0
  37. package/dist/websocket.gateway.d.ts.map +1 -0
  38. package/dist/websocket.gateway.js +214 -0
  39. package/dist/websocket.module.d.ts +57 -0
  40. package/dist/websocket.module.d.ts.map +1 -0
  41. package/dist/websocket.module.js +88 -0
  42. package/dist/websocket.types.d.ts +258 -0
  43. package/dist/websocket.types.d.ts.map +1 -0
  44. package/dist/websocket.types.js +2 -0
  45. package/package.json +48 -0
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ var WebSocketModule_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.WebSocketModule = void 0;
14
+ const core_1 = require("@hazeljs/core");
15
+ const sse_handler_1 = require("./sse/sse.handler");
16
+ const room_manager_1 = require("./room/room.manager");
17
+ const core_2 = __importDefault(require("@hazeljs/core"));
18
+ /**
19
+ * WebSocket module for HazelJS
20
+ */
21
+ let WebSocketModule = WebSocketModule_1 = class WebSocketModule {
22
+ /**
23
+ * Configure WebSocket module
24
+ */
25
+ static forRoot(options = {}) {
26
+ const { isGlobal = true, enableSSE = true, enableRooms = true } = options;
27
+ core_2.default.info('Configuring WebSocket module...');
28
+ const providers = [];
29
+ // Add SSE handler if enabled
30
+ if (enableSSE) {
31
+ providers.push({
32
+ provide: sse_handler_1.SSEHandler,
33
+ useValue: new sse_handler_1.SSEHandler(),
34
+ });
35
+ }
36
+ // Add room manager if enabled
37
+ if (enableRooms) {
38
+ providers.push({
39
+ provide: room_manager_1.RoomManager,
40
+ useValue: new room_manager_1.RoomManager(),
41
+ });
42
+ }
43
+ return {
44
+ module: WebSocketModule_1,
45
+ providers,
46
+ exports: providers.map((p) => p.provide),
47
+ global: isGlobal,
48
+ };
49
+ }
50
+ /**
51
+ * Configure WebSocket module asynchronously
52
+ */
53
+ static forRootAsync(options) {
54
+ return {
55
+ module: WebSocketModule_1,
56
+ providers: [
57
+ {
58
+ provide: 'WEBSOCKET_OPTIONS',
59
+ useFactory: options.useFactory,
60
+ inject: options.inject || [],
61
+ },
62
+ {
63
+ provide: sse_handler_1.SSEHandler,
64
+ useFactory: (wsOptions) => {
65
+ return wsOptions.enableSSE !== false ? new sse_handler_1.SSEHandler() : null;
66
+ },
67
+ inject: ['WEBSOCKET_OPTIONS'],
68
+ },
69
+ {
70
+ provide: room_manager_1.RoomManager,
71
+ useFactory: (wsOptions) => {
72
+ return wsOptions.enableRooms !== false ? new room_manager_1.RoomManager() : null;
73
+ },
74
+ inject: ['WEBSOCKET_OPTIONS'],
75
+ },
76
+ ],
77
+ exports: [sse_handler_1.SSEHandler, room_manager_1.RoomManager],
78
+ global: true,
79
+ };
80
+ }
81
+ };
82
+ exports.WebSocketModule = WebSocketModule;
83
+ exports.WebSocketModule = WebSocketModule = WebSocketModule_1 = __decorate([
84
+ (0, core_1.HazelModule)({
85
+ providers: [],
86
+ exports: [],
87
+ })
88
+ ], WebSocketModule);
@@ -0,0 +1,258 @@
1
+ import { IncomingMessage } from 'http';
2
+ /**
3
+ * WebSocket client interface
4
+ */
5
+ export interface WebSocketClient {
6
+ /**
7
+ * Unique client ID
8
+ */
9
+ id: string;
10
+ /**
11
+ * Client socket
12
+ */
13
+ socket: unknown;
14
+ /**
15
+ * Client metadata
16
+ */
17
+ metadata: Map<string, unknown>;
18
+ /**
19
+ * Rooms the client is in
20
+ */
21
+ rooms: Set<string>;
22
+ /**
23
+ * Send message to client
24
+ */
25
+ send(event: string, data: unknown): void;
26
+ /**
27
+ * Disconnect client
28
+ */
29
+ disconnect(): void;
30
+ /**
31
+ * Join a room
32
+ */
33
+ join(room: string): void;
34
+ /**
35
+ * Leave a room
36
+ */
37
+ leave(room: string): void;
38
+ /**
39
+ * Check if client is in a room
40
+ */
41
+ inRoom(room: string): boolean;
42
+ }
43
+ /**
44
+ * WebSocket message
45
+ */
46
+ export interface WebSocketMessage {
47
+ /**
48
+ * Event name
49
+ */
50
+ event: string;
51
+ /**
52
+ * Message data
53
+ */
54
+ data: unknown;
55
+ /**
56
+ * Timestamp
57
+ */
58
+ timestamp: number;
59
+ /**
60
+ * Client ID
61
+ */
62
+ clientId?: string;
63
+ }
64
+ /**
65
+ * WebSocket gateway options
66
+ */
67
+ export interface WebSocketGatewayOptions {
68
+ /**
69
+ * Gateway path
70
+ */
71
+ path?: string;
72
+ /**
73
+ * Namespace
74
+ */
75
+ namespace?: string;
76
+ /**
77
+ * CORS options
78
+ */
79
+ cors?: {
80
+ origin?: string | string[];
81
+ credentials?: boolean;
82
+ };
83
+ /**
84
+ * Authentication required
85
+ */
86
+ auth?: boolean;
87
+ /**
88
+ * Ping interval in milliseconds
89
+ */
90
+ pingInterval?: number;
91
+ /**
92
+ * Ping timeout in milliseconds
93
+ */
94
+ pingTimeout?: number;
95
+ /**
96
+ * Maximum payload size in bytes
97
+ */
98
+ maxPayload?: number;
99
+ }
100
+ /**
101
+ * Room interface
102
+ */
103
+ export interface Room {
104
+ /**
105
+ * Room name
106
+ */
107
+ name: string;
108
+ /**
109
+ * Clients in the room
110
+ */
111
+ clients: Set<string>;
112
+ /**
113
+ * Room metadata
114
+ */
115
+ metadata: Map<string, unknown>;
116
+ /**
117
+ * Created timestamp
118
+ */
119
+ createdAt: number;
120
+ }
121
+ /**
122
+ * WebSocket event handler
123
+ */
124
+ export type WebSocketEventHandler = (client: WebSocketClient, data: unknown) => void | Promise<void>;
125
+ /**
126
+ * Connection handler
127
+ */
128
+ export type ConnectionHandler = (client: WebSocketClient, request: IncomingMessage) => void | Promise<void>;
129
+ /**
130
+ * Disconnection handler
131
+ */
132
+ export type DisconnectionHandler = (client: WebSocketClient, reason?: string) => void | Promise<void>;
133
+ /**
134
+ * WebSocket server options
135
+ */
136
+ export interface WebSocketServerOptions {
137
+ /**
138
+ * Port to listen on
139
+ */
140
+ port?: number;
141
+ /**
142
+ * Host to bind to
143
+ */
144
+ host?: string;
145
+ /**
146
+ * Path for WebSocket endpoint
147
+ */
148
+ path?: string;
149
+ /**
150
+ * Enable per-message deflate
151
+ */
152
+ perMessageDeflate?: boolean;
153
+ /**
154
+ * Maximum payload size
155
+ */
156
+ maxPayload?: number;
157
+ /**
158
+ * Client tracking
159
+ */
160
+ clientTracking?: boolean;
161
+ }
162
+ /**
163
+ * SSE (Server-Sent Events) options
164
+ */
165
+ export interface SSEOptions {
166
+ /**
167
+ * Retry interval in milliseconds
168
+ */
169
+ retry?: number;
170
+ /**
171
+ * Keep-alive interval in milliseconds
172
+ */
173
+ keepAlive?: number;
174
+ /**
175
+ * Event ID
176
+ */
177
+ id?: string;
178
+ }
179
+ /**
180
+ * SSE message
181
+ */
182
+ export interface SSEMessage {
183
+ /**
184
+ * Event type
185
+ */
186
+ event?: string;
187
+ /**
188
+ * Message data
189
+ */
190
+ data: unknown;
191
+ /**
192
+ * Event ID
193
+ */
194
+ id?: string;
195
+ /**
196
+ * Retry interval
197
+ */
198
+ retry?: number;
199
+ }
200
+ /**
201
+ * Subscription options
202
+ */
203
+ export interface SubscriptionOptions {
204
+ /**
205
+ * Topic pattern
206
+ */
207
+ topic: string;
208
+ /**
209
+ * Filter function
210
+ */
211
+ filter?: (data: unknown) => boolean;
212
+ /**
213
+ * Transform function
214
+ */
215
+ transform?: (data: unknown) => unknown;
216
+ /**
217
+ * Batch size
218
+ */
219
+ batchSize?: number;
220
+ /**
221
+ * Batch interval in milliseconds
222
+ */
223
+ batchInterval?: number;
224
+ }
225
+ /**
226
+ * WebSocket statistics
227
+ */
228
+ export interface WebSocketStats {
229
+ /**
230
+ * Total connected clients
231
+ */
232
+ connectedClients: number;
233
+ /**
234
+ * Total rooms
235
+ */
236
+ totalRooms: number;
237
+ /**
238
+ * Messages sent
239
+ */
240
+ messagesSent: number;
241
+ /**
242
+ * Messages received
243
+ */
244
+ messagesReceived: number;
245
+ /**
246
+ * Bytes sent
247
+ */
248
+ bytesSent: number;
249
+ /**
250
+ * Bytes received
251
+ */
252
+ bytesReceived: number;
253
+ /**
254
+ * Uptime in milliseconds
255
+ */
256
+ uptime: number;
257
+ }
258
+ //# sourceMappingURL=websocket.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.types.d.ts","sourceRoot":"","sources":["../../src/websocket.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,61 @@
1
+ import { IncomingMessage, ServerResponse } from 'http';
2
+ import { SSEMessage, SSEOptions } from '../websocket.types';
3
+ /**
4
+ * Server-Sent Events (SSE) handler
5
+ */
6
+ export declare class SSEHandler {
7
+ private connections;
8
+ private keepAliveIntervals;
9
+ /**
10
+ * Initialize SSE connection
11
+ */
12
+ initConnection(req: IncomingMessage, res: ServerResponse, options?: SSEOptions): string;
13
+ /**
14
+ * Send message to a specific connection
15
+ */
16
+ send(connectionId: string, message: SSEMessage): boolean;
17
+ /**
18
+ * Broadcast message to all connections
19
+ */
20
+ broadcast(message: SSEMessage): void;
21
+ /**
22
+ * Close a specific connection
23
+ */
24
+ closeConnection(connectionId: string): void;
25
+ /**
26
+ * Close all connections
27
+ */
28
+ closeAll(): void;
29
+ /**
30
+ * Get active connection count
31
+ */
32
+ getConnectionCount(): number;
33
+ /**
34
+ * Check if connection exists
35
+ */
36
+ hasConnection(connectionId: string): boolean;
37
+ /**
38
+ * Get all connection IDs
39
+ */
40
+ getConnectionIds(): string[];
41
+ /**
42
+ * Generate unique connection ID
43
+ */
44
+ private generateConnectionId;
45
+ /**
46
+ * Create a stream for continuous data
47
+ */
48
+ createStream<T>(connectionId: string, dataSource: AsyncIterable<T> | Iterable<T>, options?: {
49
+ event?: string;
50
+ transform?: (data: T) => unknown;
51
+ }): AsyncGenerator<boolean>;
52
+ }
53
+ /**
54
+ * Helper function to create SSE response
55
+ */
56
+ export declare function createSSEResponse(res: ServerResponse, options?: SSEOptions): void;
57
+ /**
58
+ * Helper function to send SSE message
59
+ */
60
+ export declare function sendSSEMessage(res: ServerResponse, message: SSEMessage): void;
61
+ //# sourceMappingURL=sse.handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.handler.d.ts","sourceRoot":"","sources":["../../src/sse/sse.handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAG5D;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,WAAW,CAA0C;IAC7D,OAAO,CAAC,kBAAkB,CAA0C;IAEpE;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM;IA0C3F;;OAEG;IACH,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO;IA0CxD;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAQpC;;OAEG;IACH,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAgB3C;;OAEG;IACH,QAAQ,IAAI,IAAI;IAQhB;;OAEG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;OAEG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAI5C;;OAEG;IACH,gBAAgB,IAAI,MAAM,EAAE;IAI5B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;OAEG;IACI,YAAY,CAAC,CAAC,EACnB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,EAC1C,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAA;KAAO,GACjE,cAAc,CAAC,OAAO,CAAC;CAmB3B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,GAAE,UAAe,GAAG,IAAI,CAYrF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,UAAU,GAAG,IAAI,CAyB7E"}
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.SSEHandler = void 0;
7
+ exports.createSSEResponse = createSSEResponse;
8
+ exports.sendSSEMessage = sendSSEMessage;
9
+ const core_1 = __importDefault(require("@hazeljs/core"));
10
+ /**
11
+ * Server-Sent Events (SSE) handler
12
+ */
13
+ class SSEHandler {
14
+ constructor() {
15
+ this.connections = new Map();
16
+ this.keepAliveIntervals = new Map();
17
+ }
18
+ /**
19
+ * Initialize SSE connection
20
+ */
21
+ initConnection(req, res, options = {}) {
22
+ const connectionId = this.generateConnectionId();
23
+ // Set SSE headers
24
+ res.writeHead(200, {
25
+ 'Content-Type': 'text/event-stream',
26
+ 'Cache-Control': 'no-cache',
27
+ Connection: 'keep-alive',
28
+ 'Access-Control-Allow-Origin': '*',
29
+ 'X-Accel-Buffering': 'no', // Disable nginx buffering
30
+ });
31
+ // Send initial retry interval
32
+ if (options.retry) {
33
+ res.write(`retry: ${options.retry}\n\n`);
34
+ }
35
+ // Store connection
36
+ this.connections.set(connectionId, res);
37
+ // Setup keep-alive
38
+ const keepAliveInterval = options.keepAlive || 30000;
39
+ const interval = setInterval(() => {
40
+ if (this.connections.has(connectionId)) {
41
+ res.write(': keep-alive\n\n');
42
+ }
43
+ else {
44
+ clearInterval(interval);
45
+ }
46
+ }, keepAliveInterval);
47
+ this.keepAliveIntervals.set(connectionId, interval);
48
+ // Handle connection close
49
+ req.on('close', () => {
50
+ this.closeConnection(connectionId);
51
+ });
52
+ core_1.default.debug(`SSE connection initialized: ${connectionId}`);
53
+ return connectionId;
54
+ }
55
+ /**
56
+ * Send message to a specific connection
57
+ */
58
+ send(connectionId, message) {
59
+ const res = this.connections.get(connectionId);
60
+ if (!res) {
61
+ return false;
62
+ }
63
+ try {
64
+ let output = '';
65
+ // Add event type
66
+ if (message.event) {
67
+ output += `event: ${message.event}\n`;
68
+ }
69
+ // Add ID
70
+ if (message.id) {
71
+ output += `id: ${message.id}\n`;
72
+ }
73
+ // Add retry
74
+ if (message.retry) {
75
+ output += `retry: ${message.retry}\n`;
76
+ }
77
+ // Add data (can be multi-line)
78
+ const data = typeof message.data === 'string' ? message.data : JSON.stringify(message.data);
79
+ const lines = data.split('\n');
80
+ for (const line of lines) {
81
+ output += `data: ${line}\n`;
82
+ }
83
+ output += '\n';
84
+ res.write(output);
85
+ return true;
86
+ }
87
+ catch (error) {
88
+ core_1.default.error(`Failed to send SSE message to ${connectionId}:`, error);
89
+ return false;
90
+ }
91
+ }
92
+ /**
93
+ * Broadcast message to all connections
94
+ */
95
+ broadcast(message) {
96
+ for (const connectionId of this.connections.keys()) {
97
+ this.send(connectionId, message);
98
+ }
99
+ core_1.default.debug(`SSE broadcast: ${message.event || 'message'}`);
100
+ }
101
+ /**
102
+ * Close a specific connection
103
+ */
104
+ closeConnection(connectionId) {
105
+ const res = this.connections.get(connectionId);
106
+ if (res) {
107
+ res.end();
108
+ this.connections.delete(connectionId);
109
+ }
110
+ const interval = this.keepAliveIntervals.get(connectionId);
111
+ if (interval) {
112
+ clearInterval(interval);
113
+ this.keepAliveIntervals.delete(connectionId);
114
+ }
115
+ core_1.default.debug(`SSE connection closed: ${connectionId}`);
116
+ }
117
+ /**
118
+ * Close all connections
119
+ */
120
+ closeAll() {
121
+ for (const connectionId of this.connections.keys()) {
122
+ this.closeConnection(connectionId);
123
+ }
124
+ core_1.default.info('All SSE connections closed');
125
+ }
126
+ /**
127
+ * Get active connection count
128
+ */
129
+ getConnectionCount() {
130
+ return this.connections.size;
131
+ }
132
+ /**
133
+ * Check if connection exists
134
+ */
135
+ hasConnection(connectionId) {
136
+ return this.connections.has(connectionId);
137
+ }
138
+ /**
139
+ * Get all connection IDs
140
+ */
141
+ getConnectionIds() {
142
+ return Array.from(this.connections.keys());
143
+ }
144
+ /**
145
+ * Generate unique connection ID
146
+ */
147
+ generateConnectionId() {
148
+ return `sse-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
149
+ }
150
+ /**
151
+ * Create a stream for continuous data
152
+ */
153
+ async *createStream(connectionId, dataSource, options = {}) {
154
+ try {
155
+ for await (const data of dataSource) {
156
+ const transformedData = options.transform ? options.transform(data) : data;
157
+ const sent = this.send(connectionId, {
158
+ event: options.event,
159
+ data: transformedData,
160
+ });
161
+ yield sent;
162
+ if (!sent) {
163
+ break;
164
+ }
165
+ }
166
+ }
167
+ catch (error) {
168
+ core_1.default.error(`SSE stream error for ${connectionId}:`, error);
169
+ }
170
+ }
171
+ }
172
+ exports.SSEHandler = SSEHandler;
173
+ /**
174
+ * Helper function to create SSE response
175
+ */
176
+ function createSSEResponse(res, options = {}) {
177
+ res.writeHead(200, {
178
+ 'Content-Type': 'text/event-stream',
179
+ 'Cache-Control': 'no-cache',
180
+ Connection: 'keep-alive',
181
+ 'Access-Control-Allow-Origin': '*',
182
+ 'X-Accel-Buffering': 'no',
183
+ });
184
+ if (options.retry) {
185
+ res.write(`retry: ${options.retry}\n\n`);
186
+ }
187
+ }
188
+ /**
189
+ * Helper function to send SSE message
190
+ */
191
+ function sendSSEMessage(res, message) {
192
+ let output = '';
193
+ if (message.event) {
194
+ output += `event: ${message.event}\n`;
195
+ }
196
+ if (message.id) {
197
+ output += `id: ${message.id}\n`;
198
+ }
199
+ if (message.retry) {
200
+ output += `retry: ${message.retry}\n`;
201
+ }
202
+ const data = typeof message.data === 'string' ? message.data : JSON.stringify(message.data);
203
+ const lines = data.split('\n');
204
+ for (const line of lines) {
205
+ output += `data: ${line}\n`;
206
+ }
207
+ output += '\n';
208
+ res.write(output);
209
+ }