crossws 0.2.4 → 0.3.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 (66) hide show
  1. package/README.md +8 -9
  2. package/adapters/cloudflare-durable.d.ts +2 -0
  3. package/adapters/sse.d.ts +2 -0
  4. package/dist/adapters/bun.d.mts +25 -6
  5. package/dist/adapters/bun.d.ts +25 -6
  6. package/dist/adapters/bun.mjs +54 -62
  7. package/dist/adapters/cloudflare-durable.d.mts +20 -0
  8. package/dist/adapters/cloudflare-durable.d.ts +20 -0
  9. package/dist/adapters/cloudflare-durable.mjs +132 -0
  10. package/dist/adapters/cloudflare.d.mts +5 -5
  11. package/dist/adapters/cloudflare.d.ts +5 -5
  12. package/dist/adapters/cloudflare.mjs +56 -49
  13. package/dist/adapters/deno.d.mts +10 -3
  14. package/dist/adapters/deno.d.ts +10 -3
  15. package/dist/adapters/deno.mjs +54 -45
  16. package/dist/adapters/node.d.mts +4 -2
  17. package/dist/adapters/node.d.ts +4 -2
  18. package/dist/adapters/node.mjs +106 -82
  19. package/dist/adapters/sse.d.mts +12 -0
  20. package/dist/adapters/sse.d.ts +12 -0
  21. package/dist/adapters/sse.mjs +120 -0
  22. package/dist/adapters/uws.d.mts +45 -9
  23. package/dist/adapters/uws.d.ts +45 -9
  24. package/dist/adapters/uws.mjs +148 -124
  25. package/dist/index.d.mts +136 -4
  26. package/dist/index.d.ts +136 -4
  27. package/dist/index.mjs +1 -10
  28. package/dist/shared/crossws.B4sHId41.mjs +42 -0
  29. package/dist/shared/crossws.By9qWDAI.mjs +8 -0
  30. package/dist/shared/crossws.ChIJSJVK.d.mts +297 -0
  31. package/dist/shared/crossws.ChIJSJVK.d.ts +297 -0
  32. package/dist/shared/crossws.DTY7a69w.mjs +315 -0
  33. package/dist/shared/{crossws.a5db571c.mjs → crossws.YgHWLi0G.mjs} +284 -115
  34. package/dist/websocket/{index.d.mts → native.d.mts} +1 -1
  35. package/dist/websocket/{node.d.cts → native.d.ts} +1 -1
  36. package/dist/websocket/native.mjs +3 -0
  37. package/dist/websocket/node.d.mts +1 -1
  38. package/dist/websocket/node.d.ts +1 -1
  39. package/dist/websocket/node.mjs +1 -1
  40. package/dist/websocket/sse.d.mts +41 -0
  41. package/dist/websocket/sse.d.ts +41 -0
  42. package/dist/websocket/sse.mjs +127 -0
  43. package/package.json +78 -75
  44. package/dist/adapters/bun.cjs +0 -95
  45. package/dist/adapters/bun.d.cts +0 -17
  46. package/dist/adapters/cloudflare.cjs +0 -65
  47. package/dist/adapters/cloudflare.d.cts +0 -12
  48. package/dist/adapters/deno.cjs +0 -63
  49. package/dist/adapters/deno.d.cts +0 -15
  50. package/dist/adapters/node.cjs +0 -739
  51. package/dist/adapters/node.d.cts +0 -298
  52. package/dist/adapters/uws.cjs +0 -153
  53. package/dist/adapters/uws.d.cts +0 -19
  54. package/dist/index.cjs +0 -17
  55. package/dist/index.d.cts +0 -6
  56. package/dist/shared/crossws.2ed26345.cjs +0 -3931
  57. package/dist/shared/crossws.36b9e66f.cjs +0 -156
  58. package/dist/shared/crossws.381454fe.d.cts +0 -115
  59. package/dist/shared/crossws.381454fe.d.mts +0 -115
  60. package/dist/shared/crossws.381454fe.d.ts +0 -115
  61. package/dist/shared/crossws.77e89680.mjs +0 -149
  62. package/dist/websocket/index.cjs +0 -5
  63. package/dist/websocket/index.d.cts +0 -10
  64. package/dist/websocket/index.d.ts +0 -10
  65. package/dist/websocket/index.mjs +0 -3
  66. package/dist/websocket/node.cjs +0 -17
