crossws 0.4.3 → 0.4.5

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 (50) hide show
  1. package/adapters/bunny.d.ts +2 -0
  2. package/dist/THIRD-PARTY-LICENSES.md +33 -0
  3. package/dist/_chunks/_request.mjs +4 -6
  4. package/dist/_chunks/_types.d.mts +2 -3
  5. package/dist/_chunks/adapter.d.mts +45 -53
  6. package/dist/_chunks/adapter.mjs +6 -7
  7. package/dist/_chunks/bun.d.mts +0 -3
  8. package/dist/_chunks/bunny.d.mts +22 -0
  9. package/dist/_chunks/cloudflare.d.mts +16 -19
  10. package/dist/_chunks/deno.d.mts +0 -3
  11. package/dist/_chunks/error.mjs +1 -4
  12. package/dist/_chunks/libs/ws.mjs +77 -1179
  13. package/dist/_chunks/node.d.mts +43 -14
  14. package/dist/_chunks/node.mjs +129 -0
  15. package/dist/_chunks/peer.mjs +1 -59
  16. package/dist/_chunks/rolldown-runtime.mjs +7 -15
  17. package/dist/_chunks/sse.d.mts +0 -3
  18. package/dist/_chunks/web.d.mts +164 -166
  19. package/dist/adapters/bun.mjs +1 -6
  20. package/dist/adapters/bunny.d.mts +2 -0
  21. package/dist/adapters/bunny.mjs +68 -0
  22. package/dist/adapters/cloudflare.mjs +7 -12
  23. package/dist/adapters/deno.mjs +1 -6
  24. package/dist/adapters/node.d.mts +2 -2
  25. package/dist/adapters/node.mjs +2 -125
  26. package/dist/adapters/sse.mjs +1 -6
  27. package/dist/adapters/uws.d.mts +0 -5
  28. package/dist/adapters/uws.mjs +2 -7
  29. package/dist/index.d.mts +81 -1
  30. package/dist/index.mjs +161 -2
  31. package/dist/server/bun.d.mts +0 -6
  32. package/dist/server/bun.mjs +3 -7
  33. package/dist/server/bunny.d.mts +5 -0
  34. package/dist/server/bunny.mjs +23 -0
  35. package/dist/server/cloudflare.d.mts +0 -6
  36. package/dist/server/cloudflare.mjs +3 -7
  37. package/dist/server/default.d.mts +0 -6
  38. package/dist/server/default.mjs +3 -7
  39. package/dist/server/deno.d.mts +0 -6
  40. package/dist/server/deno.mjs +3 -7
  41. package/dist/server/node.d.mts +0 -6
  42. package/dist/server/node.mjs +3 -9
  43. package/dist/websocket/native.d.mts +0 -2
  44. package/dist/websocket/native.mjs +1 -5
  45. package/dist/websocket/node.d.mts +0 -2
  46. package/dist/websocket/node.mjs +1 -7
  47. package/dist/websocket/sse.d.mts +0 -3
  48. package/dist/websocket/sse.mjs +1 -4
  49. package/package.json +42 -40
  50. package/server/bunny.d.ts +2 -0
@@ -1,4 +1,4 @@
1
- import { n as AdapterInstance, r as AdapterOptions, t as Adapter } from "./adapter.mjs";
1
+ import { a as Hooks, n as AdapterInstance, r as AdapterOptions, t as Adapter } from "./adapter.mjs";
2
2
  import { EventEmitter } from "events";
3
3
  import { Agent, ClientRequest, ClientRequestArgs, IncomingMessage, OutgoingHttpHeaders, Server } from "node:http";
4
4
  import { Duplex, DuplexOptions } from "node:stream";
@@ -6,8 +6,6 @@ import { Server as Server$1 } from "node:https";
6
6
  import { SecureContextOptions } from "node:tls";
7
7
  import { URL } from "node:url";
8
8
  import { ZlibOptions } from "node:zlib";
9
-
10
- //#region types/ws.d.ts
11
9
  type BufferLike = string | Buffer | DataView | number | ArrayBufferView | Uint8Array | ArrayBuffer | SharedArrayBuffer | readonly any[] | readonly number[] | {
12
10
  valueOf(): ArrayBuffer;
13
11
  } | {
@@ -70,15 +68,15 @@ declare class WebSocket extends EventEmitter {
70
68
  }, cb?: (err?: Error) => void): void;
71
69
  terminate(): void;
