crossws 0.0.0 → 0.1.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 (47) hide show
  1. package/LICENSE +46 -0
  2. package/README.md +286 -0
  3. package/adapters/bun.d.ts +1 -0
  4. package/adapters/cloudflare.d.ts +1 -0
  5. package/adapters/deno.d.ts +1 -0
  6. package/adapters/node.d.ts +1 -0
  7. package/dist/adapters/bun.cjs +72 -0
  8. package/dist/adapters/bun.d.cts +13 -0
  9. package/dist/adapters/bun.d.mts +13 -0
  10. package/dist/adapters/bun.d.ts +13 -0
  11. package/dist/adapters/bun.mjs +70 -0
  12. package/dist/adapters/cloudflare.cjs +52 -0
  13. package/dist/adapters/cloudflare.d.cts +12 -0
  14. package/dist/adapters/cloudflare.d.mts +12 -0
  15. package/dist/adapters/cloudflare.d.ts +12 -0
  16. package/dist/adapters/cloudflare.mjs +50 -0
  17. package/dist/adapters/deno.cjs +48 -0
  18. package/dist/adapters/deno.d.cts +10 -0
  19. package/dist/adapters/deno.d.mts +10 -0
  20. package/dist/adapters/deno.d.ts +10 -0
  21. package/dist/adapters/deno.mjs +46 -0
  22. package/dist/adapters/node.cjs +695 -0
  23. package/dist/adapters/node.d.cts +298 -0
  24. package/dist/adapters/node.d.mts +298 -0
  25. package/dist/adapters/node.d.ts +298 -0
  26. package/dist/adapters/node.mjs +687 -0
  27. package/dist/index.cjs +13 -0
  28. package/dist/index.d.cts +67 -0
  29. package/dist/index.d.mts +67 -0
  30. package/dist/index.d.ts +67 -0
  31. package/dist/index.mjs +7 -0
  32. package/dist/shared/crossws.21e14e0d.cjs +59 -0
  33. package/dist/shared/crossws.2ed26345.cjs +3931 -0
  34. package/dist/shared/crossws.9536f626.mjs +54 -0
  35. package/dist/shared/crossws.a5db571c.mjs +3910 -0
  36. package/dist/websocket/index.cjs +5 -0
  37. package/dist/websocket/index.d.cts +10 -0
  38. package/dist/websocket/index.d.mts +10 -0
  39. package/dist/websocket/index.d.ts +10 -0
  40. package/dist/websocket/index.mjs +3 -0
  41. package/dist/websocket/node.cjs +17 -0
  42. package/dist/websocket/node.d.cts +10 -0
  43. package/dist/websocket/node.d.mts +10 -0
  44. package/dist/websocket/node.d.ts +10 -0
  45. package/dist/websocket/node.mjs +15 -0
  46. package/package.json +94 -1
  47. package/websocket.d.ts +1 -0
