crossws 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +7 -7
  2. package/adapters/bun.d.ts +2 -2
  3. package/adapters/cloudflare.d.ts +2 -2
  4. package/adapters/deno.d.ts +2 -2
  5. package/adapters/node.d.ts +2 -2
  6. package/adapters/sse.d.ts +2 -2
  7. package/adapters/uws.d.ts +2 -2
  8. package/dist/adapters/bun.d.mts +9 -6
  9. package/dist/adapters/bun.mjs +23 -13
  10. package/dist/adapters/cloudflare.d.mts +41 -7
  11. package/dist/adapters/cloudflare.mjs +172 -14
  12. package/dist/adapters/deno.d.mts +4 -3
  13. package/dist/adapters/deno.mjs +18 -9
  14. package/dist/adapters/node.d.mts +8 -7
  15. package/dist/adapters/node.mjs +39 -33
  16. package/dist/adapters/sse.d.mts +4 -3
  17. package/dist/adapters/sse.mjs +9 -8
  18. package/dist/adapters/uws.d.mts +15 -11
  19. package/dist/adapters/uws.mjs +25 -27
  20. package/dist/index.d.mts +35 -21
  21. package/dist/index.mjs +1 -1
  22. package/dist/server/bun.d.mts +24 -0
  23. package/dist/server/bun.mjs +37 -0
  24. package/dist/server/cloudflare.d.mts +24 -0
  25. package/dist/server/cloudflare.mjs +36 -0
  26. package/dist/server/default.d.mts +24 -0
  27. package/dist/server/default.mjs +32 -0
  28. package/dist/server/deno.d.mts +24 -0
  29. package/dist/server/deno.mjs +30 -0
  30. package/dist/server/node.d.mts +24 -0
  31. package/dist/server/node.mjs +43 -0
  32. package/dist/shared/crossws.95-eYp2D.d.mts +23 -0
  33. package/dist/shared/crossws.B31KJMcF.mjs +83 -0
  34. package/dist/shared/{crossws.ChIJSJVK.d.mts → crossws.BQXMA5bH.d.mts} +1 -1
  35. package/dist/shared/{crossws.D9ehKjSh.mjs → crossws.CPlNx7g8.mjs} +44 -25
  36. package/dist/shared/{crossws.DelSCW9g.mjs → crossws.CipVM6lf.mjs} +197 -7
  37. package/dist/shared/{crossws.BS81iGZK.mjs → crossws.WpyOHUXc.mjs} +21 -16
  38. package/dist/websocket/node.mjs +1 -1
  39. package/dist/websocket/sse.d.mts +3 -2
  40. package/dist/websocket/sse.mjs +1 -1
  41. package/package.json +61 -64
  42. package/server/bun.d.ts +2 -0
  43. package/server/deno.d.ts +2 -0
  44. package/server/node.d.ts +2 -0
  45. package/server.d.ts +2 -0
  46. package/websocket/sse.d.ts +2 -0
  47. package/websocket.d.ts +2 -2
  48. package/dist/adapters/bun.d.ts +0 -38
  49. package/dist/adapters/cloudflare-durable.d.mts +0 -41
  50. package/dist/adapters/cloudflare-durable.d.ts +0 -41
  51. package/dist/adapters/cloudflare-durable.mjs +0 -141
  52. package/dist/adapters/cloudflare.d.ts +0 -12
  53. package/dist/adapters/deno.d.ts +0 -18
  54. package/dist/adapters/node.d.ts +0 -298
  55. package/dist/adapters/sse.d.ts +0 -12
  56. package/dist/adapters/uws.d.ts +0 -58
  57. package/dist/index.d.ts +0 -156
  58. package/dist/shared/crossws.ChIJSJVK.d.ts +0 -297
  59. package/dist/websocket/native.d.ts +0 -3
  60. package/dist/websocket/node.d.ts +0 -3
  61. package/dist/websocket/sse.d.ts +0 -41