72
70
  /**
73
- * Pause the websocket causing it to stop emitting events. Some events can still be
74
- * emitted after this is called, until all buffered data is consumed. This method
75
- * is a noop if the ready state is `CONNECTING` or `CLOSED`.
76
- */
71
+ * Pause the websocket causing it to stop emitting events. Some events can still be
72
+ * emitted after this is called, until all buffered data is consumed. This method
73
+ * is a noop if the ready state is `CONNECTING` or `CLOSED`.
74
+ */
77
75
  pause(): void;
78
76
  /**
79
- * Make a paused socket resume emitting events. This method is a noop if the ready
80
- * state is `CONNECTING` or `CLOSED`.
81
- */
77
+ * Make a paused socket resume emitting events. This method is a noop if the ready
78
+ * state is `CONNECTING` or `CLOSED`.
79
+ */
82
80
  resume(): void;
83
81
  addEventListener(method: "message", cb: (event: MessageEvent) => void, options?: EventListenerOptions): void;
84
82
  addEventListener(method: "close", cb: (event: CloseEvent) => void, options?: EventListenerOptions): void;
@@ -284,8 +282,40 @@ declare class Server$2<T extends typeof WebSocket = typeof WebSocket, U extends
284
282
  }
285
283
  type WebSocketServer = Server$2;
286
284
  declare function createWebSocketStream(websocket: WebSocket, options?: DuplexOptions): Duplex;