@@ -1,60 +1,69 @@
1
- import { d as defineWebSocketAdapter, M as Message, P as Peer, t as toBufferLike, c as createCrossWS } from '../shared/crossws.77e89680.mjs';
2
- import { WSError } from '../index.mjs';
1
+ import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DTY7a69w.mjs';
2
+ import { d as defineWebSocketAdapter, a as adapterUtils, A as AdapterHookable } from '../shared/crossws.B4sHId41.mjs';
3
+ import { W as WSError } from '../shared/crossws.By9qWDAI.mjs';
4
+ import 'uncrypto';
3
5
 
4
6
  const deno = defineWebSocketAdapter(
5
7
  (options = {}) => {
6
- const crossws = createCrossWS(options);
7
- const handleUpgrade = async (req, info) => {
8
- const { headers } = await crossws.upgrade({
9
- url: req.url,
10
- headers: req.headers
11
- });
12
- const upgrade = Deno.upgradeWebSocket(req, {
13
- // @ts-expect-error https://github.com/denoland/deno/pull/22242
14
- headers
15
- });
16
- const peer = new DenoPeer({
17
- deno: { ws: upgrade.socket, req, info }
18
- });
19
- upgrade.socket.addEventListener("open", () => {
20
- crossws.$callHook("deno:open", peer);
21
- crossws.callHook("open", peer);
22
- });
23
- upgrade.socket.addEventListener("message", (event) => {
24
- crossws.$callHook("deno:message", peer, event);
25
- crossws.callHook("message", peer, new Message(event.data));
26
- });
27
- upgrade.socket.addEventListener("close", () => {
28
- crossws.$callHook("deno:close", peer);
29
- crossws.callHook("close", peer, {});
30
- });
31
- upgrade.socket.addEventListener("error", (error) => {
32
- crossws.$callHook("deno:error", peer, error);
33
- crossws.callHook("error", peer, new WSError(error));
34
- });
35
- return upgrade.response;
36
- };
8
+ const hooks = new AdapterHookable(options);
9
+ const peers = /* @__PURE__ */ new Set();
37
10
  return {
38
- handleUpgrade
11
+ ...adapterUtils(peers),
12
+ handleUpgrade: async (request, info) => {
13
+ const res = await hooks.callHook("upgrade", request);
14
+ if (res instanceof Response) {
15
+ return res;
16
+ }
17
+ const upgrade = Deno.upgradeWebSocket(request, {
18
+ // @ts-expect-error https://github.com/denoland/deno/pull/22242
19
+ headers: res?.headers
20
+ });
21
+ const peer = new DenoPeer({
22
+ ws: upgrade.socket,
23
+ request,
24
+ peers,
25
+ denoInfo: info
26
+ });
27
+ peers.add(peer);
28
+ upgrade.socket.addEventListener("open", () => {
29
+ hooks.callHook("open", peer);
30
+ });
31
+ upgrade.socket.addEventListener("message", (event) => {
32
+ hooks.callHook("message", peer, new Message(event.data, peer, event));
33
+ });
34
+ upgrade.socket.addEventListener("close", () => {
35
+ peers.delete(peer);
36
+ hooks.callHook("close", peer, {});
37
+ });
38
+ upgrade.socket.addEventListener("error", (error) => {
39
+ peers.delete(peer);
40
+ hooks.callHook("error", peer, new WSError(error));
41
+ });
42
+ return upgrade.response;
43
+ }
39
44
  };
40
45
  }
41
46
  );