@@ -0,0 +1,687 @@
1
+ import 'stream';
2
+ import { v as validationExports, g as getDefaultExportFromCjs, e as extension$1, p as permessageDeflate, w as websocket, c as constants } from '../shared/crossws.a5db571c.mjs';
3
+ import require$$0 from 'events';
4
+ import require$$2 from 'http';
5
+ import require$$1 from 'crypto';
6
+ import { d as defineWebSocketAdapter, a as WebSocketMessage, W as WebSocketError, b as WebSocketPeerBase } from '../shared/crossws.9536f626.mjs';
7
+ import 'https';
8
+ import 'net';
9
+ import 'tls';
10
+ import 'url';
11
+ import 'zlib';
12
+ import 'buffer';
13
+
14
+ const { tokenChars } = validationExports;
15
+
16
+ /**
17
+ * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
18
+ *
19
+ * @param {String} header The field value of the header
20
+ * @return {Set} The subprotocol names
21
+ * @public
22
+ */
23
+ function parse(header) {
24
+ const protocols = new Set();
25
+ let start = -1;
26
+ let end = -1;
27
+ let i = 0;
28
+
29
+ for (i; i < header.length; i++) {
30
+ const code = header.charCodeAt(i);
31
+
32
+ if (end === -1 && tokenChars[code] === 1) {
33
+ if (start === -1) start = i;
34
+ } else if (
35
+ i !== 0 &&
36
+ (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */
37
+ ) {
38
+ if (end === -1 && start !== -1) end = i;
39
+ } else if (code === 0x2c /* ',' */) {
40
+ if (start === -1) {
41
+ throw new SyntaxError(`Unexpected character at index ${i}`);
42
+ }
43
+
44
+ if (end === -1) end = i;
45
+
46
+ const protocol = header.slice(start, end);
47
+
48
+ if (protocols.has(protocol)) {
49
+ throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
50
+ }
51
+
52
+ protocols.add(protocol);
53
+ start = end = -1;
54
+ } else {
55
+ throw new SyntaxError(`Unexpected character at index ${i}`);
56
+ }
57
+ }
58
+
59
+ if (start === -1 || end !== -1) {
60
+ throw new SyntaxError('Unexpected end of input');
61
+ }
62
+
63
+ const protocol = header.slice(start, i);
64
+
65
+ if (protocols.has(protocol)) {
66
+ throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
67
+ }
68
+
69
+ protocols.add(protocol);
70
+ return protocols;
71
+ }
72
+
73
+ var subprotocol$1 = { parse };
74
+
75
+ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$" }] */
76
+
77
+ const EventEmitter = require$$0;
78
+ const http = require$$2;
79
+ const { createHash } = require$$1;
80
+
81
+ const extension = extension$1;
82
+ const PerMessageDeflate = permessageDeflate;
83
+ const subprotocol = subprotocol$1;
84
+ const WebSocket = websocket;
85
+ const { GUID, kWebSocket } = constants;
86
+
87
+ const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
88
+
89
+ const RUNNING = 0;
90
+ const CLOSING = 1;
91
+ const CLOSED = 2;
92
+
93
+ /**
94
+ * Class representing a WebSocket server.
95
+ *
96
+ * @extends EventEmitter
97
+ */
98
+ class WebSocketServer extends EventEmitter {
99
+ /**
100
+ * Create a `WebSocketServer` instance.
101
+ *
102
+ * @param {Object} options Configuration options
103
+ * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
104
+ * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
105
+ * multiple times in the same tick
106
+ * @param {Boolean} [options.autoPong=true] Specifies whether or not to
107
+ * automatically send a pong in response to a ping
108
+ * @param {Number} [options.backlog=511] The maximum length of the queue of
109
+ * pending connections
110
+ * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
111
+ * track clients
112
+ * @param {Function} [options.handleProtocols] A hook to handle protocols
113
+ * @param {String} [options.host] The hostname where to bind the server
114
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
115
+ * size
116
+ * @param {Boolean} [options.noServer=false] Enable no server mode
117
+ * @param {String} [options.path] Accept only connections matching this path
118
+ * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
119
+ * permessage-deflate
120
+ * @param {Number} [options.port] The port where to bind the server
121
+ * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
122
+ * server to use
123
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
124
+ * not to skip UTF-8 validation for text and close messages
125
+ * @param {Function} [options.verifyClient] A hook to reject connections
126
+ * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
127
+ * class to use. It must be the `WebSocket` class or class that extends it
128
+ * @param {Function} [callback] A listener for the `listening` event
129
+ */
130
+ constructor(options, callback) {
131
+ super();
132
+
133
+ options = {
134
+ allowSynchronousEvents: false,
135
+ autoPong: true,
136
+ maxPayload: 100 * 1024 * 1024,
137
+ skipUTF8Validation: false,
138
+ perMessageDeflate: false,
139
+ handleProtocols: null,
140
+ clientTracking: true,
141
+ verifyClient: null,
142
+ noServer: false,
143
+ backlog: null, // use default (511 as implemented in net.js)
144
+ server: null,
145
+ host: null,
146
+ path: null,
147
+ port: null,
148
+ WebSocket,
149
+ ...options
150
+ };
151
+
152
+ if (
153
+ (options.port == null && !options.server && !options.noServer) ||
154
+ (options.port != null && (options.server || options.noServer)) ||
155
+ (options.server && options.noServer)
156
+ ) {
157
+ throw new TypeError(
158
+ 'One and only one of the "port", "server", or "noServer" options ' +
159
+ 'must be specified'
160
+ );
161
+ }
162
+
163
+ if (options.port != null) {
164
+ this._server = http.createServer((req, res) => {
165
+ const body = http.STATUS_CODES[426];
166
+
167
+ res.writeHead(426, {
168
+ 'Content-Length': body.length,
169
+ 'Content-Type': 'text/plain'
170
+ });
171
+ res.end(body);
172
+ });
173
+ this._server.listen(
174
+ options.port,
175
+ options.host,
176
+ options.backlog,
177
+ callback
178
+ );
179
+ } else if (options.server) {
180
+ this._server = options.server;
181
+ }
182
+
183
+ if (this._server) {
184
+ const emitConnection = this.emit.bind(this, 'connection');
185
+
186
+ this._removeListeners = addListeners(this._server, {
187
+ listening: this.emit.bind(this, 'listening'),
188
+ error: this.emit.bind(this, 'error'),
189
+ upgrade: (req, socket, head) => {
190
+ this.handleUpgrade(req, socket, head, emitConnection);
191
+ }
192
+ });
193
+ }
194
+
195
+ if (options.perMessageDeflate === true) options.perMessageDeflate = {};
196
+ if (options.clientTracking) {
197
+ this.clients = new Set();
198
+ this._shouldEmitClose = false;
199
+ }
200
+
201
+ this.options = options;
202
+ this._state = RUNNING;
203
+ }
204
+
205
+ /**
206
+ * Returns the bound address, the address family name, and port of the server
207
+ * as reported by the operating system if listening on an IP socket.
208
+ * If the server is listening on a pipe or UNIX domain socket, the name is
209
+ * returned as a string.
210
+ *
211
+ * @return {(Object|String|null)} The address of the server
212
+ * @public
213
+ */
214
+ address() {
215
+ if (this.options.noServer) {
216
+ throw new Error('The server is operating in "noServer" mode');
217
+ }
218
+
219
+ if (!this._server) return null;
220
+ return this._server.address();
221
+ }
222
+
223
+ /**
224
+ * Stop the server from accepting new connections and emit the `'close'` event
225
+ * when all existing connections are closed.
226
+ *
227
+ * @param {Function} [cb] A one-time listener for the `'close'` event
228
+ * @public
229
+ */
230
+ close(cb) {
231
+ if (this._state === CLOSED) {
232
+ if (cb) {
233
+ this.once('close', () => {
234
+ cb(new Error('The server is not running'));
235
+ });
236
+ }
237
+
238
+ process.nextTick(emitClose, this);
239
+ return;
240
+ }
241
+
242
+ if (cb) this.once('close', cb);
243
+
244
+ if (this._state === CLOSING) return;
245
+ this._state = CLOSING;
246
+
247
+ if (this.options.noServer || this.options.server) {
248
+ if (this._server) {
249
+ this._removeListeners();
250
+ this._removeListeners = this._server = null;
251
+ }
252
+
253
+ if (this.clients) {
254
+ if (!this.clients.size) {
255
+ process.nextTick(emitClose, this);
256
+ } else {
257
+ this._shouldEmitClose = true;
258
+ }
259
+ } else {
260
+ process.nextTick(emitClose, this);
261
+ }
262
+ } else {
263
+ const server = this._server;
264
+
265
+ this._removeListeners();
266
+ this._removeListeners = this._server = null;
267
+
268
+ //
269
+ // The HTTP/S server was created internally. Close it, and rely on its
270
+ // `'close'` event.
271
+ //
272
+ server.close(() => {
273
+ emitClose(this);
274
+ });
275
+ }
276
+ }
277
+
278
+ /**
279
+ * See if a given request should be handled by this server instance.
280
+ *
281
+ * @param {http.IncomingMessage} req Request object to inspect
282
+ * @return {Boolean} `true` if the request is valid, else `false`
283
+ * @public
284
+ */
285
+ shouldHandle(req) {
286
+ if (this.options.path) {
287
+ const index = req.url.indexOf('?');
288
+ const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
289
+
290
+ if (pathname !== this.options.path) return false;
291
+ }
292
+
293
+ return true;
294
+ }
295
+
296
+ /**
297
+ * Handle a HTTP Upgrade request.
298
+ *
299
+ * @param {http.IncomingMessage} req The request object
300
+ * @param {Duplex} socket The network socket between the server and client
301
+ * @param {Buffer} head The first packet of the upgraded stream
302
+ * @param {Function} cb Callback
303
+ * @public
304
+ */
305
+ handleUpgrade(req, socket, head, cb) {
306
+ socket.on('error', socketOnError);
307
+
308
+ const key = req.headers['sec-websocket-key'];
309
+ const version = +req.headers['sec-websocket-version'];
310
+
311
+ if (req.method !== 'GET') {
312
+ const message = 'Invalid HTTP method';
313
+ abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
314
+ return;
315
+ }
316
+
317
+ if (req.headers.upgrade.toLowerCase() !== 'websocket') {
318
+ const message = 'Invalid Upgrade header';
319
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
320
+ return;
321
+ }
322
+
323
+ if (!key || !keyRegex.test(key)) {
324
+ const message = 'Missing or invalid Sec-WebSocket-Key header';
325
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
326
+ return;
327
+ }
328
+
329
+ if (version !== 8 && version !== 13) {
330
+ const message = 'Missing or invalid Sec-WebSocket-Version header';
331
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
332
+ return;
333
+ }
334
+
335
+ if (!this.shouldHandle(req)) {
336
+ abortHandshake(socket, 400);
337
+ return;
338
+ }
339
+
340
+ const secWebSocketProtocol = req.headers['sec-websocket-protocol'];
341
+ let protocols = new Set();
342
+
343
+ if (secWebSocketProtocol !== undefined) {
344
+ try {
345
+ protocols = subprotocol.parse(secWebSocketProtocol);
346
+ } catch (err) {
347
+ const message = 'Invalid Sec-WebSocket-Protocol header';
348
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
349
+ return;
350
+ }
351
+ }
352
+
353
+ const secWebSocketExtensions = req.headers['sec-websocket-extensions'];
354
+ const extensions = {};
355
+
356
+ if (
357
+ this.options.perMessageDeflate &&
358
+ secWebSocketExtensions !== undefined
359
+ ) {
360
+ const perMessageDeflate = new PerMessageDeflate(
361
+ this.options.perMessageDeflate,
362
+ true,
363
+ this.options.maxPayload
364
+ );
365
+
366
+ try {
367
+ const offers = extension.parse(secWebSocketExtensions);
368
+
369
+ if (offers[PerMessageDeflate.extensionName]) {
370
+ perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
371
+ extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
372
+ }
373
+ } catch (err) {
374
+ const message =
375
+ 'Invalid or unacceptable Sec-WebSocket-Extensions header';
376
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
377
+ return;
378
+ }
379
+ }
380
+
381
+ //
382
+ // Optionally call external client verification handler.
383
+ //
384
+ if (this.options.verifyClient) {
385
+ const info = {
386
+ origin:
387
+ req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
388
+ secure: !!(req.socket.authorized || req.socket.encrypted),
389
+ req
390
+ };
391
+
392
+ if (this.options.verifyClient.length === 2) {
393
+ this.options.verifyClient(info, (verified, code, message, headers) => {
394
+ if (!verified) {
395
+ return abortHandshake(socket, code || 401, message, headers);
396
+ }
397
+
398
+ this.completeUpgrade(
399
+ extensions,
400
+ key,
401
+ protocols,
402
+ req,
403
+ socket,
404
+ head,
405
+ cb
406
+ );
407
+ });
408
+ return;
409
+ }
410
+
411
+ if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
412
+ }
413
+
414
+ this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
415
+ }
416
+
417
+ /**
418
+ * Upgrade the connection to WebSocket.
419
+ *
420
+ * @param {Object} extensions The accepted extensions
421
+ * @param {String} key The value of the `Sec-WebSocket-Key` header
422
+ * @param {Set} protocols The subprotocols
423
+ * @param {http.IncomingMessage} req The request object
424
+ * @param {Duplex} socket The network socket between the server and client
425
+ * @param {Buffer} head The first packet of the upgraded stream
426
+ * @param {Function} cb Callback
427
+ * @throws {Error} If called more than once with the same socket
428
+ * @private
429
+ */
430
+ completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
431
+ //
432
+ // Destroy the socket if the client has already sent a FIN packet.
433
+ //
434
+ if (!socket.readable || !socket.writable) return socket.destroy();
435
+
436
+ if (socket[kWebSocket]) {
437
+ throw new Error(
438
+ 'server.handleUpgrade() was called more than once with the same ' +
439
+ 'socket, possibly due to a misconfiguration'
440
+ );
441
+ }
442
+
443
+ if (this._state > RUNNING) return abortHandshake(socket, 503);
444
+
445
+ const digest = createHash('sha1')
446
+ .update(key + GUID)
447
+ .digest('base64');
448
+
449
+ const headers = [
450
+ 'HTTP/1.1 101 Switching Protocols',
451
+ 'Upgrade: websocket',
452
+ 'Connection: Upgrade',
453
+ `Sec-WebSocket-Accept: ${digest}`
454
+ ];
455
+
456
+ const ws = new this.options.WebSocket(null, undefined, this.options);
457
+
458
+ if (protocols.size) {
459
+ //
460
+ // Optionally call external protocol selection handler.
461
+ //
462
+ const protocol = this.options.handleProtocols
463
+ ? this.options.handleProtocols(protocols, req)
464
+ : protocols.values().next().value;
465
+
466
+ if (protocol) {
467
+ headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
468
+ ws._protocol = protocol;
469
+ }
470
+ }
471
+
472
+ if (extensions[PerMessageDeflate.extensionName]) {
473
+ const params = extensions[PerMessageDeflate.extensionName].params;
474
+ const value = extension.format({
475
+ [PerMessageDeflate.extensionName]: [params]
476
+ });
477
+ headers.push(`Sec-WebSocket-Extensions: ${value}`);
478
+ ws._extensions = extensions;
479
+ }
480
+
481
+ //
482
+ // Allow external modification/inspection of handshake headers.
483
+ //
484
+ this.emit('headers', headers, req);
485
+
486
+ socket.write(headers.concat('\r\n').join('\r\n'));
487
+ socket.removeListener('error', socketOnError);
488
+
489
+ ws.setSocket(socket, head, {
490
+ allowSynchronousEvents: this.options.allowSynchronousEvents,
491
+ maxPayload: this.options.maxPayload,
492
+ skipUTF8Validation: this.options.skipUTF8Validation
493
+ });
494
+
495
+ if (this.clients) {
496
+ this.clients.add(ws);
497
+ ws.on('close', () => {
498
+ this.clients.delete(ws);
499
+
500
+ if (this._shouldEmitClose && !this.clients.size) {
501
+ process.nextTick(emitClose, this);
502
+ }
503
+ });
504
+ }
505
+
506
+ cb(ws, req);
507
+ }
508
+ }
509
+
510
+ var websocketServer = WebSocketServer;
511
+
512
+ /**
513
+ * Add event listeners on an `EventEmitter` using a map of <event, listener>
514
+ * pairs.
515
+ *
516
+ * @param {EventEmitter} server The event emitter
517
+ * @param {Object.<String, Function>} map The listeners to add
518
+ * @return {Function} A function that will remove the added listeners when
519
+ * called
520
+ * @private
521
+ */
522
+ function addListeners(server, map) {
523
+ for (const event of Object.keys(map)) server.on(event, map[event]);
524
+
525
+ return function removeListeners() {
526
+ for (const event of Object.keys(map)) {
527
+ server.removeListener(event, map[event]);
528
+ }
529
+ };
530
+ }
531
+
532
+ /**
533
+ * Emit a `'close'` event on an `EventEmitter`.
534
+ *
535
+ * @param {EventEmitter} server The event emitter
536
+ * @private
537
+ */
538
+ function emitClose(server) {
539
+ server._state = CLOSED;
540
+ server.emit('close');
541
+ }
542
+
543
+ /**
544
+ * Handle socket errors.
545
+ *
546
+ * @private
547
+ */
548
+ function socketOnError() {
549
+ this.destroy();
550
+ }
551
+
552
+ /**
553
+ * Close the connection when preconditions are not fulfilled.
554
+ *
555
+ * @param {Duplex} socket The socket of the upgrade request
556
+ * @param {Number} code The HTTP response status code
557
+ * @param {String} [message] The HTTP response body
558
+ * @param {Object} [headers] Additional HTTP response headers
559
+ * @private
560
+ */
561
+ function abortHandshake(socket, code, message, headers) {
562
+ //
563
+ // The socket is writable unless the user destroyed or ended it before calling
564
+ // `server.handleUpgrade()` or in the `verifyClient` function, which is a user
565
+ // error. Handling this does not make much sense as the worst that can happen
566
+ // is that some of the data written by the user might be discarded due to the
567
+ // call to `socket.end()` below, which triggers an `'error'` event that in
568
+ // turn causes the socket to be destroyed.
569
+ //
570
+ message = message || http.STATUS_CODES[code];
571
+ headers = {
572
+ Connection: 'close',
573
+ 'Content-Type': 'text/html',
574
+ 'Content-Length': Buffer.byteLength(message),
575
+ ...headers
576
+ };
577
+
578
+ socket.once('finish', socket.destroy);
579
+
580
+ socket.end(
581
+ `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
582
+ Object.keys(headers)
583
+ .map((h) => `${h}: ${headers[h]}`)
584
+ .join('\r\n') +
585
+ '\r\n\r\n' +
586
+ message
587
+ );
588
+ }
589
+
590
+ /**
591
+ * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
592
+ * one listener for it, otherwise call `abortHandshake()`.
593
+ *
594
+ * @param {WebSocketServer} server The WebSocket server
595
+ * @param {http.IncomingMessage} req The request object
596
+ * @param {Duplex} socket The socket of the upgrade request
597
+ * @param {Number} code The HTTP response status code
598
+ * @param {String} message The HTTP response body
599
+ * @private
600
+ */
601
+ function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) {
602
+ if (server.listenerCount('wsClientError')) {
603
+ const err = new Error(message);
604
+ Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
605
+
606
+ server.emit('wsClientError', err, socket, req);
607
+ } else {
608
+ abortHandshake(socket, code, message);
609
+ }
610
+ }
611
+
612
+ const _WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServer);
613
+
614
+ const node = defineWebSocketAdapter(
615
+ (hooks, opts = {}) => {
616
+ const wss = opts.wss || new _WebSocketServer({
617
+ noServer: true,
618
+ ...opts.serverOptions
619
+ });
620
+ wss.on("connection", (ws, req) => {
621
+ const peer = new NodeWebSocketPeer({ node: { ws, req, server: wss } });
622
+ hooks.open?.(peer);
623
+ ws.on("message", (data, isBinary) => {
624
+ hooks["node:message"]?.(peer, data, isBinary);
625
+ if (Array.isArray(data)) {
626
+ data = Buffer.concat(data);
627
+ }
628
+ hooks.message?.(peer, new WebSocketMessage(data, isBinary));
629
+ });
630
+ ws.on("error", (error) => {
631
+ hooks["node:error"]?.(peer, error);
632
+ hooks.error?.(peer, new WebSocketError(error));
633
+ });
634
+ ws.on("close", (code, reason) => {
635
+ hooks["node:close"]?.(peer, code, reason);
636
+ hooks.close?.(peer, {
637
+ code,
638
+ reason: reason?.toString()
639
+ });
640
+ });
641
+ ws.on("open", () => {
642
+ hooks["node:open"]?.(peer);
643
+ });
644
+ ws.on("ping", (data) => {
645
+ hooks["node:ping"]?.(peer, data);
646
+ });
647
+ ws.on("pong", (data) => {
648
+ hooks["node:pong"]?.(peer, data);
649
+ });
650
+ ws.on(
651
+ "unexpected-response",
652
+ (req2, res) => {
653
+ hooks["node:unexpected-response"]?.(peer, req2, res);
654
+ }
655
+ );
656
+ ws.on("upgrade", (req2) => {
657
+ hooks["node:upgrade"]?.(peer, req2);
658
+ });
659
+ });
660
+ return {
661
+ handleUpgrade: (req, socket, head) => {
662
+ wss.handleUpgrade(req, socket, head, (ws) => {
663
+ wss.emit("connection", ws, req);
664
+ });
665
+ }
666
+ };
667
+ }
668
+ );
669
+ class NodeWebSocketPeer extends WebSocketPeerBase {
670
+ get id() {
671
+ const socket = this.ctx.node.req.socket;
672
+ if (!socket) {
673
+ return void 0;
674
+ }
675
+ const addr = socket.remoteFamily === "IPv6" ? `[${socket.remoteAddress}]` : socket.remoteAddress;
676
+ return `${addr}:${socket.remotePort}`;
677
+ }
678
+ get readyState() {
679
+ return this.ctx.node.ws.readyState;
680
+ }
681
+ send(message, compress) {
682
+ this.ctx.node.ws.send(message, { compress });
683
+ return 0;
684
+ }
685
+ }
686
+
687
+ export { node as default };
package/dist/index.cjs ADDED
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ const peer = require('./shared/crossws.21e14e0d.cjs');
4
+
5
+ function defineWebSocketHooks(hooks) {
6
+ return hooks;
7
+ }
8
+
9
+ exports.WebSocketError = peer.WebSocketError;
10
+ exports.WebSocketMessage = peer.WebSocketMessage;
11
+ exports.WebSocketPeerBase = peer.WebSocketPeerBase;
12
+ exports.defineWebSocketAdapter = peer.defineWebSocketAdapter;
13
+ exports.defineWebSocketHooks = defineWebSocketHooks;