crossws 0.3.5 → 0.4.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 (53) hide show
  1. package/adapters/bun.d.ts +2 -2
  2. package/adapters/cloudflare.d.ts +2 -2
  3. package/adapters/deno.d.ts +2 -2
  4. package/adapters/node.d.ts +2 -2
  5. package/adapters/sse.d.ts +2 -2
  6. package/adapters/uws.d.ts +2 -2
  7. package/dist/adapters/bun.d.mts +5 -3
  8. package/dist/adapters/bun.mjs +23 -13
  9. package/dist/adapters/cloudflare.d.mts +40 -7
  10. package/dist/adapters/cloudflare.mjs +172 -14
  11. package/dist/adapters/deno.mjs +18 -9
  12. package/dist/adapters/node.d.mts +1 -1
  13. package/dist/adapters/node.mjs +28 -29
  14. package/dist/adapters/sse.mjs +8 -7
  15. package/dist/adapters/uws.d.mts +12 -9
  16. package/dist/adapters/uws.mjs +25 -27
  17. package/dist/index.d.mts +33 -20
  18. package/dist/index.mjs +1 -1
  19. package/dist/server/bun.d.mts +24 -0
  20. package/dist/server/bun.mjs +37 -0
  21. package/dist/server/cloudflare.d.mts +24 -0
  22. package/dist/server/cloudflare.mjs +36 -0
  23. package/dist/server/default.d.mts +24 -0
  24. package/dist/server/default.mjs +32 -0
  25. package/dist/server/deno.d.mts +24 -0
  26. package/dist/server/deno.mjs +30 -0
  27. package/dist/server/node.d.mts +24 -0
  28. package/dist/server/node.mjs +49 -0
  29. package/dist/shared/crossws.95-eYp2D.d.mts +23 -0
  30. package/dist/shared/crossws.B31KJMcF.mjs +83 -0
  31. package/dist/shared/{crossws.D9ehKjSh.mjs → crossws.CPlNx7g8.mjs} +44 -25
  32. package/dist/shared/{crossws.DfCzGthR.mjs → crossws.WpyOHUXc.mjs} +18 -13
  33. package/package.json +42 -53
  34. package/server/bun.d.ts +2 -0
  35. package/server/deno.d.ts +2 -0
  36. package/server/node.d.ts +2 -0
  37. package/server.d.ts +2 -0
  38. package/websocket/sse.d.ts +2 -0
  39. package/websocket.d.ts +2 -2
  40. package/dist/adapters/bun.d.ts +0 -39
  41. package/dist/adapters/cloudflare-durable.d.mts +0 -42
  42. package/dist/adapters/cloudflare-durable.d.ts +0 -42
  43. package/dist/adapters/cloudflare-durable.mjs +0 -141
  44. package/dist/adapters/cloudflare.d.ts +0 -13
  45. package/dist/adapters/deno.d.ts +0 -19
  46. package/dist/adapters/node.d.ts +0 -299
  47. package/dist/adapters/sse.d.ts +0 -13
  48. package/dist/adapters/uws.d.ts +0 -59
  49. package/dist/index.d.ts +0 -157
  50. package/dist/shared/crossws.BQXMA5bH.d.ts +0 -297
  51. package/dist/websocket/native.d.ts +0 -3
  52. package/dist/websocket/node.d.ts +0 -3
  53. package/dist/websocket/sse.d.ts +0 -42