@@ -0,0 +1,30 @@
1
+ import { serve as serve$1 } from 'srvx/deno';
2
+ import denoAdapter from '../adapters/deno.mjs';
3
+ import '../shared/crossws.WpyOHUXc.mjs';
4
+ import '../shared/crossws.CPlNx7g8.mjs';
5
+ import '../shared/crossws.By9qWDAI.mjs';
6
+
7
+ function plugin(wsOpts) {
8
+ return (server) => {
9
+ const ws = denoAdapter({
10
+ hooks: wsOpts,
11
+ resolve: wsOpts.resolve,
12
+ ...wsOpts.options?.deno
13
+ });
14
+ server.options.middleware.unshift((req, next) => {
15
+ if (req.headers.get("upgrade")?.toLowerCase() === "websocket") {
16
+ return ws.handleUpgrade(req, req.runtime.deno.info);
17
+ }
18
+ return next();
19
+ });
20
+ };
21
+ }
22
+ function serve(options) {
23
+ if (options.websocket) {
24
+ options.plugins ||= [];
25
+ options.plugins.push(plugin(options.websocket));
26
+ }
27
+ return serve$1(options);
28
+ }
29
+
30
+ export { plugin, serve };
@@ -0,0 +1,24 @@
1
+ import { ServerPlugin, Server } from 'srvx/types';
2
+ import { W as WSOptions, S as ServerWithWSOptions } from '../shared/crossws.95-eYp2D.mjs';
3
+ import '../index.mjs';
4
+ import '../shared/crossws.BQXMA5bH.mjs';
5
+ import '../adapters/bun.mjs';
6
+ import 'bun';
7
+ import '../adapters/deno.mjs';
8
+ import '../adapters/node.mjs';
9
+ import 'node:http';
10
+ import 'node:stream';
11
+ import 'events';
12
+ import 'node:https';
13
+ import 'node:tls';
14
+ import 'node:url';
15
+ import 'node:zlib';
16
+ import '../adapters/sse.mjs';
17
+ import '../adapters/cloudflare.mjs';
18
+ import '@cloudflare/workers-types';
19
+ import 'cloudflare:workers';
20
+
21
+ declare function plugin(wsOpts: WSOptions): ServerPlugin;
22
+ declare function serve(options: ServerWithWSOptions): Server;
23
+
24
+ export { plugin, serve };
@@ -0,0 +1,43 @@
1
+ import { NodeRequest, serve as serve$1 } from 'srvx/node';
2
+ import nodeAdapter from '../adapters/node.mjs';
3
+ import '../shared/crossws.WpyOHUXc.mjs';
4
+ import '../shared/crossws.CPlNx7g8.mjs';
5
+ import '../shared/crossws.By9qWDAI.mjs';
6
+ import '../shared/crossws.CipVM6lf.mjs';
7
+ import 'stream';
8
+ import 'events';
9
+ import 'http';
10
+ import 'crypto';
11
+ import 'buffer';
12
+ import 'zlib';
13
+ import 'https';
14
+ import 'net';
15
+ import 'tls';
16
+ import 'url';
17
+ import '../shared/crossws.B31KJMcF.mjs';
18
+
19
+ function plugin(wsOpts) {
20
+ return (server) => {
21
+ const ws = nodeAdapter({
22
+ hooks: wsOpts,
23
+ resolve: wsOpts.resolve,
24
+ ...wsOpts.options?.deno
25
+ });
26
+ const originalServe = server.serve;
27
+ server.serve = () => {
28
+ server.node?.server.on("upgrade", (req, socket, head) => {
29
+ ws.handleUpgrade(req, socket, head, new NodeRequest(req));
30
+ });
31
+ return originalServe.call(server);
32
+ };
33
+ };
34
+ }
35
+ function serve(options) {
36
+ if (options.websocket) {
37
+ options.plugins ||= [];
38
+ options.plugins.push(plugin(options.websocket));
39
+ }
40
+ return serve$1(options);
41
+ }
42
+
43
+ export { plugin, serve };
@@ -0,0 +1,23 @@
1
+ import { ServerRequest, ServerOptions } from 'srvx/types';
2
+ import { Hooks } from '../index.mjs';
3
+ import { BunOptions } from '../adapters/bun.mjs';
4
+ import { DenoOptions } from '../adapters/deno.mjs';
5
+ import { NodeOptions } from '../adapters/node.mjs';
6
+ import { SSEOptions } from '../adapters/sse.mjs';
7
+ import { CloudflareOptions } from '../adapters/cloudflare.mjs';
8
+
9
+ type WSOptions = Partial<Hooks> & {
10
+ resolve?: (req: ServerRequest) => Partial<Hooks> | Promise<Partial<Hooks>>;
11
+ options?: {
12
+ bun?: BunOptions;
13
+ deno?: DenoOptions;
14
+ node?: NodeOptions;
15
+ sse?: SSEOptions;
16
+ cloudflare?: CloudflareOptions;
17
+ };
18
+ };
19
+ type ServerWithWSOptions = ServerOptions & {
20
+ websocket?: WSOptions;
21
+ };
22
+
23
+ export type { ServerWithWSOptions as S, WSOptions as W };
@@ -0,0 +1,83 @@
1
+ const StubRequest = /* @__PURE__ */ (() => {
2
+ class StubRequest2 {
3
+ url;
4
+ _signal;
5
+ _headers;
6
+ _init;
7
+ constructor(url, init = {}) {
8
+ this.url = url;
9
+ this._init = init;
10
+ }
11
+ get headers() {
12
+ if (!this._headers) {
13
+ this._headers = new Headers(this._init?.headers);
14
+ }
15
+ return this._headers;
16
+ }
17
+ clone() {
18
+ return new StubRequest2(this.url, this._init);
19
+ }
20
+ // --- dummy ---
21
+ get method() {
22
+ return "GET";
23
+ }
24
+ get signal() {
25
+ return this._signal ??= new AbortSignal();
26
+ }
27
+ get cache() {
28
+ return "default";
29
+ }
30
+ get credentials() {
31
+ return "same-origin";
32
+ }
33
+ get destination() {
34
+ return "";
35
+ }
36
+ get integrity() {
37
+ return "";
38
+ }
39
+ get keepalive() {
40
+ return false;
41
+ }
42
+ get redirect() {
43
+ return "follow";
44
+ }
45
+ get mode() {
46
+ return "cors";
47
+ }
48
+ get referrer() {
49
+ return "about:client";
50
+ }
51
+ get referrerPolicy() {
52
+ return "";
53
+ }
54
+ get body() {
55
+ return null;
56
+ }
57
+ get bodyUsed() {
58
+ return false;
59
+ }
60
+ arrayBuffer() {
61
+ return Promise.resolve(new ArrayBuffer(0));
62
+ }
63
+ blob() {
64
+ return Promise.resolve(new Blob());
65
+ }
66
+ bytes() {
67
+ return Promise.resolve(new Uint8Array());
68
+ }
69
+ formData() {
70
+ return Promise.resolve(new FormData());
71
+ }
72
+ json() {
73
+ return Promise.resolve(JSON.parse(""));
74
+ }
75
+ text() {
76
+ return Promise.resolve("");
77
+ }
78
+ }
79
+ Object.setPrototypeOf(StubRequest2.prototype, globalThis.Request.prototype);
80
+ return StubRequest2;
81
+ })();
82
+
83
+ export { StubRequest as S };
@@ -294,4 +294,4 @@ interface WebSocket extends EventTarget {
294
294
  removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
295
295
  }