287
- //#endregion
288
- //#region src/adapters/node.d.ts
285
+ /**
286
+ * A Node.js `(req, socket, head)` upgrade handler.
287
+ */
288
+ type NodeUpgradeHandler = (req: IncomingMessage, socket: Duplex, head: Buffer) => void | Promise<void>;
289
+ /**
290
+ * Wrap a Node.js `(req, socket, head)` upgrade handler as a {@link Hooks}
291
+ * object that can be mounted via `crossws/server/node`.
292
+ *
293
+ * The wrapped handler takes ownership of the socket; crossws's other
294
+ * lifecycle hooks (`open`/`message`/`close`/`error`) are **not** invoked
295
+ * for connections routed through it.
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * import { WebSocketServer } from "ws";
300
+ * import { fromNodeUpgradeHandler } from "crossws/adapters/node";
301
+ * import { serve } from "crossws/server/node";
302
+ *
303
+ * const wss = new WebSocketServer({ noServer: true });
304
+ * wss.on("connection", (ws) => {
305
+ * ws.on("message", (data) => ws.send(data));
306
+ * });
307
+ *
308
+ * serve({
309
+ * websocket: fromNodeUpgradeHandler((req, socket, head) => {
310
+ * wss.handleUpgrade(req, socket, head, (ws) => {
311
+ * wss.emit("connection", ws, req);
312
+ * });
313
+ * }),
314
+ * fetch: () => new Response("ok"),
315
+ * });
316
+ * ```
317
+ */
318
+ declare function fromNodeUpgradeHandler(handler: NodeUpgradeHandler): Partial<Hooks>;
289
319
  interface NodeAdapter extends AdapterInstance {
290
320
  handleUpgrade(req: IncomingMessage, socket: Duplex, head: Buffer, webRequest?: Request): Promise<void>;
291
321
  closeAll: (code?: number, data?: string | Buffer, force?: boolean) => void;
@@ -295,5 +325,4 @@ interface NodeOptions extends AdapterOptions {
295
325
  serverOptions?: ServerOptions;
296
326
  }
297
327
  declare const nodeAdapter: Adapter<NodeAdapter, NodeOptions>;
298
- //#endregion
299
- export { NodeOptions as n, nodeAdapter as r, NodeAdapter as t };
328
+ export { fromNodeUpgradeHandler as a, NodeUpgradeHandler as i, NodeOptions as n, nodeAdapter as r, NodeAdapter as t };
@@ -0,0 +1,129 @@
1
+ import { i as AdapterHookable, r as getPeers, t as adapterUtils } from "./adapter.mjs";
2
+ import { n as import_websocket_server } from "./libs/ws.mjs";
3
+ import { n as Message, r as toBufferLike, t as Peer } from "./peer.mjs";
4
+ import { t as WSError } from "./error.mjs";
5
+ import { t as StubRequest } from "./_request.mjs";
6
+ function fromNodeUpgradeHandler(handler) {
7
+ return { async upgrade(request) {
8
+ const node = request.runtime?.node;
9
+ if (!node?.upgrade) throw new Error("[crossws] `fromNodeUpgradeHandler` must be mounted via `crossws/server/node`.");
10
+ await handler(node.req, node.upgrade.socket, node.upgrade.head);
11
+ return { handled: true };
12
+ } };
13
+ }
14
+ const nodeAdapter = (options = {}) => {
15
+ if ("Deno" in globalThis || "Bun" in globalThis) throw new Error("[crossws] Using Node.js adapter in an incompatible environment.");
16
+ const hooks = new AdapterHookable(options);
17
+ const globalPeers = /* @__PURE__ */ new Map();
18
+ const wss = options.wss || new import_websocket_server.default({
19
+ noServer: true,
20
+ handleProtocols: () => false,
21
+ ...options.serverOptions
22
+ });
23
+ wss.on("connection", (ws, nodeReq) => {
24
+ const request = new NodeReqProxy(nodeReq);
25
+ const peers = getPeers(globalPeers, nodeReq._namespace);
26
+ const peer = new NodePeer({
27
+ ws,
28
+ request,
29
+ peers,
30
+ nodeReq,
31
+ namespace: nodeReq._namespace
32
+ });
33
+ peers.add(peer);
34
+ hooks.callHook("open", peer);
35
+ ws.on("message", (data, isBinary) => {
36
+ if (Array.isArray(data)) data = Buffer.concat(data);
37
+ if (!isBinary && Buffer.isBuffer(data)) data = data.toString("utf8");
38
+ hooks.callHook("message", peer, new Message(data, peer));
39
+ });
40
+ ws.on("error", (error) => {
41
+ peers.delete(peer);
42
+ hooks.callHook("error", peer, new WSError(error));
43
+ });
44
+ ws.on("close", (code, reason) => {
45
+ peers.delete(peer);
46
+ hooks.callHook("close", peer, {
47
+ code,
48
+ reason: reason?.toString()
49
+ });
50
+ });
51
+ });
52
+ wss.on("headers", (outgoingHeaders, req) => {
53
+ const upgradeHeaders = req._upgradeHeaders;
54
+ if (upgradeHeaders) for (const [key, value] of new Headers(upgradeHeaders)) outgoingHeaders.push(`${key}: ${value}`);
55
+ });
56
+ return {
57
+ ...adapterUtils(globalPeers),
58
+ handleUpgrade: async (nodeReq, socket, head, webRequest) => {
59
+ const request = webRequest || new NodeReqProxy(nodeReq);
60
+ const { upgradeHeaders, endResponse, handled, context, namespace } = await hooks.upgrade(request);
61
+ if (endResponse) return sendResponse(socket, endResponse);
62
+ if (handled) return;
63
+ nodeReq._request = request;
64
+ nodeReq._upgradeHeaders = upgradeHeaders;
65
+ nodeReq._context = context;
66
+ nodeReq._namespace = namespace;
67
+ wss.handleUpgrade(nodeReq, socket, head, (ws) => {
68
+ wss.emit("connection", ws, nodeReq);
69
+ });
70
+ },
71
+ closeAll: (code, data, force) => {
72
+ for (const client of wss.clients) if (force) client.terminate();
73
+ else client.close(code, data);
74
+ }
75
+ };
76
+ };
77
+ var NodePeer = class extends Peer {
78
+ get remoteAddress() {
79
+ return this._internal.nodeReq.socket?.remoteAddress;
80
+ }
81
+ get context() {
82
+ return this._internal.nodeReq._context;
83
+ }
84
+ send(data, options) {
85
+ const dataBuff = toBufferLike(data);
86
+ const isBinary = typeof dataBuff !== "string";
87
+ this._internal.ws.send(dataBuff, {
88
+ compress: options?.compress,
89
+ binary: isBinary,
90
+ ...options
91
+ });
92
+ return 0;
93
+ }
94
+ publish(topic, data, options) {
95
+ const dataBuff = toBufferLike(data);
96
+ const isBinary = typeof data !== "string";
97
+ const sendOptions = {
98
+ compress: options?.compress,
99
+ binary: isBinary,
100
+ ...options
101
+ };
102
+ for (const peer of this._internal.peers) if (peer !== this && peer._topics.has(topic)) peer._internal.ws.send(dataBuff, sendOptions);
103
+ }
104
+ close(code, data) {
105
+ this._internal.ws.close(code, data);
106
+ }
107
+ terminate() {
108
+ this._internal.ws.terminate();
109
+ }
110
+ };
111
+ var NodeReqProxy = class extends StubRequest {
112
+ constructor(req) {
113
+ const host = req.headers["host"] || "localhost";
114
+ const url = `${req.socket?.encrypted ?? req.headers["x-forwarded-proto"] === "https" ? "https" : "http"}://${host}${req.url}`;
115
+ super(url, { headers: req.headers });
116
+ }
117
+ };
118
+ async function sendResponse(socket, res) {
119
+ const head = [`HTTP/1.1 ${res.status || 200} ${res.statusText || ""}`, ...[...res.headers.entries()].map(([key, value]) => `${key}: ${value}`)];
120
+ socket.write(head.join("\r\n") + "\r\n\r\n");
121
+ if (res.body) for await (const chunk of res.body) socket.write(chunk);
122
+ return new Promise((resolve) => {
123
+ socket.end(() => {
124
+ socket.destroy();
125
+ resolve();
126
+ });
127
+ });
128
+ }
129
+ export { fromNodeUpgradeHandler as n, nodeAdapter as t };
@@ -1,4 +1,3 @@
1
- //#region src/utils.ts
2
1
  const kNodeInspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
3
2
  function toBufferLike(val) {
4
3
  if (val === void 0 || val === null) return "";
@@ -24,15 +23,9 @@ function isPlainObject(value) {
24
23
  if (Symbol.toStringTag in value) return Object.prototype.toString.call(value) === "[object Module]";
25
24
  return true;
26
25
  }
27
-
28
- //#endregion
29
- //#region src/message.ts
30
26
  var Message = class {
31
- /** Access to the original [message event](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/message_event) if available. */
32
27
  event;
33
- /** Access to the Peer that emitted the message. */
34
28
  peer;
35
- /** Raw message data (can be of any type). */
36
29
  rawData;
37
30
  #id;
38
31
  #uint8Array;
@@ -45,18 +38,10 @@ var Message = class {
45
38
  this.peer = peer;
46
39
  this.event = event;
47
40
  }
48
- /**
49
- * Unique random [uuid v4](https://developer.mozilla.org/en-US/docs/Glossary/UUID) identifier for the message.
50
- */
51
41
  get id() {
52
42
  if (!this.#id) this.#id = crypto.randomUUID();
53
43
  return this.#id;
54
44
  }
55
- /**
56
- * Get data as [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) value.
57
- *
58
- * If raw data is in any other format or string, it will be automatically converted and encoded.
59
- */
60
45
  uint8Array() {
61
46
  const _uint8Array = this.#uint8Array;
62
47
  if (_uint8Array) return _uint8Array;
@@ -75,11 +60,6 @@ var Message = class {
75
60
  if (rawData instanceof DataView) return this.#uint8Array = new Uint8Array(rawData.buffer, rawData.byteOffset, rawData.byteLength);
76
61
  throw new TypeError(`Unsupported message type: ${Object.prototype.toString.call(rawData)}`);
77
62
  }
78
- /**
79
- * Get data as [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) or [SharedArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) value.
80
- *
81
- * If raw data is in any other format or string, it will be automatically converted and encoded.
82
- */
83
63
  arrayBuffer() {
84
64
  const _arrayBuffer = this.#arrayBuffer;
85
65
  if (_arrayBuffer) return _arrayBuffer;
@@ -87,10 +67,6 @@ var Message = class {
87
67
  if (rawData instanceof ArrayBuffer || rawData instanceof SharedArrayBuffer) return this.#arrayBuffer = rawData;
88
68
  return this.#arrayBuffer = this.uint8Array().buffer;
89
69
  }
90
- /**
91
- * Get data as [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) value.
92
- *
93
- * If raw data is in any other format or string, it will be automatically converted and encoded. */
94
70
  blob() {
95
71
  const _blob = this.#blob;
96
72
  if (_blob) return _blob;
@@ -98,11 +74,6 @@ var Message = class {
98
74
  if (rawData instanceof Blob) return this.#blob = rawData;
99
75
  return this.#blob = new Blob([this.uint8Array()]);
100
76
  }
101
- /**
102
- * Get stringified text version of the message.
103
- *
104
- * If raw data is in any other format, it will be automatically converted and decoded.
105
- */
106
77
  text() {
107
78
  const _text = this.#text;
108
79
  if (_text) return _text;
@@ -110,17 +81,11 @@ var Message = class {
110
81
  if (typeof rawData === "string") return this.#text = rawData;
111
82
  return this.#text = new TextDecoder().decode(this.uint8Array());
112
83
  }
113
- /**
114
- * Get parsed version of the message text with [`JSON.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse).
115
- */
116
84
  json() {
117
85
  const _json = this.#json;
118
86
  if (_json) return _json;
119
87
  return this.#json = JSON.parse(this.text());
120
88
  }
121
- /**
122
- * Message data (value varies based on `peer.websocket.binaryType`).
123
- */
124
89
  get data() {
125
90
  switch (this.peer?.websocket?.binaryType) {
126
91
  case "arraybuffer": return this.arrayBuffer();
@@ -145,9 +110,6 @@ var Message = class {
145
110
  } };
146
111
  }
147
112
  };
148
-
149
- //#endregion
150
- //#region src/peer.ts
151
113
  var Peer = class {
152
114
  _internal;
153
115
  _topics;
@@ -163,27 +125,14 @@ var Peer = class {
163
125
  get namespace() {
164
126
  return this._internal.namespace;
165
127
  }
166
- /**
167
- * Unique random [uuid v4](https://developer.mozilla.org/en-US/docs/Glossary/UUID) identifier for the peer.
168
- */
169
128
  get id() {
170
129
  if (!this._id) this._id = crypto.randomUUID();
171
130
  return this._id;
172
131
  }
173
- /** IP address of the peer */
174
132
  get remoteAddress() {}
175
- /** upgrade request */
176
133
  get request() {
177
134
  return this._internal.request;
178
135
  }
179
- /**
180
- * Get the [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) instance.
181
- *
182
- * **Note:** crossws adds polyfill for the following properties if native values are not available:
183
- * - `protocol`: Extracted from the `sec-websocket-protocol` header.
184
- * - `extensions`: Extracted from the `sec-websocket-extensions` header.
185
- * - `url`: Extracted from the request URL (http -> ws).
186
- * */
187
136
  get websocket() {
188
137
  if (!this.#ws) {
189
138
  const _ws = this._internal.ws;
@@ -192,23 +141,18 @@ var Peer = class {
192
141
  }
193
142
  return this.#ws;
194
143
  }
195
- /** All connected peers to the server */
196
144
  get peers() {
197
145
  return this._internal.peers || /* @__PURE__ */ new Set();
198
146
  }
199
- /** All topics, this peer has been subscribed to. */
200
147
  get topics() {
201
148
  return this._topics;
202
149
  }
203
- /** Abruptly close the connection */
204
150
  terminate() {
205
151
  this.close();
206
152
  }
207
- /** Subscribe to a topic */
208
153
  subscribe(topic) {
209
154
  this._topics.add(topic);
210
155
  }
211
- /** Unsubscribe from a topic */
212
156
  unsubscribe(topic) {
213
157
  this._topics.delete(topic);
214
158
  }
@@ -239,6 +183,4 @@ function createWsProxy(ws, request) {
239
183
  return value;
240
184
  } });
241
185
  }
242
-
243
- //#endregion
244
- export { toString as i, Message as n, toBufferLike as r, Peer as t };
186
+ export { toString as i, Message as n, toBufferLike as r, Peer as t };
@@ -1,6 +1,4 @@
1
1
  import { createRequire } from "node:module";
2
-
3
- //#region rolldown:runtime
4
2
  var __create = Object.create;
5
3
  var __defProp = Object.defineProperty;
6
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -9,16 +7,12 @@ var __getProtoOf = Object.getPrototypeOf;
9
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
10
8
  var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
11
9
  var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
- key = keys[i];
15
- if (!__hasOwnProp.call(to, key) && key !== except) {
16
- __defProp(to, key, {
17
- get: ((k) => from[k]).bind(null, key),
18
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
- });
20
- }
21
- }
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
22
16
  }
23
17
  return to;
24
18
  };
@@ -27,6 +21,4 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
21
  enumerable: true
28
22
  }) : target, mod));
29
23
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
30
-
31
- //#endregion
32
- export { __require as n, __toESM as r, __commonJSMin as t };
24
+ export { __require as n, __toESM as r, __commonJSMin as t };
@@ -1,6 +1,4 @@
1
1
  import { n as AdapterInstance, r as AdapterOptions, t as Adapter } from "./adapter.mjs";
2
-
3
- //#region src/adapters/sse.d.ts
4
2
  interface SSEAdapter extends AdapterInstance {
5
3
  fetch(req: Request): Promise<Response>;
6
4
  }
@@ -8,5 +6,4 @@ interface SSEOptions extends AdapterOptions {
8
6
  bidir?: boolean;
9
7
  }
10
8
  declare const sseAdapter: Adapter<SSEAdapter, SSEOptions>;
11
- //#endregion
12
9
  export { SSEOptions as n, sseAdapter as r, SSEAdapter as t };