package/adapters/bun.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from "../dist/adapters/bun";
2
- export { default } from "../dist/adapters/bun";
1
+ export * from "../dist/adapters/bun.mjs";
2
+ export { default } from "../dist/adapters/bun.mjs";
@@ -1,2 +1,2 @@
1
- export * from "../dist/adapters/cloudflare";
2
- export { default } from "../dist/adapters/cloudflare";
1
+ export * from "../dist/adapters/cloudflare.mjs";
2
+ export { default } from "../dist/adapters/cloudflare.mjs";
@@ -1,2 +1,2 @@
1
- export * from "../dist/adapters/deno";
2
- export { default } from "../dist/adapters/deno";
1
+ export * from "../dist/adapters/deno.mjs";
2
+ export { default } from "../dist/adapters/deno.mjs";
@@ -1,2 +1,2 @@
1
- export * from "../dist/adapters/node";
2
- export { default } from "../dist/adapters/node";
1
+ export * from "../dist/adapters/node.mjs";
2
+ export { default } from "../dist/adapters/node.mjs";
package/adapters/sse.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from "../dist/adapters/sse";
2
- export { default } from "../dist/adapters/sse";
1
+ export * from "../dist/adapters/sse.mjs";
2
+ export { default } from "../dist/adapters/sse.mjs";
package/adapters/uws.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export * from "../dist/adapters/uws";
2
- export { default } from "../dist/adapters/uws";
1
+ export * from "../dist/adapters/uws.mjs";
2
+ export { default } from "../dist/adapters/uws.mjs";
@@ -1,5 +1,5 @@
1
1
  import { WebSocketHandler, ServerWebSocket, Server } from 'bun';
2
- import { Adapter, AdapterInstance, Peer, AdapterOptions } from '../index.mjs';
2
+ import { Adapter, AdapterInstance, Peer, PeerContext, AdapterOptions } from '../index.mjs';
3
3
  import '../shared/crossws.BQXMA5bH.mjs';
4
4
 