296
296
 
297
- export type { CloseEvent as C, Event as E, MessageEvent as M, WebSocket as W, EventTarget as a };
297
+ export type { CloseEvent as C, EventTarget as E, MessageEvent as M, WebSocket as W, Event as a };
@@ -6,7 +6,8 @@ class AdapterHookable {
6
6
  callHook(name, arg1, arg2) {
7
7
  const globalHook = this.options.hooks?.[name];
8
8
  const globalPromise = globalHook?.(arg1, arg2);
9
- const resolveHooksPromise = this.options.resolve?.(arg1);
9
+ const request = arg1.request || arg1;
10
+ const resolveHooksPromise = this.options.resolve?.(request);
10
11
  if (!resolveHooksPromise) {
11
12
  return globalPromise;
12
13
  }
@@ -19,28 +20,32 @@ class AdapterHookable {
19
20
  );
20
21
  }
21
22
  async upgrade(request) {
22
- let context = request.context;
23
- if (!context) {
24
- context = {};
25
- Object.defineProperty(request, "context", {
26
- enumerable: true,
27
- value: context
28
- });
29
- }
23
+ let namespace = this.options.getNamespace?.(request) ?? new URL(request.url).pathname;
24
+ const context = request.context || {};
30
25
  try {
31
26
  const res = await this.callHook(
32
27
  "upgrade",
33
28
  request
34
29
  );
35
30
  if (!res) {
36
- return { context };
31
+ return { context, namespace };
32
+ }
33
+ if (res.namespace) {
34
+ namespace = res.namespace;
37
35
  }
38
- if (res.ok === false) {
39
- return { context, endResponse: res };
36
+ if (res.context) {
37
+ Object.assign(
38
+ context,
39
+ res.context
40
+ );
41
+ }
42
+ if (res instanceof Response) {
43
+ return { context, namespace, endResponse: res };
40
44
  }
41
45
  if (res.headers) {
42
46
  return {
43
47
  context,
48
+ namespace,
44
49
  upgradeHeaders: res.headers
45
50
  };
46
51
  }
@@ -49,38 +54,52 @@ class AdapterHookable {
49
54
  if (errResponse instanceof Response) {
50
55
  return {
51
56
  context,
57
+ namespace,
52
58
  endResponse: errResponse
53
59
  };
54
60
  }
55
61
  throw error;
56
62
  }
57
- return { context };
63
+ return { context, namespace };
58
64
  }
59
65
  }
60
66
  function defineHooks(hooks) {
61
67
  return hooks;
62
68
  }
63
69
 
64
- function adapterUtils(peers) {
70
+ function adapterUtils(globalPeers) {
65
71
  return {
66
- peers,
72
+ peers: globalPeers,
67
73
  publish(topic, message, options) {
68
- let firstPeerWithTopic;
69
- for (const peer of peers) {
70
- if (peer.topics.has(topic)) {
71
- firstPeerWithTopic = peer;
72
- break;
74
+ for (const peers of options?.namespace ? [globalPeers.get(options.namespace) || []] : globalPeers.values()) {
75
+ let firstPeerWithTopic;
76
+ for (const peer of peers) {
77
+ if (peer.topics.has(topic)) {
78
+ firstPeerWithTopic = peer;
79
+ break;
80
+ }
81
+ }
82
+ if (firstPeerWithTopic) {
83
+ firstPeerWithTopic.send(message, options);
84
+ firstPeerWithTopic.publish(topic, message, options);
73
85
  }
74
- }
75
- if (firstPeerWithTopic) {
76
- firstPeerWithTopic.send(message, options);
77
- firstPeerWithTopic.publish(topic, message, options);
78
86
  }
79
87
  }
80
88
  };
81
89
  }
90
+ function getPeers(globalPeers, namespace) {
91
+ if (!namespace) {
92
+ throw new Error("Websocket publish namespace missing.");
93
+ }
94
+ let peers = globalPeers.get(namespace);
95
+ if (!peers) {
96
+ peers = /* @__PURE__ */ new Set();
97
+ globalPeers.set(namespace, peers);
98
+ }
99
+ return peers;
100
+ }
82
101
  function defineWebSocketAdapter(factory) {
83
102
  return factory;
84
103
  }
85
104
 
86
- export { AdapterHookable as A, adapterUtils as a, defineWebSocketAdapter as b, defineHooks as d };
105
+ export { AdapterHookable as A, adapterUtils as a, defineWebSocketAdapter as b, defineHooks as d, getPeers as g };
@@ -1,6 +1,6 @@
1
+ import require$$0$2 from 'stream';
1
2
  import require$$0$3 from 'events';
2
3
  import require$$2 from 'http';
3
- import require$$0$2 from 'stream';
4
4
  import require$$1 from 'crypto';
5
5
  import require$$0$1 from 'buffer';
6
6
  import require$$0 from 'zlib';
@@ -743,6 +743,14 @@ function requirePermessageDeflate () {
743
743
  this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
744
744
  this[kError][kStatusCode] = 1009;
745
745
  this.removeListener('data', inflateOnData);
746
+
747
+ //
748
+ // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the
749
+ // fact that in Node.js versions prior to 13.10.0, the callback for
750
+ // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing
751
+ // `zlib.reset()` ensures that either the callback is invoked or an error is
752
+ // emitted.
753
+ //
746
754
  this.reset();
747
755
  }
748
756
 
@@ -758,6 +766,12 @@ function requirePermessageDeflate () {
758
766
  // closed when an error is emitted.
759
767
  //
760
768
  this[kPerMessageDeflate]._inflate = null;
769
+
770
+ if (this[kError]) {
771
+ this[kCallback](this[kError]);
772
+ return;
773
+ }
774
+
761
775
  err[kStatusCode] = 1007;
762
776
  this[kCallback](err);
763
777
  }
@@ -1639,8 +1653,6 @@ function requireReceiver () {
1639
1653
  return receiver;
1640
1654
  }
1641
1655
 
1642
- requireReceiver();
1643
-
1644
1656
  /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */
1645
1657
 
1646
1658
  var sender;
@@ -1649,6 +1661,8 @@ var hasRequiredSender;
1649
1661
  function requireSender () {
1650
1662
  if (hasRequiredSender) return sender;
1651
1663
  hasRequiredSender = 1;
1664
+
1665
+ const { Duplex } = require$$0$2;
1652
1666
  const { randomFillSync } = require$$1;
1653
1667
 
1654
1668
  const PerMessageDeflate = requirePermessageDeflate();
@@ -2197,7 +2211,7 @@ function requireSender () {
2197
2211
  /**
2198
2212
  * Sends a frame.
2199
2213
  *
2200
- * @param {Buffer[]} list The frame to send
2214
+ * @param {(Buffer | String)[]} list The frame to send
2201
2215
  * @param {Function} [cb] Callback
2202
2216
  * @private
2203
2217
  */
@@ -2249,8 +2263,6 @@ function requireSender () {
2249
2263
  return sender;
2250
2264
  }
2251
2265
 
2252
- requireSender();
2253
-
2254
2266
  var eventTarget;
2255
2267
  var hasRequiredEventTarget;
2256
2268
 
@@ -2777,6 +2789,7 @@ function requireWebsocket () {
2777
2789
  const net = require$$3;
2778
2790
  const tls = require$$4;
2779
2791
  const { randomBytes, createHash } = require$$1;
2792
+ const { Duplex, Readable } = require$$0$2;
2780
2793
  const { URL } = require$$7;
2781
2794
 
2782
2795
  const PerMessageDeflate = requirePermessageDeflate();
@@ -3476,7 +3489,7 @@ function requireWebsocket () {
3476
3489
  if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
3477
3490
  invalidUrlMessage =
3478
3491
  'The URL\'s protocol must be one of "ws:", "wss:", ' +
3479
- '"http:", "https", or "ws+unix:"';
3492
+ '"http:", "https:", or "ws+unix:"';
3480
3493
  } else if (isIpcUrl && !parsedUrl.pathname) {
3481
3494
  invalidUrlMessage = "The URL's pathname is empty";
3482
3495
  } else if (parsedUrl.hash) {
@@ -4157,6 +4170,182 @@ function requireWebsocket () {
4157
4170
  return websocket;
4158
4171
  }
4159
4172
 
4173
+ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^WebSocket$" }] */
4174
+
4175
+ var stream;
4176
+ var hasRequiredStream;
4177
+
4178
+ function requireStream () {
4179
+ if (hasRequiredStream) return stream;
4180
+ hasRequiredStream = 1;
4181
+
4182
+ requireWebsocket();
4183
+ const { Duplex } = require$$0$2;
4184
+
4185
+ /**
4186
+ * Emits the `'close'` event on a stream.
4187
+ *
4188
+ * @param {Duplex} stream The stream.
4189
+ * @private
4190
+ */
4191
+ function emitClose(stream) {
4192
+ stream.emit('close');
4193
+ }
4194
+
4195
+ /**
4196
+ * The listener of the `'end'` event.
4197
+ *
4198
+ * @private
4199
+ */
4200
+ function duplexOnEnd() {
4201
+ if (!this.destroyed && this._writableState.finished) {
4202
+ this.destroy();
4203
+ }
4204
+ }
4205
+
4206
+ /**
4207
+ * The listener of the `'error'` event.
4208
+ *
4209
+ * @param {Error} err The error
4210
+ * @private
4211
+ */
4212
+ function duplexOnError(err) {
4213
+ this.removeListener('error', duplexOnError);
4214
+ this.destroy();
4215
+ if (this.listenerCount('error') === 0) {
4216
+ // Do not suppress the throwing behavior.
4217
+ this.emit('error', err);
4218
+ }
4219
+ }
4220
+
4221
+ /**
4222
+ * Wraps a `WebSocket` in a duplex stream.
4223
+ *
4224
+ * @param {WebSocket} ws The `WebSocket` to wrap
4225
+ * @param {Object} [options] The options for the `Duplex` constructor
4226
+ * @return {Duplex} The duplex stream
4227
+ * @public
4228
+ */
4229
+ function createWebSocketStream(ws, options) {
4230
+ let terminateOnDestroy = true;
4231
+
4232
+ const duplex = new Duplex({
4233
+ ...options,
4234
+ autoDestroy: false,
4235
+ emitClose: false,
4236
+ objectMode: false,
4237
+ writableObjectMode: false
4238
+ });
4239
+
4240
+ ws.on('message', function message(msg, isBinary) {
4241
+ const data =
4242
+ !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;
4243
+
4244
+ if (!duplex.push(data)) ws.pause();
4245
+ });
4246
+
4247
+ ws.once('error', function error(err) {
4248
+ if (duplex.destroyed) return;
4249
+
4250
+ // Prevent `ws.terminate()` from being called by `duplex._destroy()`.
4251
+ //
4252
+ // - If the `'error'` event is emitted before the `'open'` event, then
4253
+ // `ws.terminate()` is a noop as no socket is assigned.
4254
+ // - Otherwise, the error is re-emitted by the listener of the `'error'`
4255
+ // event of the `Receiver` object. The listener already closes the
4256
+ // connection by calling `ws.close()`. This allows a close frame to be
4257
+ // sent to the other peer. If `ws.terminate()` is called right after this,
4258
+ // then the close frame might not be sent.
4259
+ terminateOnDestroy = false;
4260
+ duplex.destroy(err);
4261
+ });
4262
+
4263
+ ws.once('close', function close() {
4264
+ if (duplex.destroyed) return;
4265
+
4266
+ duplex.push(null);
4267
+ });
4268
+
4269
+ duplex._destroy = function (err, callback) {
4270
+ if (ws.readyState === ws.CLOSED) {
4271
+ callback(err);
4272
+ process.nextTick(emitClose, duplex);
4273
+ return;
4274
+ }
4275
+
4276
+ let called = false;
4277
+
4278
+ ws.once('error', function error(err) {
4279
+ called = true;
4280
+ callback(err);
4281
+ });
4282
+
4283
+ ws.once('close', function close() {
4284
+ if (!called) callback(err);
4285
+ process.nextTick(emitClose, duplex);
4286
+ });
4287
+
4288
+ if (terminateOnDestroy) ws.terminate();
4289
+ };
4290
+
4291
+ duplex._final = function (callback) {
4292
+ if (ws.readyState === ws.CONNECTING) {
4293
+ ws.once('open', function open() {
4294
+ duplex._final(callback);
4295
+ });
4296
+ return;
4297
+ }
4298
+
4299
+ // If the value of the `_socket` property is `null` it means that `ws` is a
4300
+ // client websocket and the handshake failed. In fact, when this happens, a
4301
+ // socket is never assigned to the websocket. Wait for the `'error'` event
4302
+ // that will be emitted by the websocket.
4303
+ if (ws._socket === null) return;
4304
+
4305
+ if (ws._socket._writableState.finished) {
4306
+ callback();
4307
+ if (duplex._readableState.endEmitted) duplex.destroy();
4308
+ } else {
4309
+ ws._socket.once('finish', function finish() {
4310
+ // `duplex` is not destroyed here because the `'end'` event will be
4311
+ // emitted on `duplex` after this `'finish'` event. The EOF signaling
4312
+ // `null` chunk is, in fact, pushed when the websocket emits `'close'`.
4313
+ callback();
4314
+ });
4315
+ ws.close();
4316
+ }
4317
+ };
4318
+
4319
+ duplex._read = function () {
4320
+ if (ws.isPaused) ws.resume();
4321
+ };
4322
+
4323
+ duplex._write = function (chunk, encoding, callback) {
4324
+ if (ws.readyState === ws.CONNECTING) {
4325
+ ws.once('open', function open() {
4326
+ duplex._write(chunk, encoding, callback);
4327
+ });
4328
+ return;
4329
+ }
4330
+
4331
+ ws.send(chunk, callback);
4332
+ };
4333
+
4334
+ duplex.on('end', duplexOnEnd);
4335
+ duplex.on('error', duplexOnError);
4336
+ return duplex;
4337
+ }
4338
+
4339
+ stream = createWebSocketStream;
4340
+ return stream;
4341
+ }
4342
+
4343
+ requireStream();
4344
+
4345
+ requireReceiver();
4346
+
4347
+ requireSender();
4348
+
4160
4349
  var websocketExports = requireWebsocket();
4161
4350
  const _WebSocket = /*@__PURE__*/getDefaultExportFromCjs(websocketExports);
4162
4351
 
@@ -4241,6 +4430,7 @@ function requireWebsocketServer () {
4241
4430
 
4242
4431
  const EventEmitter = require$$0$3;
4243
4432
  const http = require$$2;
4433
+ const { Duplex } = require$$0$2;
4244
4434
  const { createHash } = require$$1;
4245
4435
 
4246
4436
  const extension = requireExtension();
@@ -1,10 +1,8 @@
1
- import { randomUUID } from 'uncrypto';
2
-
3
1
  const kNodeInspect = /* @__PURE__ */ Symbol.for(
4
2
  "nodejs.util.inspect.custom"
5
3
  );
6
4
  function toBufferLike(val) {
7
- if (val === undefined || val === null) {
5
+ if (val === void 0 || val === null) {
8
6
  return "";
9
7
  }
10
8
  const type = typeof val;
@@ -76,7 +74,7 @@ class Message {
76
74
  */
77
75
  get id() {
78
76
  if (!this.#id) {
79
- this.#id = randomUUID();
77
+ this.#id = crypto.randomUUID();
80
78
  }
81
79
  return this.#id;
82
80
  }
@@ -210,7 +208,13 @@ class Message {
210
208
  return this.text();
211
209
  }
212
210
  [kNodeInspect]() {
213
- return { data: this.rawData };
211
+ return {
212
+ message: {
213
+ id: this.id,
214
+ peer: this.peer,
215
+ text: this.text()
216
+ }
217
+ };
214
218
  }
215
219
  }
216
220
 
@@ -226,18 +230,21 @@ class Peer {
226
230
  get context() {
227
231
  return this._internal.context ??= {};
228
232
  }
233
+ get namespace() {
234
+ return this._internal.namespace;
235
+ }
229
236
  /**
230
237
  * Unique random [uuid v4](https://developer.mozilla.org/en-US/docs/Glossary/UUID) identifier for the peer.
231
238
  */
232
239
  get id() {
233
240
  if (!this._id) {
234
- this._id = randomUUID();
241
+ this._id = crypto.randomUUID();
235
242
  }
236
243
  return this._id;
237
244
  }
238
245
  /** IP address of the peer */
239
246
  get remoteAddress() {
240
- return undefined;
247
+ return void 0;
241
248
  }
242
249
  /** upgrade request */
243
250
  get request() {
@@ -290,14 +297,12 @@ class Peer {
290
297
  return "WebSocket";
291
298
  }
292
299
  [kNodeInspect]() {
293
- return Object.fromEntries(
294
- [
295
- ["id", this.id],
296
- ["remoteAddress", this.remoteAddress],
297
- ["peers", this.peers],
298
- ["webSocket", this.websocket]
299
- ].filter((p) => p[1])
300
- );
300
+ return {
301
+ peer: {
302
+ id: this.id,
303
+ ip: this.remoteAddress
304
+ }
305
+ };
301
306
  }
302
307
  }
303
308
  function createWsProxy(ws, request) {
@@ -313,7 +318,7 @@ function createWsProxy(ws, request) {
313
318
  return request?.headers?.get("sec-websocket-extensions") || "";
314
319
  }
315
320
  case "url": {
316
- return request?.url?.replace(/^http/, "ws") || undefined;
321
+ return request?.url?.replace(/^http/, "ws") || void 0;
317
322
  }
318
323
  }
319
324
  }