@morojs/moro 1.3.0 → 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.
- package/README.md +61 -7
- package/dist/core/config/types.d.ts +147 -0
- package/dist/core/config/types.js +124 -0
- package/dist/core/config/types.js.map +1 -0
- package/dist/core/config/typescript-loader.d.ts +6 -0
- package/dist/core/config/typescript-loader.js +268 -0
- package/dist/core/config/typescript-loader.js.map +1 -0
- package/dist/core/config/validation.d.ts +18 -0
- package/dist/core/config/validation.js +134 -0
- package/dist/core/config/validation.js.map +1 -0
- package/dist/core/docs/openapi-generator.js +6 -6
- package/dist/core/docs/openapi-generator.js.map +1 -1
- package/dist/core/docs/schema-to-openapi.d.ts +7 -0
- package/dist/core/docs/schema-to-openapi.js +124 -0
- package/dist/core/docs/schema-to-openapi.js.map +1 -0
- package/dist/core/docs/zod-to-openapi.d.ts +2 -0
- package/dist/core/docs/zod-to-openapi.js.map +1 -1
- package/dist/core/framework.d.ts +29 -6
- package/dist/core/framework.js +117 -18
- package/dist/core/framework.js.map +1 -1
- package/dist/core/networking/adapters/index.d.ts +3 -0
- package/dist/core/networking/adapters/index.js +10 -0
- package/dist/core/networking/adapters/index.js.map +1 -0
- package/dist/core/networking/adapters/socketio-adapter.d.ts +16 -0
- package/dist/core/networking/adapters/socketio-adapter.js +244 -0
- package/dist/core/networking/adapters/socketio-adapter.js.map +1 -0
- package/dist/core/networking/adapters/ws-adapter.d.ts +54 -0
- package/dist/core/networking/adapters/ws-adapter.js +383 -0
- package/dist/core/networking/adapters/ws-adapter.js.map +1 -0
- package/dist/core/networking/websocket-adapter.d.ts +171 -0
- package/dist/core/networking/websocket-adapter.js +5 -0
- package/dist/core/networking/websocket-adapter.js.map +1 -0
- package/dist/core/networking/websocket-manager.d.ts +53 -17
- package/dist/core/networking/websocket-manager.js +166 -108
- package/dist/core/networking/websocket-manager.js.map +1 -1
- package/dist/core/routing/index.d.ts +13 -13
- package/dist/core/routing/index.js.map +1 -1
- package/dist/core/validation/adapters.d.ts +51 -0
- package/dist/core/validation/adapters.js +135 -0
- package/dist/core/validation/adapters.js.map +1 -0
- package/dist/core/validation/index.d.ts +14 -11
- package/dist/core/validation/index.js +37 -26
- package/dist/core/validation/index.js.map +1 -1
- package/dist/core/validation/schema-interface.d.ts +36 -0
- package/dist/core/validation/schema-interface.js +68 -0
- package/dist/core/validation/schema-interface.js.map +1 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/moro.js +8 -2
- package/dist/moro.js.map +1 -1
- package/package.json +31 -7
- package/src/core/config/types.ts +277 -0
- package/src/core/config/typescript-loader.ts +571 -0
- package/src/core/config/validation.ts +145 -0
- package/src/core/docs/openapi-generator.ts +7 -6
- package/src/core/docs/schema-to-openapi.ts +148 -0
- package/src/core/docs/zod-to-openapi.ts +2 -0
- package/src/core/framework.ts +121 -28
- package/src/core/networking/adapters/index.ts +16 -0
- package/src/core/networking/adapters/socketio-adapter.ts +252 -0
- package/src/core/networking/adapters/ws-adapter.ts +425 -0
- package/src/core/networking/websocket-adapter.ts +217 -0
- package/src/core/networking/websocket-manager.ts +185 -127
- package/src/core/routing/index.ts +13 -13
- package/src/core/validation/adapters.ts +147 -0
- package/src/core/validation/index.ts +60 -38
- package/src/core/validation/schema-interface.ts +100 -0
- package/src/index.ts +25 -2
- package/src/moro.ts +11 -2
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Socket.IO WebSocket Adapter for Moro Framework
|
|
3
|
+
// Implements the WebSocket adapter interface using Socket.IO
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.SocketIOAdapter = void 0;
|
|
39
|
+
/**
|
|
40
|
+
* Socket.IO adapter implementation
|
|
41
|
+
*/
|
|
42
|
+
class SocketIOAdapter {
|
|
43
|
+
async initialize(httpServer, options = {}) {
|
|
44
|
+
try {
|
|
45
|
+
// Dynamic import to avoid requiring socket.io as a hard dependency
|
|
46
|
+
const { Server } = await Promise.resolve().then(() => __importStar(require('socket.io')));
|
|
47
|
+
this.io = new Server(httpServer, {
|
|
48
|
+
cors: options.cors || { origin: '*' },
|
|
49
|
+
path: options.path || '/socket.io/',
|
|
50
|
+
compression: options.compression !== false,
|
|
51
|
+
maxHttpBufferSize: options.maxPayloadLength,
|
|
52
|
+
...options,
|
|
53
|
+
});
|
|
54
|
+
// Apply custom ID generator if set
|
|
55
|
+
if (this.customIdGenerator) {
|
|
56
|
+
this.io.engine.generateId = this.customIdGenerator;
|
|
57
|
+
}
|
|
58
|
+
// Setup compression if enabled
|
|
59
|
+
if (options.compression) {
|
|
60
|
+
this.setCompression(true);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
throw new Error('Socket.IO not found. Install it with: npm install socket.io\n' +
|
|
65
|
+
'Or use a different WebSocket adapter.');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
createNamespace(namespace) {
|
|
69
|
+
if (!this.io) {
|
|
70
|
+
throw new Error('Socket.IO adapter not initialized');
|
|
71
|
+
}
|
|
72
|
+
const ns = this.io.of(namespace);
|
|
73
|
+
return new SocketIONamespaceWrapper(ns);
|
|
74
|
+
}
|
|
75
|
+
getDefaultNamespace() {
|
|
76
|
+
return this.createNamespace('/');
|
|
77
|
+
}
|
|
78
|
+
async close() {
|
|
79
|
+
if (this.io) {
|
|
80
|
+
return new Promise(resolve => {
|
|
81
|
+
this.io.close(() => resolve());
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
setCompression(enabled, options = {}) {
|
|
86
|
+
if (this.io && enabled) {
|
|
87
|
+
this.io.engine.compression = true;
|
|
88
|
+
this.io.engine.perMessageDeflate = {
|
|
89
|
+
threshold: 1024,
|
|
90
|
+
concurrencyLimit: 10,
|
|
91
|
+
memLevel: 8,
|
|
92
|
+
...options,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
setCustomIdGenerator(generator) {
|
|
97
|
+
this.customIdGenerator = generator;
|
|
98
|
+
if (this.io) {
|
|
99
|
+
this.io.engine.generateId = generator;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
getAdapterName() {
|
|
103
|
+
return 'socket.io';
|
|
104
|
+
}
|
|
105
|
+
getConnectionCount() {
|
|
106
|
+
if (!this.io)
|
|
107
|
+
return 0;
|
|
108
|
+
return this.io.engine.clientsCount || 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
exports.SocketIOAdapter = SocketIOAdapter;
|
|
112
|
+
/**
|
|
113
|
+
* Socket.IO namespace wrapper
|
|
114
|
+
*/
|
|
115
|
+
class SocketIONamespaceWrapper {
|
|
116
|
+
constructor(namespace) {
|
|
117
|
+
this.namespace = namespace;
|
|
118
|
+
}
|
|
119
|
+
on(event, handler) {
|
|
120
|
+
this.namespace.on(event, (socket) => {
|
|
121
|
+
handler(new SocketIOConnectionWrapper(socket));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
emit(event, data) {
|
|
125
|
+
this.namespace.emit(event, data);
|
|
126
|
+
}
|
|
127
|
+
to(room) {
|
|
128
|
+
const target = Array.isArray(room)
|
|
129
|
+
? room.reduce((acc, r) => acc.to(r), this.namespace)
|
|
130
|
+
: this.namespace.to(room);
|
|
131
|
+
return new SocketIOEmitterWrapper(target);
|
|
132
|
+
}
|
|
133
|
+
except(room) {
|
|
134
|
+
const target = Array.isArray(room)
|
|
135
|
+
? room.reduce((acc, r) => acc.except(r), this.namespace)
|
|
136
|
+
: this.namespace.except(room);
|
|
137
|
+
return new SocketIOEmitterWrapper(target);
|
|
138
|
+
}
|
|
139
|
+
getSockets() {
|
|
140
|
+
const sockets = this.namespace.sockets;
|
|
141
|
+
return Array.from(sockets.values()).map((socket) => new SocketIOConnectionWrapper(socket));
|
|
142
|
+
}
|
|
143
|
+
getConnectionCount() {
|
|
144
|
+
return this.namespace.sockets.size;
|
|
145
|
+
}
|
|
146
|
+
use(middleware) {
|
|
147
|
+
this.namespace.use((socket, next) => {
|
|
148
|
+
middleware(new SocketIOConnectionWrapper(socket), next);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Socket.IO connection wrapper
|
|
154
|
+
*/
|
|
155
|
+
class SocketIOConnectionWrapper {
|
|
156
|
+
constructor(socket) {
|
|
157
|
+
this.socket = socket;
|
|
158
|
+
this.data = {};
|
|
159
|
+
// Map socket.data to our data property
|
|
160
|
+
this.data = socket.data || {};
|
|
161
|
+
}
|
|
162
|
+
get id() {
|
|
163
|
+
return this.socket.id;
|
|
164
|
+
}
|
|
165
|
+
get ip() {
|
|
166
|
+
return this.socket.handshake?.address;
|
|
167
|
+
}
|
|
168
|
+
get headers() {
|
|
169
|
+
return this.socket.handshake?.headers;
|
|
170
|
+
}
|
|
171
|
+
get connected() {
|
|
172
|
+
return this.socket.connected;
|
|
173
|
+
}
|
|
174
|
+
get broadcast() {
|
|
175
|
+
return new SocketIOEmitterWrapper(this.socket.broadcast);
|
|
176
|
+
}
|
|
177
|
+
on(event, handler) {
|
|
178
|
+
this.socket.on(event, handler);
|
|
179
|
+
}
|
|
180
|
+
onAny(handler) {
|
|
181
|
+
this.socket.onAny(handler);
|
|
182
|
+
}
|
|
183
|
+
emit(event, data) {
|
|
184
|
+
this.socket.emit(event, data);
|
|
185
|
+
}
|
|
186
|
+
compressedEmit(event, data) {
|
|
187
|
+
this.socket.compress(true).emit(event, data);
|
|
188
|
+
}
|
|
189
|
+
join(room) {
|
|
190
|
+
if (Array.isArray(room)) {
|
|
191
|
+
room.forEach(r => this.socket.join(r));
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
this.socket.join(room);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
leave(room) {
|
|
198
|
+
if (Array.isArray(room)) {
|
|
199
|
+
room.forEach(r => this.socket.leave(r));
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
this.socket.leave(room);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
to(room) {
|
|
206
|
+
const target = Array.isArray(room)
|
|
207
|
+
? room.reduce((acc, r) => acc.to(r), this.socket)
|
|
208
|
+
: this.socket.to(room);
|
|
209
|
+
return new SocketIOEmitterWrapper(target);
|
|
210
|
+
}
|
|
211
|
+
getRooms() {
|
|
212
|
+
return new Set(this.socket.rooms);
|
|
213
|
+
}
|
|
214
|
+
disconnect(close) {
|
|
215
|
+
this.socket.disconnect(close);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Socket.IO emitter wrapper
|
|
220
|
+
*/
|
|
221
|
+
class SocketIOEmitterWrapper {
|
|
222
|
+
constructor(emitter) {
|
|
223
|
+
this.emitter = emitter;
|
|
224
|
+
}
|
|
225
|
+
emit(event, data) {
|
|
226
|
+
this.emitter.emit(event, data);
|
|
227
|
+
}
|
|
228
|
+
to(room) {
|
|
229
|
+
const target = Array.isArray(room)
|
|
230
|
+
? room.reduce((acc, r) => acc.to(r), this.emitter)
|
|
231
|
+
: this.emitter.to(room);
|
|
232
|
+
return new SocketIOEmitterWrapper(target);
|
|
233
|
+
}
|
|
234
|
+
except(room) {
|
|
235
|
+
const target = Array.isArray(room)
|
|
236
|
+
? room.reduce((acc, r) => acc.except(r), this.emitter)
|
|
237
|
+
: this.emitter.except(room);
|
|
238
|
+
return new SocketIOEmitterWrapper(target);
|
|
239
|
+
}
|
|
240
|
+
compress(compress) {
|
|
241
|
+
return new SocketIOEmitterWrapper(this.emitter.compress(compress));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=socketio-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socketio-adapter.js","sourceRoot":"","sources":["../../../../src/core/networking/adapters/socketio-adapter.ts"],"names":[],"mappings":";AAAA,iDAAiD;AACjD,6DAA6D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAW7D;;GAEG;AACH,MAAa,eAAe;IAI1B,KAAK,CAAC,UAAU,CAAC,UAAe,EAAE,UAAmC,EAAE;QACrE,IAAI,CAAC;YACH,mEAAmE;YACnE,MAAM,EAAE,MAAM,EAAE,GAAG,wDAAa,WAAW,GAAC,CAAC;YAE7C,IAAI,CAAC,EAAE,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE;gBAC/B,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;gBACrC,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,aAAa;gBACnC,WAAW,EAAE,OAAO,CAAC,WAAW,KAAK,KAAK;gBAC1C,iBAAiB,EAAE,OAAO,CAAC,gBAAgB;gBAC3C,GAAG,OAAO;aACX,CAAC,CAAC;YAEH,mCAAmC;YACnC,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBAC1B,IAAI,CAAC,EAAE,CAAC,MAAc,CAAC,UAAU,GAAG,IAAI,CAAC,iBAAiB,CAAC;YAC9D,CAAC;YAED,+BAA+B;YAC/B,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACxB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,+DAA+D;gBAC7D,uCAAuC,CAC1C,CAAC;QACJ,CAAC;IACH,CAAC;IAED,eAAe,CAAC,SAAiB;QAC/B,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;QACjC,OAAO,IAAI,wBAAwB,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,mBAAmB;QACjB,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;gBAC3B,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,cAAc,CAAC,OAAgB,EAAE,UAAe,EAAE;QAChD,IAAI,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,CAAC;YACtB,IAAI,CAAC,EAAE,CAAC,MAAc,CAAC,WAAW,GAAG,IAAI,CAAC;YAC1C,IAAI,CAAC,EAAE,CAAC,MAAc,CAAC,iBAAiB,GAAG;gBAC1C,SAAS,EAAE,IAAI;gBACf,gBAAgB,EAAE,EAAE;gBACpB,QAAQ,EAAE,CAAC;gBACX,GAAG,OAAO;aACX,CAAC;QACJ,CAAC;IACH,CAAC;IAED,oBAAoB,CAAC,SAAuB;QAC1C,IAAI,CAAC,iBAAiB,GAAG,SAAS,CAAC;QACnC,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACX,IAAI,CAAC,EAAE,CAAC,MAAc,CAAC,UAAU,GAAG,SAAS,CAAC;QACjD,CAAC;IACH,CAAC;IAED,cAAc;QACZ,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,kBAAkB;QAChB,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,OAAO,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC;IAC1C,CAAC;CACF;AAlFD,0CAkFC;AAED;;GAEG;AACH,MAAM,wBAAwB;IAC5B,YAAoB,SAAc;QAAd,cAAS,GAAT,SAAS,CAAK;IAAG,CAAC;IAEtC,EAAE,CAAC,KAAmB,EAAE,OAA8C;QACpE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAW,EAAE,EAAE;YACvC,OAAO,CAAC,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,KAAa,EAAE,IAAS;QAC3B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,EAAE,CAAC,IAAuB;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAChC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;YACpD,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC5B,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,IAAuB;QAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAChC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;YACxD,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,UAAU;QACR,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;QACvC,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAW,EAAE,EAAE,CAAC,IAAI,yBAAyB,CAAC,MAAM,CAAC,CAAC,CAAC;IAClG,CAAC;IAED,kBAAkB;QAChB,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;IACrC,CAAC;IAED,GAAG,CAAC,UAA+B;QACjC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,MAAW,EAAE,IAAS,EAAE,EAAE;YAC5C,UAAU,CAAC,IAAI,yBAAyB,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED;;GAEG;AACH,MAAM,yBAAyB;IAG7B,YAAoB,MAAW;QAAX,WAAM,GAAN,MAAM,CAAK;QAFxB,SAAI,GAAwB,EAAE,CAAC;QAGpC,uCAAuC;QACvC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;IACxC,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC;IACxC,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;IAC/B,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3D,CAAC;IAED,EAAE,CAAC,KAAa,EAAE,OAAiE;QACjF,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,OAAgD;QACpD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,CAAC,KAAa,EAAE,IAAS;QAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,cAAc,CAAC,KAAa,EAAE,IAAS;QACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,IAAI,CAAC,IAAuB;QAC1B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAuB;QAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,EAAE,CAAC,IAAuB;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAChC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;YACjD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;IAED,UAAU,CAAC,KAAe;QACxB,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,sBAAsB;IAC1B,YAAoB,OAAY;QAAZ,YAAO,GAAP,OAAO,CAAK;IAAG,CAAC;IAEpC,IAAI,CAAC,KAAa,EAAE,IAAS;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAED,EAAE,CAAC,IAAuB;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAChC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC;YAClD,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1B,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,CAAC,IAAuB;QAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;YAChC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC;YACtD,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,IAAI,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED,QAAQ,CAAC,QAAiB;QACxB,OAAO,IAAI,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IACrE,CAAC;CACF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { WebSocketAdapter, WebSocketAdapterOptions, WebSocketNamespace, WebSocketConnection, WebSocketEmitter } from '../websocket-adapter';
|
|
2
|
+
/**
|
|
3
|
+
* Native WebSocket adapter using the 'ws' library
|
|
4
|
+
* Provides a lightweight, standards-compliant WebSocket implementation
|
|
5
|
+
*/
|
|
6
|
+
export declare class WSAdapter implements WebSocketAdapter {
|
|
7
|
+
private wss;
|
|
8
|
+
private namespaces;
|
|
9
|
+
private connections;
|
|
10
|
+
private customIdGenerator?;
|
|
11
|
+
private connectionCounter;
|
|
12
|
+
initialize(httpServer: any, options?: WebSocketAdapterOptions): Promise<void>;
|
|
13
|
+
private handleConnection;
|
|
14
|
+
createNamespace(namespace: string): WebSocketNamespace;
|
|
15
|
+
getDefaultNamespace(): WebSocketNamespace;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
setCompression(enabled: boolean, _options?: any): void;
|
|
18
|
+
setCustomIdGenerator(generator: () => string): void;
|
|
19
|
+
getAdapterName(): string;
|
|
20
|
+
getConnectionCount(): number;
|
|
21
|
+
generateId(): string;
|
|
22
|
+
addConnection(id: string, connection: WSConnectionWrapper): void;
|
|
23
|
+
removeConnection(id: string): void;
|
|
24
|
+
getAllConnections(): Map<string, WSConnectionWrapper>;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* WebSocket connection wrapper
|
|
28
|
+
*/
|
|
29
|
+
declare class WSConnectionWrapper implements WebSocketConnection {
|
|
30
|
+
readonly id: string;
|
|
31
|
+
readonly ws: any;
|
|
32
|
+
private request;
|
|
33
|
+
data: Record<string, any>;
|
|
34
|
+
private eventHandlers;
|
|
35
|
+
private anyHandlers;
|
|
36
|
+
private rooms;
|
|
37
|
+
private _connected;
|
|
38
|
+
constructor(id: string, ws: any, request: any);
|
|
39
|
+
get ip(): string | undefined;
|
|
40
|
+
get headers(): Record<string, string> | undefined;
|
|
41
|
+
get connected(): boolean;
|
|
42
|
+
get broadcast(): WebSocketEmitter;
|
|
43
|
+
on(event: string, handler: (data: any, callback?: (response?: any) => void) => void): void;
|
|
44
|
+
onAny(handler: (event: string, ...args: any[]) => void): void;
|
|
45
|
+
emit(event: string, data?: any): void;
|
|
46
|
+
compressedEmit(event: string, data: any): void;
|
|
47
|
+
join(room: string | string[]): void;
|
|
48
|
+
leave(room: string | string[]): void;
|
|
49
|
+
to(room: string | string[]): WebSocketEmitter;
|
|
50
|
+
getRooms(): Set<string>;
|
|
51
|
+
disconnect(close?: boolean): void;
|
|
52
|
+
private handleMessage;
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Native WebSocket Adapter for Moro Framework
|
|
3
|
+
// Implements the WebSocket adapter interface using the 'ws' library
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.WSAdapter = void 0;
|
|
39
|
+
/**
|
|
40
|
+
* Native WebSocket adapter using the 'ws' library
|
|
41
|
+
* Provides a lightweight, standards-compliant WebSocket implementation
|
|
42
|
+
*/
|
|
43
|
+
class WSAdapter {
|
|
44
|
+
constructor() {
|
|
45
|
+
this.namespaces = new Map();
|
|
46
|
+
this.connections = new Map();
|
|
47
|
+
this.connectionCounter = 0;
|
|
48
|
+
}
|
|
49
|
+
async initialize(httpServer, options = {}) {
|
|
50
|
+
try {
|
|
51
|
+
// Dynamic import to avoid requiring ws as a hard dependency
|
|
52
|
+
const { WebSocketServer } = await Promise.resolve().then(() => __importStar(require('ws')));
|
|
53
|
+
this.wss = new WebSocketServer({
|
|
54
|
+
server: httpServer,
|
|
55
|
+
path: options.path || '/ws',
|
|
56
|
+
maxPayload: options.maxPayloadLength || 100 * 1024 * 1024, // 100MB default
|
|
57
|
+
// Note: ws doesn't have built-in compression like socket.io
|
|
58
|
+
// but browsers handle compression at the transport level
|
|
59
|
+
});
|
|
60
|
+
// Setup connection handling
|
|
61
|
+
this.wss.on('connection', (ws, request) => {
|
|
62
|
+
this.handleConnection(ws, request);
|
|
63
|
+
});
|
|
64
|
+
// Setup default namespace
|
|
65
|
+
this.createNamespace('/');
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw new Error('ws library not found. Install it with: npm install ws @types/ws\n' +
|
|
69
|
+
'Or use a different WebSocket adapter.');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
handleConnection(ws, request) {
|
|
73
|
+
const id = this.generateId();
|
|
74
|
+
const connection = new WSConnectionWrapper(id, ws, request);
|
|
75
|
+
this.connections.set(id, connection);
|
|
76
|
+
// Parse namespace from URL path or default to '/'
|
|
77
|
+
const url = new URL(request.url || '/', `http://${request.headers.host}`);
|
|
78
|
+
const namespacePath = url.pathname === '/ws' ? '/' : url.pathname.replace('/ws', '') || '/';
|
|
79
|
+
const namespace = this.namespaces.get(namespacePath);
|
|
80
|
+
if (namespace) {
|
|
81
|
+
namespace.handleConnection(connection);
|
|
82
|
+
}
|
|
83
|
+
// Clean up on disconnect
|
|
84
|
+
ws.on('close', () => {
|
|
85
|
+
this.connections.delete(id);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
createNamespace(namespace) {
|
|
89
|
+
if (!this.namespaces.has(namespace)) {
|
|
90
|
+
const ns = new WSNamespaceWrapper(namespace, this);
|
|
91
|
+
this.namespaces.set(namespace, ns);
|
|
92
|
+
}
|
|
93
|
+
return this.namespaces.get(namespace);
|
|
94
|
+
}
|
|
95
|
+
getDefaultNamespace() {
|
|
96
|
+
return this.createNamespace('/');
|
|
97
|
+
}
|
|
98
|
+
async close() {
|
|
99
|
+
if (this.wss) {
|
|
100
|
+
return new Promise(resolve => {
|
|
101
|
+
this.wss.close(() => {
|
|
102
|
+
this.connections.clear();
|
|
103
|
+
this.namespaces.clear();
|
|
104
|
+
resolve();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
setCompression(enabled, _options = {}) {
|
|
110
|
+
// ws library handles compression at the browser level
|
|
111
|
+
// This is a no-op but kept for interface compatibility
|
|
112
|
+
if (enabled) {
|
|
113
|
+
console.warn('Compression is handled automatically by the ws library and browsers');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
setCustomIdGenerator(generator) {
|
|
117
|
+
this.customIdGenerator = generator;
|
|
118
|
+
}
|
|
119
|
+
getAdapterName() {
|
|
120
|
+
return 'ws';
|
|
121
|
+
}
|
|
122
|
+
getConnectionCount() {
|
|
123
|
+
return this.connections.size;
|
|
124
|
+
}
|
|
125
|
+
generateId() {
|
|
126
|
+
if (this.customIdGenerator) {
|
|
127
|
+
return this.customIdGenerator();
|
|
128
|
+
}
|
|
129
|
+
return `ws_${++this.connectionCounter}_${Date.now()}`;
|
|
130
|
+
}
|
|
131
|
+
addConnection(id, connection) {
|
|
132
|
+
this.connections.set(id, connection);
|
|
133
|
+
}
|
|
134
|
+
removeConnection(id) {
|
|
135
|
+
this.connections.delete(id);
|
|
136
|
+
}
|
|
137
|
+
getAllConnections() {
|
|
138
|
+
return this.connections;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
exports.WSAdapter = WSAdapter;
|
|
142
|
+
/**
|
|
143
|
+
* WebSocket namespace wrapper
|
|
144
|
+
*/
|
|
145
|
+
class WSNamespaceWrapper {
|
|
146
|
+
constructor(namespacePath, adapter) {
|
|
147
|
+
this.namespacePath = namespacePath;
|
|
148
|
+
this.adapter = adapter;
|
|
149
|
+
this.connectionHandlers = [];
|
|
150
|
+
this.middlewares = [];
|
|
151
|
+
this.connections = new Map();
|
|
152
|
+
}
|
|
153
|
+
handleConnection(connection) {
|
|
154
|
+
this.connections.set(connection.id, connection);
|
|
155
|
+
// Run middlewares
|
|
156
|
+
this.runMiddlewares(connection, () => {
|
|
157
|
+
// Notify connection handlers
|
|
158
|
+
this.connectionHandlers.forEach(handler => handler(connection));
|
|
159
|
+
});
|
|
160
|
+
// Clean up on disconnect
|
|
161
|
+
connection.on('close', () => {
|
|
162
|
+
this.connections.delete(connection.id);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
runMiddlewares(connection, callback) {
|
|
166
|
+
let index = 0;
|
|
167
|
+
const next = (err) => {
|
|
168
|
+
if (err || index >= this.middlewares.length) {
|
|
169
|
+
if (!err)
|
|
170
|
+
callback();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const middleware = this.middlewares[index++];
|
|
174
|
+
middleware(connection, next);
|
|
175
|
+
};
|
|
176
|
+
next();
|
|
177
|
+
}
|
|
178
|
+
on(event, handler) {
|
|
179
|
+
this.connectionHandlers.push(handler);
|
|
180
|
+
}
|
|
181
|
+
emit(event, data) {
|
|
182
|
+
const message = JSON.stringify({ event, data });
|
|
183
|
+
for (const connection of this.connections.values()) {
|
|
184
|
+
if (connection.connected) {
|
|
185
|
+
connection.ws.send(message);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
to(room) {
|
|
190
|
+
return new WSEmitterWrapper(this.connections, room);
|
|
191
|
+
}
|
|
192
|
+
except(room) {
|
|
193
|
+
return new WSEmitterWrapper(this.connections, undefined, room);
|
|
194
|
+
}
|
|
195
|
+
getSockets() {
|
|
196
|
+
return Array.from(this.connections.values());
|
|
197
|
+
}
|
|
198
|
+
getConnectionCount() {
|
|
199
|
+
return this.connections.size;
|
|
200
|
+
}
|
|
201
|
+
use(middleware) {
|
|
202
|
+
this.middlewares.push(middleware);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* WebSocket connection wrapper
|
|
207
|
+
*/
|
|
208
|
+
class WSConnectionWrapper {
|
|
209
|
+
constructor(id, ws, request) {
|
|
210
|
+
this.id = id;
|
|
211
|
+
this.ws = ws;
|
|
212
|
+
this.request = request;
|
|
213
|
+
this.data = {};
|
|
214
|
+
this.eventHandlers = new Map();
|
|
215
|
+
this.anyHandlers = [];
|
|
216
|
+
this.rooms = new Set();
|
|
217
|
+
this._connected = true;
|
|
218
|
+
// Setup message handling
|
|
219
|
+
this.ws.on('message', (data) => {
|
|
220
|
+
this.handleMessage(data);
|
|
221
|
+
});
|
|
222
|
+
this.ws.on('close', () => {
|
|
223
|
+
this._connected = false;
|
|
224
|
+
this.emit('close');
|
|
225
|
+
});
|
|
226
|
+
this.ws.on('error', (error) => {
|
|
227
|
+
this.emit('error', error);
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
get ip() {
|
|
231
|
+
return (this.request.socket?.remoteAddress || this.request.headers['x-forwarded-for']?.split(',')[0]);
|
|
232
|
+
}
|
|
233
|
+
get headers() {
|
|
234
|
+
return this.request.headers;
|
|
235
|
+
}
|
|
236
|
+
get connected() {
|
|
237
|
+
return this._connected && this.ws.readyState === 1; // WebSocket.OPEN
|
|
238
|
+
}
|
|
239
|
+
get broadcast() {
|
|
240
|
+
// Get all connections except this one
|
|
241
|
+
const allConnections = new Map();
|
|
242
|
+
// This would need access to adapter's connections
|
|
243
|
+
return new WSEmitterWrapper(allConnections, undefined, undefined, this.id);
|
|
244
|
+
}
|
|
245
|
+
on(event, handler) {
|
|
246
|
+
if (event === 'close' || event === 'error') {
|
|
247
|
+
// Special internal events
|
|
248
|
+
if (!this.eventHandlers.has(event)) {
|
|
249
|
+
this.eventHandlers.set(event, []);
|
|
250
|
+
}
|
|
251
|
+
this.eventHandlers.get(event).push(handler);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (!this.eventHandlers.has(event)) {
|
|
255
|
+
this.eventHandlers.set(event, []);
|
|
256
|
+
}
|
|
257
|
+
this.eventHandlers.get(event).push(handler);
|
|
258
|
+
}
|
|
259
|
+
onAny(handler) {
|
|
260
|
+
this.anyHandlers.push(handler);
|
|
261
|
+
}
|
|
262
|
+
emit(event, data) {
|
|
263
|
+
if (event === 'close' || event === 'error') {
|
|
264
|
+
// Internal events
|
|
265
|
+
const handlers = this.eventHandlers.get(event);
|
|
266
|
+
if (handlers) {
|
|
267
|
+
handlers.forEach(handler => handler(data));
|
|
268
|
+
}
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
if (this.connected) {
|
|
272
|
+
const message = JSON.stringify({ event, data });
|
|
273
|
+
this.ws.send(message);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
compressedEmit(event, data) {
|
|
277
|
+
// ws library handles compression automatically
|
|
278
|
+
this.emit(event, data);
|
|
279
|
+
}
|
|
280
|
+
join(room) {
|
|
281
|
+
if (Array.isArray(room)) {
|
|
282
|
+
room.forEach(r => this.rooms.add(r));
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
this.rooms.add(room);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
leave(room) {
|
|
289
|
+
if (Array.isArray(room)) {
|
|
290
|
+
room.forEach(r => this.rooms.delete(r));
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
this.rooms.delete(room);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
to(room) {
|
|
297
|
+
const connections = new Map([[this.id, this]]);
|
|
298
|
+
return new WSEmitterWrapper(connections, room);
|
|
299
|
+
}
|
|
300
|
+
getRooms() {
|
|
301
|
+
return new Set(this.rooms);
|
|
302
|
+
}
|
|
303
|
+
disconnect(close) {
|
|
304
|
+
if (close !== false && this.ws.readyState === 1) {
|
|
305
|
+
this.ws.close();
|
|
306
|
+
}
|
|
307
|
+
this._connected = false;
|
|
308
|
+
}
|
|
309
|
+
handleMessage(data) {
|
|
310
|
+
try {
|
|
311
|
+
const text = data.toString();
|
|
312
|
+
const parsed = JSON.parse(text);
|
|
313
|
+
const { event, data: messageData, callback: callbackId } = parsed;
|
|
314
|
+
// Create callback function if callback ID is provided
|
|
315
|
+
const callback = callbackId
|
|
316
|
+
? (response) => {
|
|
317
|
+
this.emit('callback', { id: callbackId, data: response });
|
|
318
|
+
}
|
|
319
|
+
: undefined;
|
|
320
|
+
// Call any handlers
|
|
321
|
+
this.anyHandlers.forEach(handler => handler(event, messageData));
|
|
322
|
+
// Call specific event handlers
|
|
323
|
+
const handlers = this.eventHandlers.get(event);
|
|
324
|
+
if (handlers) {
|
|
325
|
+
handlers.forEach(handler => handler(messageData, callback));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
// Invalid message format - ignore
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* WebSocket emitter wrapper
|
|
335
|
+
*/
|
|
336
|
+
class WSEmitterWrapper {
|
|
337
|
+
constructor(connections, targetRooms, excludeRooms, excludeId) {
|
|
338
|
+
this.connections = connections;
|
|
339
|
+
this.targetRooms = targetRooms;
|
|
340
|
+
this.excludeRooms = excludeRooms;
|
|
341
|
+
this.excludeId = excludeId;
|
|
342
|
+
}
|
|
343
|
+
emit(event, data) {
|
|
344
|
+
const message = JSON.stringify({ event, data });
|
|
345
|
+
for (const connection of this.connections.values()) {
|
|
346
|
+
if (this.excludeId && connection.id === this.excludeId) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (this.shouldIncludeConnection(connection) && connection.connected) {
|
|
350
|
+
connection.ws.send(message);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
to(room) {
|
|
355
|
+
return new WSEmitterWrapper(this.connections, room, this.excludeRooms, this.excludeId);
|
|
356
|
+
}
|
|
357
|
+
except(room) {
|
|
358
|
+
return new WSEmitterWrapper(this.connections, this.targetRooms, room, this.excludeId);
|
|
359
|
+
}
|
|
360
|
+
compress(_compress) {
|
|
361
|
+
// ws library handles compression automatically
|
|
362
|
+
return this;
|
|
363
|
+
}
|
|
364
|
+
shouldIncludeConnection(connection) {
|
|
365
|
+
const rooms = connection.getRooms();
|
|
366
|
+
// Check target rooms
|
|
367
|
+
if (this.targetRooms) {
|
|
368
|
+
const targets = Array.isArray(this.targetRooms) ? this.targetRooms : [this.targetRooms];
|
|
369
|
+
if (!targets.some(room => rooms.has(room))) {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// Check exclude rooms
|
|
374
|
+
if (this.excludeRooms) {
|
|
375
|
+
const excludes = Array.isArray(this.excludeRooms) ? this.excludeRooms : [this.excludeRooms];
|
|
376
|
+
if (excludes.some(room => rooms.has(room))) {
|
|
377
|
+
return false;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
//# sourceMappingURL=ws-adapter.js.map
|