5
5
  interface BunAdapter extends AdapterInstance {
@@ -10,19 +10,21 @@ interface BunOptions extends AdapterOptions {
10
10
  }
11
11
  type ContextData = {
12
12
  peer?: BunPeer;
13
+ namespace: string;
13
14
  request: Request;
14
15
  server?: Server;
15
- context: Peer["context"];
16
+ context: PeerContext;
16
17
  };
17
18
  declare const bunAdapter: Adapter<BunAdapter, BunOptions>;
18
19
 
19
20
  declare class BunPeer extends Peer<{
20
21
  ws: ServerWebSocket<ContextData>;
22
+ namespace: string;
21
23
  request: Request;
22
24
  peers: Set<BunPeer>;
23
25
  }> {
24
26
  get remoteAddress(): string;
25
- get context(): Peer["context"];
27
+ get context(): PeerContext;
26
28
  send(data: unknown, options?: {
27
29
  compress?: boolean;
28
30
  }): number;
@@ -1,14 +1,18 @@
1
- import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DfCzGthR.mjs';
2
- import { a as adapterUtils, A as AdapterHookable } from '../shared/crossws.D9ehKjSh.mjs';
3
- import 'uncrypto';
1
+ import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.WpyOHUXc.mjs';
2
+ import { a as adapterUtils, g as getPeers, A as AdapterHookable } from '../shared/crossws.CPlNx7g8.mjs';
4
3
 
5
4
  const bunAdapter = (options = {}) => {
5
+ if (typeof Bun === "undefined") {
6
+ throw new Error(
7
+ "[crossws] Using Bun adapter in an incompatible environment."
8
+ );
9
+ }
6
10
  const hooks = new AdapterHookable(options);
7
- const peers = /* @__PURE__ */ new Set();
11
+ const globalPeers = /* @__PURE__ */ new Map();
8
12
  return {
9
- ...adapterUtils(peers),
13
+ ...adapterUtils(globalPeers),
10
14
  async handleUpgrade(request, server) {
11
- const { upgradeHeaders, endResponse, context } = await hooks.upgrade(request);
15
+ const { upgradeHeaders, endResponse, context, namespace } = await hooks.upgrade(request);
12
16
  if (endResponse) {
13
17
  return endResponse;
14
18
  }
@@ -16,7 +20,8 @@ const bunAdapter = (options = {}) => {
16
20
  data: {
17
21
  server,
18
22
  request,
19
- context
23
+ context,
24
+ namespace
20
25
  },
21
26
  headers: upgradeHeaders
22
27
  });
@@ -26,15 +31,18 @@ const bunAdapter = (options = {}) => {
26
31
  },
27
32
  websocket: {
28
33
  message: (ws, message) => {
34
+ const peers = getPeers(globalPeers, ws.data.namespace);
29
35
  const peer = getPeer(ws, peers);
30
36
  hooks.callHook("message", peer, new Message(message, peer));
31
37
  },
32
38
  open: (ws) => {
39
+ const peers = getPeers(globalPeers, ws.data.namespace);
33
40
  const peer = getPeer(ws, peers);
34
41
  peers.add(peer);
35
42
  hooks.callHook("open", peer);
36
43
  },
37
44
  close: (ws, code, reason) => {
45
+ const peers = getPeers(globalPeers, ws.data.namespace);
38
46
  const peer = getPeer(ws, peers);
39
47
  peers.delete(peer);
40
48
  hooks.callHook("close", peer, { code, reason });
@@ -43,14 +51,16 @@ const bunAdapter = (options = {}) => {
43
51
  };
44
52
  };
45
53
  function getPeer(ws, peers) {
46
- if (ws.data?.peer) {
54
+ if (ws.data.peer) {
47
55
  return ws.data.peer;
48
56
  }
49
- const peer = new BunPeer({ ws, request: ws.data.request, peers });
50
- ws.data = {
51
- ...ws.data,
52
- peer
53
- };
57
+ const peer = new BunPeer({
58
+ ws,
59
+ request: ws.data.request,
60
+ peers,
61
+ namespace: ws.data.namespace
62
+ });
63
+ ws.data.peer = peer;
54
64
  return peer;
55
65
  }
56
66
  class BunPeer extends Peer {
@@ -1,13 +1,46 @@
1
- import { Adapter, AdapterInstance, AdapterOptions } from '../index.mjs';
2
1
  import * as CF from '@cloudflare/workers-types';
3
- import '../shared/crossws.BQXMA5bH.mjs';
2
+ import { DurableObject } from 'cloudflare:workers';
3
+ import { Adapter, AdapterInstance, AdapterOptions } from '../index.mjs';
4
+ import { W as WebSocket$1 } from '../shared/crossws.BQXMA5bH.mjs';
4
5
 
5
- interface CloudflareAdapter extends AdapterInstance {
6
- handleUpgrade(req: CF.Request, env: unknown, context: CF.ExecutionContext): Promise<CF.Response>;
7
- }
6
+ type WSDurableObjectStub = CF.DurableObjectStub & {
7
+ webSocketPublish?: (topic: string, data: unknown, opts: any) => Promise<void>;
8
+ };
9
+ type ResolveDurableStub = (req: CF.Request | undefined, env: unknown, context: CF.ExecutionContext | undefined) => WSDurableObjectStub | undefined | Promise<WSDurableObjectStub | undefined>;
8
10
  interface CloudflareOptions extends AdapterOptions {
11
+ /**
12
+ * Durable Object binding name from environment.
13
+ *
14
+ * **Note:** This option will be ignored if `resolveDurableStub` is provided.
15
+ *
16
+ * @default "$DurableObject"
17
+ */
18
+ bindingName?: string;
19
+ /**
20
+ * Durable Object instance name.
21
+ *
22
+ * **Note:** This option will be ignored if `resolveDurableStub` is provided.
23
+ *
24
+ * @default "crossws"
25
+ */
26
+ instanceName?: string;
27
+ /**
28
+ * Custom function that resolves Durable Object binding to handle the WebSocket upgrade.
29
+ *
30
+ * **Note:** This option will override `bindingName` and `instanceName`.
31
+ */
32
+ resolveDurableStub?: ResolveDurableStub;
33
+ }
34
+ declare const cloudflareAdapter: Adapter<CloudflareDurableAdapter, CloudflareOptions>;
35
+
36
+ interface CloudflareDurableAdapter extends AdapterInstance {
37
+ handleUpgrade(req: Request | CF.Request, env: unknown, context: CF.ExecutionContext): Promise<Response>;
38
+ handleDurableInit(obj: DurableObject, state: DurableObjectState, env: unknown): void;
39
+ handleDurableUpgrade(obj: DurableObject, req: Request | CF.Request): Promise<Response>;
40
+ handleDurableMessage(obj: DurableObject, ws: WebSocket | CF.WebSocket | WebSocket$1, message: ArrayBuffer | string): Promise<void>;
41
+ handleDurablePublish: (obj: DurableObject, topic: string, data: unknown, opts: any) => Promise<void>;
42
+ handleDurableClose(obj: DurableObject, ws: WebSocket | CF.WebSocket | WebSocket$1, code: number, reason: string, wasClean: boolean): Promise<void>;
9
43
  }
10
- declare const cloudflareAdapter: Adapter<CloudflareAdapter, CloudflareOptions>;
11
44
 
12
45
  export { cloudflareAdapter as default };
13
- export type { CloudflareAdapter, CloudflareOptions };
46
+ export type { CloudflareDurableAdapter, CloudflareOptions };
@@ -1,31 +1,54 @@
1
- import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DfCzGthR.mjs';
2
- import { a as adapterUtils, A as AdapterHookable } from '../shared/crossws.D9ehKjSh.mjs';
1
+ import { env } from 'cloudflare:workers';
2
+ import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.WpyOHUXc.mjs';
3
+ import { a as adapterUtils, g as getPeers, A as AdapterHookable } from '../shared/crossws.CPlNx7g8.mjs';
4
+ import { S as StubRequest } from '../shared/crossws.B31KJMcF.mjs';
3
5
  import { W as WSError } from '../shared/crossws.By9qWDAI.mjs';
4
- import 'uncrypto';
5
6
 
6
- const cloudflareAdapter = (options = {}) => {
7
- const hooks = new AdapterHookable(options);
8
- const peers = /* @__PURE__ */ new Set();
7
+ const cloudflareAdapter = (opts = {}) => {
8
+ const hooks = new AdapterHookable(opts);
9
+ const globalPeers = /* @__PURE__ */ new Map();
10
+ const resolveDurableStub = opts.resolveDurableStub || ((_req, env$1, _context) => {
11
+ const bindingName = opts.bindingName || "$DurableObject";
12
+ const binding = (env$1 || env)[bindingName];
13
+ if (binding) {
14
+ const instanceId = binding.idFromName(opts.instanceName || "crossws");
15
+ return binding.get(instanceId);
16
+ }
17
+ });
18
+ const { publish: durablePublish, ...utils } = adapterUtils(globalPeers);
9
19
  return {
10
- ...adapterUtils(peers),
11
- handleUpgrade: async (request, env, cfCtx) => {
12
- const { upgradeHeaders, endResponse, context } = await hooks.upgrade(
13
- request
20
+ ...utils,
21
+ handleUpgrade: async (request, cfEnv, cfCtx) => {
22
+ const stub = await resolveDurableStub(
23
+ request,
24
+ cfEnv,
25
+ cfCtx
14
26
  );
27
+ if (stub) {
28
+ return stub.fetch(
29
+ request
30
+ );
31
+ }
32
+ const { upgradeHeaders, endResponse, context, namespace } = await hooks.upgrade(request);
15
33
  if (endResponse) {
16
34
  return endResponse;
17
35
  }
36
+ const peers = getPeers(
37
+ globalPeers,
38
+ namespace
39
+ );
18
40
  const pair = new WebSocketPair();
19
41
  const client = pair[0];
20
42
  const server = pair[1];
21
- const peer = new CloudflarePeer({
43
+ const peer = new CloudflareFallbackPeer({
22
44
  ws: client,
23
45
  peers,
24
46
  wsServer: server,
25
47
  request,
26
- cfEnv: env,
48
+ cfEnv,
27
49
  cfCtx,
28
- context
50
+ context,
51
+ namespace
29
52
  });
30
53
  peers.add(peer);
31
54
  server.accept();
@@ -50,19 +73,154 @@ const cloudflareAdapter = (options = {}) => {
50
73
  webSocket: client,
51
74
  headers: upgradeHeaders
52
75
  });
76
+ },
77
+ handleDurableInit: async (obj, state, env) => {
78
+ },
79
+ handleDurableUpgrade: async (obj, request) => {
80
+ const { upgradeHeaders, endResponse, namespace } = await hooks.upgrade(
81
+ request
82
+ );
83
+ if (endResponse) {
84
+ return endResponse;
85
+ }
86
+ const peers = getPeers(globalPeers, namespace);
87
+ const pair = new WebSocketPair();
88
+ const client = pair[0];
89
+ const server = pair[1];
90
+ const peer = CloudflareDurablePeer._restore(
91
+ obj,
92
+ server,
93
+ request,
94
+ namespace
95
+ );
96
+ peers.add(peer);
97
+ obj.ctx.acceptWebSocket(server);
98
+ await hooks.callHook("open", peer);
99
+ return new Response(null, {
100
+ status: 101,
101
+ webSocket: client,
102
+ headers: upgradeHeaders
103
+ });
104
+ },
105
+ handleDurableMessage: async (obj, ws, message) => {
106
+ const peer = CloudflareDurablePeer._restore(obj, ws);
107
+ await hooks.callHook("message", peer, new Message(message, peer));
108
+ },
109
+ handleDurableClose: async (obj, ws, code, reason, wasClean) => {
110
+ const peer = CloudflareDurablePeer._restore(obj, ws);
111
+ const peers = getPeers(globalPeers, peer.namespace);
112
+ peers.delete(peer);
113
+ const details = { code, reason, wasClean };
114
+ await hooks.callHook("close", peer, details);
115
+ },
116
+ handleDurablePublish: async (_obj, topic, data, opts2) => {
117
+ return durablePublish(topic, data, opts2);
118
+ },
119
+ publish: async (topic, data, opts2) => {
120
+ const stub = await resolveDurableStub(void 0, env, void 0);
121
+ if (!stub) {
122
+ throw new Error("[crossws] Durable Object binding cannot be resolved.");
123
+ }
124
+ try {
125
+ return await stub.webSocketPublish(topic, data, opts2);
126
+ } catch (error) {
127
+ console.error(error);
128
+ throw error;
129
+ }
53
130
  }
54
131
  };
55
132
  };
56
- class CloudflarePeer extends Peer {
133
+ class CloudflareDurablePeer extends Peer {
134
+ get peers() {
135
+ return new Set(
136
+ this.#getwebsockets().map(
137
+ (ws) => CloudflareDurablePeer._restore(this._internal.durable, ws)
138
+ )
139
+ );
140
+ }
141
+ #getwebsockets() {
142
+ return this._internal.durable.ctx.getWebSockets();
143
+ }
144
+ send(data) {
145
+ return this._internal.ws.send(toBufferLike(data));
146
+ }
147
+ subscribe(topic) {
148
+ super.subscribe(topic);
149
+ const state = getAttachedState(this._internal.ws);
150
+ if (!state.t) {
151
+ state.t = /* @__PURE__ */ new Set();
152
+ }
153
+ state.t.add(topic);
154
+ setAttachedState(this._internal.ws, state);
155
+ }
156
+ publish(topic, data) {
157
+ const websockets = this.#getwebsockets();
158
+ if (websockets.length < 2) {
159
+ return;
160
+ }
161
+ const dataBuff = toBufferLike(data);
162
+ for (const ws of websockets) {
163
+ if (ws === this._internal.ws) {
164
+ continue;
165
+ }
166
+ const state = getAttachedState(ws);
167
+ if (state.t?.has(topic)) {
168
+ ws.send(dataBuff);
169
+ }
170
+ }
171
+ }
172
+ close(code, reason) {
173
+ this._internal.ws.close(code, reason);
174
+ }
175
+ static _restore(durable, ws, request, namespace) {
176
+ let peer = ws._crosswsPeer;
177
+ if (peer) {
178
+ return peer;
179
+ }
180
+ const state = ws.deserializeAttachment() || {};
181
+ peer = ws._crosswsPeer = new CloudflareDurablePeer({
182
+ ws,
183
+ request: request || new StubRequest(state.u || ""),
184
+ namespace: namespace || state.n || "",
185
+ durable
186
+ });
187
+ if (state.i) {
188
+ peer._id = state.i;
189
+ }
190
+ if (request?.url) {
191
+ state.u = request.url;
192
+ }
193
+ state.i = peer.id;
194
+ setAttachedState(ws, state);
195
+ return peer;
196
+ }
197
+ }
198
+ class CloudflareFallbackPeer extends Peer {
57
199
  send(data) {
58
200
  this._internal.wsServer.send(toBufferLike(data));
59
201
  return 0;
60
202
  }
61
203
  publish(_topic, _message) {
204
+ console.warn(
205
+ "[crossws] [cloudflare] pub/sub support requires Durable Objects."
206
+ );
62
207
  }
63
208
  close(code, reason) {
64
209
  this._internal.ws.close(code, reason);
65
210
  }
66
211
  }
212
+ function getAttachedState(ws) {
213
+ let state = ws._crosswsState;
214
+ if (state) {
215
+ return state;
216
+ }
217
+ state = ws.deserializeAttachment() || {};
218
+ ws._crosswsState = state;
219
+ return state;
220
+ }
221
+ function setAttachedState(ws, state) {
222
+ ws._crosswsState = state;
223
+ ws.serializeAttachment(state);
224
+ }
67
225
 
68
226
  export { cloudflareAdapter as default };
@@ -1,28 +1,37 @@
1
- import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DfCzGthR.mjs';
2
- import { a as adapterUtils, A as AdapterHookable } from '../shared/crossws.D9ehKjSh.mjs';
1
+ import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.WpyOHUXc.mjs';
2
+ import { a as adapterUtils, A as AdapterHookable, g as getPeers } from '../shared/crossws.CPlNx7g8.mjs';
3
3
  import { W as WSError } from '../shared/crossws.By9qWDAI.mjs';
4
- import 'uncrypto';
5
4
 
6
5
  const denoAdapter = (options = {}) => {
6
+ if (typeof Deno === "undefined") {
7
+ throw new Error(
8
+ "[crossws] Using Deno adapter in an incompatible environment."
9
+ );
10
+ }
7
11
  const hooks = new AdapterHookable(options);
8
- const peers = /* @__PURE__ */ new Set();
12
+ const globalPeers = /* @__PURE__ */ new Map();
9
13
  return {
10
- ...adapterUtils(peers),
14
+ ...adapterUtils(globalPeers),
11
15
  handleUpgrade: async (request, info) => {
12
- const { upgradeHeaders, endResponse, context } = await hooks.upgrade(request);
16
+ const { upgradeHeaders, endResponse, context, namespace } = await hooks.upgrade(request);
13
17
  if (endResponse) {
14
18
  return endResponse;
15
19
  }
20
+ const headers = upgradeHeaders instanceof Headers ? upgradeHeaders : new Headers(upgradeHeaders);
16
21
  const upgrade = Deno.upgradeWebSocket(request, {
17
- // @ts-expect-error https://github.com/denoland/deno/pull/22242
18
- headers: upgradeHeaders
22
+ // @ts-expect-error Setting headers is currently not supported in Deno
23
+ // https://github.com/denoland/deno/issues/19277
24
+ headers,
25
+ protocol: headers.get("sec-websocket-protocol") ?? ""
19
26
  });
27
+ const peers = getPeers(globalPeers, namespace);
20
28
  const peer = new DenoPeer({
21
29
  ws: upgrade.socket,
22
30
  request,
23
31
  peers,
24
32
  denoInfo: info,
25
- context
33
+ context,
34
+ namespace
26
35
  });
27
36
  peers.add(peer);
28
37
  upgrade.socket.addEventListener("open", () => {
@@ -286,7 +286,7 @@ type WebSocketServer = Server;
286
286
  declare function createWebSocketStream(websocket: WebSocket, options?: DuplexOptions): Duplex;
287
287
 
288
288
  interface NodeAdapter extends AdapterInstance {
289
- handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer): Promise<void>;
289
+ handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer, webRequest?: Request): Promise<void>;
290
290
  closeAll: (code?: number, data?: string | Buffer, force?: boolean) => void;
291
291
  }
292
292
  interface NodeOptions extends AdapterOptions {
@@ -1,8 +1,8 @@
1
- import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DfCzGthR.mjs';
2
- import { A as AdapterHookable, a as adapterUtils } from '../shared/crossws.D9ehKjSh.mjs';
1
+ import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.WpyOHUXc.mjs';
2
+ import { g as getPeers, A as AdapterHookable, a as adapterUtils } from '../shared/crossws.CPlNx7g8.mjs';
3
3
  import { W as WSError } from '../shared/crossws.By9qWDAI.mjs';
4
4
  import { _ as _WebSocketServer } from '../shared/crossws.CipVM6lf.mjs';
5
- import 'uncrypto';
5
+ import { S as StubRequest } from '../shared/crossws.B31KJMcF.mjs';
6
6
  import 'stream';
7
7
  import 'events';
8
8
  import 'http';
@@ -15,15 +15,28 @@ import 'tls';
15
15
  import 'url';
16
16
 
17
17
  const nodeAdapter = (options = {}) => {
18
+ if ("Deno" in globalThis || "Bun" in globalThis) {
19
+ throw new Error(
20
+ "[crossws] Using Node.js adapter in an incompatible environment."
21
+ );
22
+ }
18
23
  const hooks = new AdapterHookable(options);
19
- const peers = /* @__PURE__ */ new Set();
24
+ const globalPeers = /* @__PURE__ */ new Map();
20
25
  const wss = options.wss || new _WebSocketServer({
21
26
  noServer: true,
27
+ handleProtocols: () => false,
22
28
  ...options.serverOptions
23
29
  });
24
30
  wss.on("connection", (ws, nodeReq) => {
25
31
  const request = new NodeReqProxy(nodeReq);
26
- const peer = new NodePeer({ ws, request, peers, nodeReq });
32
+ const peers = getPeers(globalPeers, nodeReq._namespace);
33
+ const peer = new NodePeer({
34
+ ws,
35
+ request,
36
+ peers,
37
+ nodeReq,
38
+ namespace: nodeReq._namespace
39
+ });
27
40
  peers.add(peer);
28
41
  hooks.callHook("open", peer);
29
42
  ws.on("message", (data) => {
@@ -53,16 +66,17 @@ const nodeAdapter = (options = {}) => {
53
66
  }
54
67
  });
55
68
  return {
56
- ...adapterUtils(peers),
57
- handleUpgrade: async (nodeReq, socket, head) => {
58
- const request = new NodeReqProxy(nodeReq);
59
- const { upgradeHeaders, endResponse, context } = await hooks.upgrade(request);
69
+ ...adapterUtils(globalPeers),
70
+ handleUpgrade: async (nodeReq, socket, head, webRequest) => {
71
+ const request = webRequest || new NodeReqProxy(nodeReq);
72
+ const { upgradeHeaders, endResponse, context, namespace } = await hooks.upgrade(request);
60
73
  if (endResponse) {
61
74
  return sendResponse(socket, endResponse);
62
75
  }
63
76
  nodeReq._request = request;
64
77
  nodeReq._upgradeHeaders = upgradeHeaders;
65
78
  nodeReq._context = context;
79
+ nodeReq._namespace = namespace;
66
80
  wss.handleUpgrade(nodeReq, socket, head, (ws) => {
67
81
  wss.emit("connection", ws, nodeReq);
68
82
  });
@@ -116,27 +130,12 @@ class NodePeer extends Peer {
116
130
  this._internal.ws.terminate();
117
131
  }
118
132
  }
119
- class NodeReqProxy {
120
- _req;
121
- _headers;
122
- _url;
133
+ class NodeReqProxy extends StubRequest {
123
134
  constructor(req) {
124
- this._req = req;
125
- }
126
- get url() {
127
- if (!this._url) {
128
- const req = this._req;
129
- const host = req.headers["host"] || "localhost";
130
- const isSecure = req.socket?.encrypted ?? req.headers["x-forwarded-proto"] === "https";
131
- this._url = `${isSecure ? "https" : "http"}://${host}${req.url}`;
132
- }
133
- return this._url;
134
- }
135
- get headers() {
136
- if (!this._headers) {
137
- this._headers = new Headers(this._req.headers);
138
- }
139
- return this._headers;
135
+ const host = req.headers["host"] || "localhost";
136
+ const isSecure = req.socket?.encrypted ?? req.headers["x-forwarded-proto"] === "https";
137
+ const url = `${isSecure ? "https" : "http"}://${host}${req.url}`;
138
+ super(url, { headers: req.headers });
140
139
  }
141
140
  }
142
141
  async function sendResponse(socket, res) {
@@ -1,15 +1,14 @@
1
- import { M as Message, P as Peer, a as toString } from '../shared/crossws.DfCzGthR.mjs';
2
- import { a as adapterUtils, A as AdapterHookable } from '../shared/crossws.D9ehKjSh.mjs';
3
- import 'uncrypto';
1
+ import { M as Message, P as Peer, a as toString } from '../shared/crossws.WpyOHUXc.mjs';
2
+ import { a as adapterUtils, A as AdapterHookable, g as getPeers } from '../shared/crossws.CPlNx7g8.mjs';
4
3
 
5
4
  const sseAdapter = (opts = {}) => {
6
5
  const hooks = new AdapterHookable(opts);
7
- const peers = /* @__PURE__ */ new Set();
6
+ const globalPeers = /* @__PURE__ */ new Map();
8
7
  const peersMap = opts.bidir ? /* @__PURE__ */ new Map() : void 0;
9
8
  return {
10
- ...adapterUtils(peers),
9
+ ...adapterUtils(globalPeers),
11
10
  fetch: async (request) => {
12
- const { upgradeHeaders, endResponse, context } = await hooks.upgrade(request);
11
+ const { upgradeHeaders, endResponse, context, namespace } = await hooks.upgrade(request);
13
12
  if (endResponse) {
14
13
  return endResponse;
15
14
  }
@@ -32,13 +31,15 @@ const sseAdapter = (opts = {}) => {
32
31
  return new Response(null, {});
33
32
  } else {
34
33
  const ws = new SSEWebSocketStub();
34
+ const peers = getPeers(globalPeers, namespace);
35
35
  peer = new SSEPeer({
36
36
  peers,
37
37
  peersMap,
38
38
  request,
39
39
  hooks,
40
40
  ws,
41
- context
41
+ context,
42
+ namespace
42
43
  });
43
44
  peers.add(peer);
44
45
  if (opts.bidir) {
@@ -1,14 +1,20 @@
1
- import { Adapter, AdapterInstance, Peer, AdapterOptions } from '../index.mjs';
1
+ import { Adapter, AdapterInstance, Peer, PeerContext, AdapterOptions } from '../index.mjs';
2
2
  import { W as WebSocket } from '../shared/crossws.BQXMA5bH.mjs';
3
3
  import uws from 'uWebSockets.js';
4
4
 
5
+ declare const StubRequest: {
6
+ new (url: string, init?: RequestInit): Request;
7
+ };
8
+
5
9
  type UserData = {
6
10
  peer?: UWSPeer;
7
11
  req: uws.HttpRequest;
8
12
  res: uws.HttpResponse;
13
+ webReq: UWSReqProxy;
9
14
  protocol: string;
10
15
  extensions: string;
11
- context: Peer["context"];
16
+ context: PeerContext;
17
+ namespace: string;
12
18
  };
13
19
  type WebSocketHandler = uws.WebSocketBehavior<UserData>;
14
20
  interface UWSAdapter extends AdapterInstance {
@@ -22,12 +28,13 @@ declare const uwsAdapter: Adapter<UWSAdapter, UWSOptions>;
22
28
  declare class UWSPeer extends Peer<{
23
29
  peers: Set<UWSPeer>;
24
30
  request: UWSReqProxy;
31
+ namespace: string;
25
32
  uws: uws.WebSocket<UserData>;
26
33
  ws: UwsWebSocketProxy;
27
34
  uwsData: UserData;
28
35
  }> {
29
36
  get remoteAddress(): string | undefined;
30
- get context(): Record<string, unknown>;
37
+ get context(): PeerContext;
31
38
  send(data: unknown, options?: {
32
39
  compress?: boolean;
33
40
  }): number;
@@ -39,12 +46,8 @@ declare class UWSPeer extends Peer<{
39
46
  close(code?: number, reason?: uws.RecognizedString): void;
40
47
  terminate(): void;
41
48
  }
42
- declare class UWSReqProxy {
43
- private _headers?;
44
- private _rawHeaders;
45
- url: string;
46
- constructor(_req: uws.HttpRequest);
47
- get headers(): Headers;
49
+ declare class UWSReqProxy extends StubRequest {
50
+ constructor(req: uws.HttpRequest);
48
51
  }
49
52
  declare class UwsWebSocketProxy implements Partial<WebSocket> {
50
53
  private _uws;