42
47
  class DenoPeer extends Peer {
43
- get addr() {
44
- return this.ctx.deno.ws.remoteAddress;
48
+ get remoteAddress() {
49
+ return this._internal.denoInfo.remoteAddr?.hostname;
45
50
  }
46
- get readyState() {
47
- return this.ctx.deno.ws.readyState;
51
+ send(data) {
52
+ return this._internal.ws.send(toBufferLike(data));
48
53
  }
49
- get url() {
50
- return this.ctx.deno.req.url;
54
+ publish(topic, data) {
55
+ const dataBuff = toBufferLike(data);
56
+ for (const peer of this._internal.peers) {
57
+ if (peer !== this && peer._topics.has(topic)) {
58
+ peer._internal.ws.send(dataBuff);
59
+ }
60
+ }
51
61
  }
52
- get headers() {
53
- return this.ctx.deno.req.headers || new Headers();
62
+ close(code, reason) {
63
+ this._internal.ws.close(code, reason);
54
64
  }
55
- send(message) {
56
- this.ctx.deno.ws.send(toBufferLike(message));
57
- return 0;
65
+ terminate() {
66
+ this._internal.ws.terminate();
58
67
  }
59
68
  }
60
69
 
@@ -1,4 +1,4 @@
1
- import { A as AdapterOptions, b as Adapter } from '../shared/crossws.381454fe.mjs';
1
+ import { AdapterInstance, AdapterOptions, Adapter } from '../index.mjs';
2
2
  import { IncomingMessage as IncomingMessage$1 } from 'node:http';
3
3
  import { Duplex as Duplex$1 } from 'node:stream';
4
4
  import { EventEmitter } from 'events';
@@ -8,6 +8,7 @@ import { Duplex, DuplexOptions } from 'stream';
8
8
  import { SecureContextOptions } from 'tls';
9
9
  import { URL } from 'url';
10
10
  import { ZlibOptions } from 'zlib';
11
+ import '../shared/crossws.ChIJSJVK.mjs';
11
12
 
12
13
  type BufferLike = string | Buffer | DataView | number | ArrayBufferView | Uint8Array | ArrayBuffer | SharedArrayBuffer | readonly any[] | readonly number[] | {
13
14
  valueOf(): ArrayBuffer;
@@ -286,8 +287,9 @@ declare class Server<T extends typeof WebSocket = typeof WebSocket, U extends ty
286
287
  type WebSocketServer = Server;
287
288
  declare function createWebSocketStream(websocket: WebSocket, options?: DuplexOptions): Duplex;
288
289
 
289
- interface NodeAdapter {
290
+ interface NodeAdapter extends AdapterInstance {
290
291
  handleUpgrade(req: IncomingMessage$1, socket: Duplex$1, head: Buffer): void;
292
+ closeAll: (code?: number, data?: string | Buffer) => void;
291
293
  }
292
294
  interface NodeOptions extends AdapterOptions {
293
295
  wss?: WebSocketServer;
@@ -1,4 +1,4 @@
1
- import { A as AdapterOptions, b as Adapter } from '../shared/crossws.381454fe.js';
1
+ import { AdapterInstance, AdapterOptions, Adapter } from '../index.js';
2
2
  import { IncomingMessage as IncomingMessage$1 } from 'node:http';
3
3
  import { Duplex as Duplex$1 } from 'node:stream';
4
4
  import { EventEmitter } from 'events';
@@ -8,6 +8,7 @@ import { Duplex, DuplexOptions } from 'stream';
8
8
  import { SecureContextOptions } from 'tls';
9
9
  import { URL } from 'url';
10
10
  import { ZlibOptions } from 'zlib';
11
+ import '../shared/crossws.ChIJSJVK.js';
11
12
 
12
13
  type BufferLike = string | Buffer | DataView | number | ArrayBufferView | Uint8Array | ArrayBuffer | SharedArrayBuffer | readonly any[] | readonly number[] | {
13
14
  valueOf(): ArrayBuffer;
@@ -286,8 +287,9 @@ declare class Server<T extends typeof WebSocket = typeof WebSocket, U extends ty
286
287
  type WebSocketServer = Server;
287
288
  declare function createWebSocketStream(websocket: WebSocket, options?: DuplexOptions): Duplex;
288
289
 
289
- interface NodeAdapter {
290
+ interface NodeAdapter extends AdapterInstance {
290
291
  handleUpgrade(req: IncomingMessage$1, socket: Duplex$1, head: Buffer): void;
292
+ closeAll: (code?: number, data?: string | Buffer) => void;
291
293
  }
292
294
  interface NodeOptions extends AdapterOptions {
293
295
  wss?: WebSocketServer;
@@ -1,10 +1,12 @@
1
+ import { M as Message, P as Peer, t as toBufferLike } from '../shared/crossws.DTY7a69w.mjs';
2
+ import { d as defineWebSocketAdapter, a as adapterUtils, A as AdapterHookable } from '../shared/crossws.B4sHId41.mjs';
3
+ import { W as WSError } from '../shared/crossws.By9qWDAI.mjs';
1
4
  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';
5
+ import { v as validationExports, g as getDefaultExportFromCjs, e as extension$1, p as permessageDeflate, w as websocket, c as constants } from '../shared/crossws.YgHWLi0G.mjs';
3
6
  import require$$0 from 'events';
4
7
  import require$$2 from 'http';
5
8
  import require$$1 from 'crypto';
6
- import { d as defineWebSocketAdapter, M as Message, P as Peer, t as toBufferLike, c as createCrossWS } from '../shared/crossws.77e89680.mjs';
7
- import { WSError } from '../index.mjs';
9
+ import 'uncrypto';
8
10
  import 'https';
9
11
  import 'net';
10
12
  import 'tls';
@@ -73,7 +75,7 @@ function parse(header) {
73
75
 
74
76
  var subprotocol$1 = { parse };
75
77
 
76
- /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$" }] */
78
+ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$", "caughtErrors": "none" }] */
77
79
 
78
80
  const EventEmitter = require$$0;
79
81
  const http = require$$2;
@@ -101,7 +103,7 @@ class WebSocketServer extends EventEmitter {
101
103
  * Create a `WebSocketServer` instance.
102
104
  *
103
105
  * @param {Object} options Configuration options
104
- * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
106
+ * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
105
107
  * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
106
108
  * multiple times in the same tick
107
109
  * @param {Boolean} [options.autoPong=true] Specifies whether or not to
@@ -132,7 +134,7 @@ class WebSocketServer extends EventEmitter {
132
134
  super();
133
135
 
134
136
  options = {
135
- allowSynchronousEvents: false,
137
+ allowSynchronousEvents: true,
136
138
  autoPong: true,
137
139
  maxPayload: 100 * 1024 * 1024,
138
140
  skipUTF8Validation: false,
@@ -307,6 +309,7 @@ class WebSocketServer extends EventEmitter {
307
309
  socket.on('error', socketOnError);
308
310
 
309
311
  const key = req.headers['sec-websocket-key'];
312
+ const upgrade = req.headers.upgrade;
310
313
  const version = +req.headers['sec-websocket-version'];
311
314
 
312
315
  if (req.method !== 'GET') {
@@ -315,13 +318,13 @@ class WebSocketServer extends EventEmitter {
315
318
  return;
316
319
  }
317
320
 
318
- if (req.headers.upgrade.toLowerCase() !== 'websocket') {
321
+ if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
319
322
  const message = 'Invalid Upgrade header';
320
323
  abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
321
324
  return;
322
325
  }
323
326
 
324
- if (!key || !keyRegex.test(key)) {
327
+ if (key === undefined || !keyRegex.test(key)) {
325
328
  const message = 'Missing or invalid Sec-WebSocket-Key header';
326
329
  abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
327
330
  return;
@@ -614,118 +617,139 @@ const _WebSocketServer = /*@__PURE__*/getDefaultExportFromCjs(websocketServer);
614
617
 
615
618
  const node = defineWebSocketAdapter(
616
619
  (options = {}) => {
617
- const crossws = createCrossWS(options);
620
+ const hooks = new AdapterHookable(options);
621
+ const peers = /* @__PURE__ */ new Set();
618
622
  const wss = options.wss || new _WebSocketServer({
619
623
  noServer: true,
620
624
  ...options.serverOptions
621
625
  });
622
- wss.on("connection", (ws, req) => {
623
- const peer = new NodePeer({ node: { ws, req, server: wss } });
624
- crossws.callHook("open", peer);
625
- ws.on("message", (data, isBinary) => {
626
- crossws.$callHook("node:message", peer, data, isBinary);
626
+ wss.on("connection", (ws, nodeReq) => {
627
+ const request = new NodeReqProxy(nodeReq);
628
+ const peer = new NodePeer({ ws, request, peers, nodeReq });
629
+ peers.add(peer);
630
+ hooks.callHook("open", peer);
631
+ ws.on("message", (data) => {
627
632
  if (Array.isArray(data)) {
628
633
  data = Buffer.concat(data);
629
634
  }
630
- crossws.callHook("message", peer, new Message(data, isBinary));
635
+ hooks.callHook("message", peer, new Message(data, peer));
631
636
  });
632
637
  ws.on("error", (error) => {
633
- crossws.$callHook("node:error", peer, error);
634
- crossws.callHook("error", peer, new WSError(error));
638
+ peers.delete(peer);
639
+ hooks.callHook("error", peer, new WSError(error));
635
640
  });
636
641
  ws.on("close", (code, reason) => {
637
- crossws.$callHook("node:close", peer, code, reason);
638
- crossws.callHook("close", peer, {
642
+ peers.delete(peer);
643
+ hooks.callHook("close", peer, {
639
644
  code,
640
645
  reason: reason?.toString()
641
646
  });
642
647
  });
643
- ws.on("open", () => {
644
- crossws.$callHook("node:open", peer);
645
- });
646
- ws.on("ping", (data) => {
647
- crossws.$callHook("node:ping", peer, data);
648
- });
649
- ws.on("pong", (data) => {
650
- crossws.$callHook("node:pong", peer, data);
651
- });
652
- ws.on(
653
- "unexpected-response",
654
- (req2, res) => {
655
- crossws.$callHook("node:unexpected-response", peer, req2, res);
656
- }
657
- );
658
- ws.on("upgrade", (req2) => {
659
- crossws.$callHook("node:upgrade", peer, req2);
660
- });
661
648
  });
662
- wss.on("headers", function(outgoingHeaders, req) {
649
+ wss.on("headers", (outgoingHeaders, req) => {
663
650
  const upgradeHeaders = req._upgradeHeaders;
664
651
  if (upgradeHeaders) {
665
- const _headers = new Headers(upgradeHeaders);
666
- for (const [key, value] of _headers) {
652
+ for (const [key, value] of new Headers(upgradeHeaders)) {
667
653
  outgoingHeaders.push(`${key}: ${value}`);
668
654
  }
669
655
  }
670
656
  });
671
657
  return {
672
- handleUpgrade: async (req, socket, head) => {
673
- const { headers } = await crossws.upgrade({
674
- url: req.url || "",
675
- headers: req.headers
676
- });
677
- req._upgradeHeaders = headers;
678
- wss.handleUpgrade(req, socket, head, (ws) => {
679
- wss.emit("connection", ws, req);
658
+ ...adapterUtils(peers),
659
+ handleUpgrade: async (nodeReq, socket, head) => {
660
+ const request = new NodeReqProxy(nodeReq);
661
+ const res = await hooks.callHook("upgrade", request);
662
+ if (res instanceof Response) {
663
+ return sendResponse(socket, res);
664
+ }
665
+ nodeReq._request = request;
666
+ nodeReq._upgradeHeaders = res?.headers;
667
+ wss.handleUpgrade(nodeReq, socket, head, (ws) => {
668
+ wss.emit("connection", ws, nodeReq);
680
669
  });
670
+ },
671
+ closeAll: (code, data) => {
672
+ for (const client of wss.clients) {
673
+ client.close(code, data);
674
+ }
681
675
  }
682
676
  };
683
677
  }
684
678
  );
685
679
  class NodePeer extends Peer {
686
- constructor(ctx) {
687
- super(ctx);
688
- ctx.node.ws._peer = this;
689
- }
690
- get addr() {
691
- const socket = this.ctx.node.req.socket;
692
- if (!socket) {
693
- return void 0;
694
- }
695
- const headers = this.ctx.node.req.headers;
696
- let addr = headers["x-forwarded-for"] || socket.remoteAddress || "??";
697
- if (addr.includes(":")) {
698
- addr = `[${addr}]`;
699
- }
700
- const port = headers["x-forwarded-port"] || socket.remotePort || "??";
701
- return `${addr}:${port}`;
702
- }
703
- get url() {
704
- return this.ctx.node.req.url || "/";
705
- }
706
- get headers() {
707
- return this.ctx.node.req.headers;
708
- }
709
- get readyState() {
710
- return this.ctx.node.ws.readyState;
680
+ get remoteAddress() {
681
+ return this._internal.nodeReq.socket?.remoteAddress;
711
682
  }
712
- send(message, options) {
713
- this.ctx.node.ws.send(toBufferLike(message), {
683
+ send(data, options) {
684
+ const dataBuff = toBufferLike(data);
685
+ const isBinary = typeof data !== "string";
686
+ this._internal.ws.send(dataBuff, {
714
687
  compress: options?.compress,
715
- binary: options?.binary,
688
+ binary: isBinary,
716
689
  ...options
717
690
  });
718
691
  return 0;
719
692
  }
720
- publish(topic, message) {
721
- message = toBufferLike(message);
722
- for (const client of this.ctx.node.server.clients) {
723
- const peer = client._peer;
724
- if (peer && peer !== this && peer._subscriptions.has(topic)) {
725
- peer.send(message);
693
+ publish(topic, data, options) {
694
+ const dataBuff = toBufferLike(data);
695
+ const isBinary = typeof data !== "string";
696
+ const sendOptions = {
697
+ compress: options?.compress,
698
+ binary: isBinary,
699
+ ...options
700
+ };
701
+ for (const peer of this._internal.peers) {
702
+ if (peer !== this && peer._topics.has(topic)) {
703
+ peer._internal.ws.send(dataBuff, sendOptions);
726
704
  }
727
705
  }
728
706
  }
707
+ close(code, data) {
708
+ this._internal.ws.close(code, data);
709
+ }
710
+ terminate() {
711
+ this._internal.ws.terminate();
712
+ }
713
+ }
714
+ class NodeReqProxy {
715
+ _req;
716
+ _headers;
717
+ _url;
718
+ constructor(req) {
719
+ this._req = req;
720
+ }
721
+ get url() {
722
+ if (!this._url) {
723
+ const req = this._req;
724
+ const host = req.headers["host"] || "localhost";
725
+ const isSecure = req.socket?.encrypted ?? req.headers["x-forwarded-proto"] === "https";
726
+ this._url = `${isSecure ? "https" : "http"}://${host}${req.url}`;
727
+ }
728
+ return this._url;
729
+ }
730
+ get headers() {
731
+ if (!this._headers) {
732
+ this._headers = new Headers(this._req.headers);
733
+ }
734
+ return this._headers;
735
+ }
736
+ }
737
+ async function sendResponse(socket, res) {
738
+ const head = [
739
+ `HTTP/1.1 ${res.status || 200} ${res.statusText || ""}`,
740
+ ...[...res.headers.entries()].map(
741
+ ([key, value]) => `${encodeURIComponent(key)}: ${encodeURIComponent(value)}`
742
+ )
743
+ ];
744
+ socket.write(head.join("\r\n") + "\r\n\r\n");
745
+ if (res.body) {
746
+ for await (const chunk of res.body) {
747
+ socket.write(chunk);
748
+ }
749
+ }
750
+ return new Promise((resolve) => {
751
+ socket.end(resolve);
752
+ });
729
753
  }
730
754
 
731
755
  export { node as default };
@@ -0,0 +1,12 @@
1
+ import { AdapterInstance, AdapterOptions, Adapter } from '../index.mjs';
2
+ import '../shared/crossws.ChIJSJVK.mjs';
3
+
4
+ interface SSEAdapter extends AdapterInstance {
5
+ fetch(req: Request): Promise<Response>;
6
+ }
7
+ interface SSEOptions extends AdapterOptions {
8
+ bidir?: boolean;
9
+ }
10
+ declare const _default: Adapter<SSEAdapter, SSEOptions>;
11
+
12
+ export { type SSEAdapter, type SSEOptions, _default as default };
@@ -0,0 +1,12 @@
1
+ import { AdapterInstance, AdapterOptions, Adapter } from '../index.js';
2
+ import '../shared/crossws.ChIJSJVK.js';
3
+
4
+ interface SSEAdapter extends AdapterInstance {
5
+ fetch(req: Request): Promise<Response>;
6
+ }
7
+ interface SSEOptions extends AdapterOptions {
8
+ bidir?: boolean;
9
+ }
10
+ declare const _default: Adapter<SSEAdapter, SSEOptions>;
11
+
12
+ export { type SSEAdapter, type SSEOptions, _default as default };
@@ -0,0 +1,120 @@
1
+ import { M as Message, P as Peer, a as toString } from '../shared/crossws.DTY7a69w.mjs';
2
+ import { d as defineWebSocketAdapter, a as adapterUtils, A as AdapterHookable } from '../shared/crossws.B4sHId41.mjs';
3
+ import 'uncrypto';
4
+
5
+ const sse = defineWebSocketAdapter((opts = {}) => {
6
+ const hooks = new AdapterHookable(opts);
7
+ const peers = /* @__PURE__ */ new Set();
8
+ const peersMap = opts.bidir ? /* @__PURE__ */ new Map() : void 0;
9
+ return {
10
+ ...adapterUtils(peers),
11
+ fetch: async (request) => {
12
+ const _res = await hooks.callHook("upgrade", request);
13
+ if (_res instanceof Response) {
14
+ return _res;
15
+ }
16
+ let peer;
17
+ if (opts.bidir && request.body && request.headers.has("x-crossws-id")) {
18
+ const id = request.headers.get("x-crossws-id");
19
+ peer = peersMap?.get(id);
20
+ if (!peer) {
21
+ return new Response("invalid peer id", { status: 400 });
22
+ }
23
+ const stream = request.body.pipeThrough(new TextDecoderStream());
24
+ try {
25
+ for await (const chunk of stream) {
26
+ hooks.callHook("message", peer, new Message(chunk, peer));
27
+ }
28
+ } catch {
29
+ await stream.cancel().catch(() => {
30
+ });
31
+ }
32
+ return new Response(null, {});
33
+ } else {
34
+ const ws = new SSEWebSocketStub();
35
+ peer = new SSEPeer({
36
+ peers,
37
+ peersMap,
38
+ request,
39
+ hooks,
40
+ ws
41
+ });
42
+ peers.add(peer);
43
+ if (opts.bidir) {
44
+ peersMap.set(peer.id, peer);
45
+ peer._sendEvent("crossws-id", peer.id);
46
+ }
47
+ }
48
+ let headers = {
49
+ "Content-Type": "text/event-stream",
50
+ "Cache-Control": "no-cache",
51
+ Connection: "keep-alive"
52
+ };
53
+ if (opts.bidir) {
54
+ headers["x-crossws-id"] = peer.id;
55
+ }
56
+ if (_res?.headers) {
57
+ headers = new Headers(headers);
58
+ for (const [key, value] of new Headers(_res.headers)) {
59
+ headers.set(key, value);
60
+ }
61
+ }
62
+ return new Response(peer._sseStream, { ..._res, headers });
63
+ }
64
+ };
65
+ });
66
+ class SSEPeer extends Peer {
67
+ _sseStream;
68
+ // server -> client
69
+ _sseStreamController;
70
+ constructor(_internal) {
71
+ super(_internal);
72
+ _internal.ws.readyState = 0;
73
+ this._sseStream = new ReadableStream({
74
+ start: (controller) => {
75
+ _internal.ws.readyState = 1;
76
+ this._sseStreamController = controller;
77
+ _internal.hooks.callHook("open", this);
78
+ },
79
+ cancel: () => {
80
+ _internal.ws.readyState = 2;
81
+ _internal.peers.delete(this);
82
+ _internal.peersMap?.delete(this.id);
83
+ Promise.resolve(this._internal.hooks.callHook("close", this)).finally(
84
+ () => {
85
+ _internal.ws.readyState = 3;
86
+ }
87
+ );
88
+ }
89
+ }).pipeThrough(new TextEncoderStream());
90
+ }
91
+ _sendEvent(event, data) {
92
+ const lines = data.split("\n");
93
+ this._sseStreamController?.enqueue(
94
+ `event: ${event}
95
+ ${lines.map((l) => `data: ${l}`)}
96
+
97
+ `
98
+ );
99
+ }
100
+ send(data) {
101
+ this._sendEvent("message", toString(data));
102
+ return 0;
103
+ }
104
+ publish(topic, data) {
105
+ const dataBuff = toString(data);
106
+ for (const peer of this._internal.peers) {
107
+ if (peer !== this && peer._topics.has(topic)) {
108
+ peer._sendEvent("message", dataBuff);
109
+ }
110
+ }
111
+ }
112
+ close() {
113
+ this._sseStreamController?.close();
114
+ }
115
+ }
116
+ class SSEWebSocketStub {
117
+ readyState;
118
+ }
119
+
120
+ export { sse as default };
@@ -1,19 +1,55 @@
1
- import { A as AdapterOptions, b as Adapter } from '../shared/crossws.381454fe.mjs';
2
- import { WebSocketBehavior, HttpRequest, HttpResponse } from 'uWebSockets.js';
1
+ import { AdapterInstance, AdapterOptions, Adapter, Peer } from '../index.mjs';
2
+ import { W as WebSocket } from '../shared/crossws.ChIJSJVK.mjs';
3
+ import uws from 'uWebSockets.js';
3
4
 
4
5
  type UserData = {
5
- _peer?: any;
6
- req: HttpRequest;
7
- res: HttpResponse;
8
- context: any;
6
+ peer?: UWSPeer;
7
+ req: uws.HttpRequest;
8
+ res: uws.HttpResponse;
9
+ protocol: string;
10
+ extensions: string;
9
11
  };
10
- type WebSocketHandler = WebSocketBehavior<UserData>;
11
- interface UWSAdapter {
12
+ type WebSocketHandler = uws.WebSocketBehavior<UserData>;
13
+ interface UWSAdapter extends AdapterInstance {
12
14
  websocket: WebSocketHandler;
13
15
  }
14
16
  interface UWSOptions extends AdapterOptions {
15
- uws?: Exclude<WebSocketBehavior<any>, "close" | "drain" | "message" | "open" | "ping" | "pong" | "subscription" | "upgrade">;
17
+ uws?: Exclude<uws.WebSocketBehavior<any>, "close" | "drain" | "message" | "open" | "ping" | "pong" | "subscription" | "upgrade">;
16
18
  }
17
19
  declare const _default: Adapter<UWSAdapter, UWSOptions>;
18
20
 
21
+ declare class UWSPeer extends Peer<{
22
+ peers: Set<UWSPeer>;
23
+ request: UWSReqProxy;
24
+ uws: uws.WebSocket<UserData>;
25
+ ws: UwsWebSocketProxy;
26
+ uwsData: UserData;
27
+ }> {
28
+ get remoteAddress(): string | undefined;
29
+ send(data: unknown, options?: {
30
+ compress?: boolean;
31
+ }): number;
32
+ subscribe(topic: string): void;
33
+ publish(topic: string, message: string, options?: {
34
+ compress?: boolean;
35
+ }): number;
36
+ close(code?: number, reason?: uws.RecognizedString): void;
37
+ terminate(): void;
38
+ }
39
+ declare class UWSReqProxy {
40
+ private _headers?;
41
+ private _rawHeaders;
42
+ url: string;
43
+ constructor(_req: uws.HttpRequest);
44
+ get headers(): Headers;
45
+ }
46
+ declare class UwsWebSocketProxy implements Partial<WebSocket> {
47
+ private _uws;
48
+ readyState?: number;
49
+ constructor(_uws: uws.WebSocket<UserData>);
50
+ get bufferedAmount(): number;
51
+ get protocol(): string;
52
+ get extensions(): string;
53
+ }
54
+
19
55
  export { type UWSAdapter, type UWSOptions, _default as default };