crossws 0.4.5 → 0.4.7
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.
- package/adapters/vercel.d.ts +2 -0
- package/dist/THIRD-PARTY-LICENSES.md +1 -1
- package/dist/_chunks/_request.mjs +2 -2
- package/dist/_chunks/_types.d.mts +8 -8
- package/dist/_chunks/adapter.d.mts +458 -4
- package/dist/_chunks/adapter.mjs +90 -13
- package/dist/_chunks/bun.d.mts +5 -3
- package/dist/_chunks/bunny.d.mts +2 -2
- package/dist/_chunks/cloudflare.d.mts +3 -3
- package/dist/_chunks/deno.d.mts +2 -2
- package/dist/_chunks/error.mjs +1 -1
- package/dist/_chunks/libs/ws.mjs +53 -4
- package/dist/_chunks/node.d.mts +2 -2
- package/dist/_chunks/node.mjs +17 -11
- package/dist/_chunks/peer.mjs +38 -26
- package/dist/_chunks/sse.d.mts +2 -2
- package/dist/_chunks/web.d.mts +1 -1
- package/dist/adapters/bun.d.mts +1 -1
- package/dist/adapters/bun.mjs +18 -9
- package/dist/adapters/bunny.d.mts +1 -1
- package/dist/adapters/bunny.mjs +8 -6
- package/dist/adapters/cloudflare.d.mts +1 -1
- package/dist/adapters/cloudflare.mjs +16 -13
- package/dist/adapters/deno.d.mts +1 -1
- package/dist/adapters/deno.mjs +22 -9
- package/dist/adapters/node.d.mts +2 -2
- package/dist/adapters/node.mjs +1 -1
- package/dist/adapters/sse.d.mts +1 -1
- package/dist/adapters/sse.mjs +7 -5
- package/dist/adapters/uws.d.mts +5 -4
- package/dist/adapters/uws.mjs +17 -10
- package/dist/adapters/vercel.d.mts +25 -0
- package/dist/adapters/vercel.mjs +48 -0
- package/dist/index.d.mts +30 -7
- package/dist/index.mjs +78 -35
- package/dist/server/bun.d.mts +1 -1
- package/dist/server/bunny.d.mts +1 -1
- package/dist/server/cloudflare.d.mts +1 -1
- package/dist/server/default.d.mts +1 -1
- package/dist/server/deno.d.mts +1 -1
- package/dist/server/node.d.mts +1 -1
- package/dist/server/node.mjs +1 -1
- package/dist/sync.d.mts +2 -0
- package/dist/sync.mjs +200 -0
- package/dist/websocket/node.mjs +1 -1
- package/dist/websocket/sse.d.mts +1 -1
- package/package.json +23 -35
- package/sync.d.ts +2 -0
- package/dist/_chunks/rolldown-runtime.mjs +0 -24
package/dist/_chunks/bun.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Adapter, AdapterInstance, AdapterOptions, Peer, PeerContext, SyncDriver } from "./adapter.mjs";
|
|
2
2
|
import { Server, ServerWebSocket, WebSocketHandler } from "bun";
|
|
3
3
|
interface BunAdapter extends AdapterInstance {
|
|
4
4
|
websocket: WebSocketHandler<ContextData>;
|
|
@@ -18,13 +18,15 @@ declare class BunPeer extends Peer<{
|
|
|
18
18
|
namespace: string;
|
|
19
19
|
request: Request;
|
|
20
20
|
peers: Set<BunPeer>;
|
|
21
|
+
sync?: SyncDriver;
|
|
21
22
|
}> {
|
|
22
23
|
get remoteAddress(): string;
|
|
23
24
|
get context(): PeerContext;
|
|
25
|
+
get bufferedAmount(): number;
|
|
24
26
|
send(data: unknown, options?: {
|
|
25
27
|
compress?: boolean;
|
|
26
28
|
}): number;
|
|
27
|
-
|
|
29
|
+
_publish(topic: string, data: unknown, options?: {
|
|
28
30
|
compress?: boolean;
|
|
29
31
|
}): number;
|
|
30
32
|
subscribe(topic: string): void;
|
|
@@ -32,4 +34,4 @@ declare class BunPeer extends Peer<{
|
|
|
32
34
|
close(code?: number, reason?: string): void;
|
|
33
35
|
terminate(): void;
|
|
34
36
|
}
|
|
35
|
-
export { BunOptions
|
|
37
|
+
export { BunAdapter, BunOptions, bunAdapter };
|
package/dist/_chunks/bunny.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Adapter, AdapterInstance, AdapterOptions } from "./adapter.mjs";
|
|
2
2
|
interface BunnyAdapter extends AdapterInstance {
|
|
3
3
|
handleUpgrade(req: Request): Promise<Response>;
|
|
4
4
|
}
|
|
@@ -19,4 +19,4 @@ interface BunnyOptions extends AdapterOptions {
|
|
|
19
19
|
idleTimeout?: number;
|
|
20
20
|
}
|
|
21
21
|
declare const bunnyAdapter: Adapter<BunnyAdapter, BunnyOptions>;
|
|
22
|
-
export { BunnyOptions
|
|
22
|
+
export { BunnyAdapter, BunnyOptions, bunnyAdapter };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Adapter, AdapterInstance, AdapterOptions } from "./adapter.mjs";
|
|
2
|
+
import { WebSocket as WebSocket$1 } from "./web.mjs";
|
|
3
3
|
import { DurableObject } from "cloudflare:workers";
|
|
4
4
|
import * as CF from "@cloudflare/workers-types";
|
|
5
5
|
type WSDurableObjectStub = CF.DurableObjectStub & {
|
|
@@ -39,4 +39,4 @@ interface CloudflareDurableAdapter extends AdapterInstance {
|
|
|
39
39
|
handleDurablePublish: (obj: DurableObject, topic: string, data: unknown, opts: any) => Promise<void>;
|
|
40
40
|
handleDurableClose(obj: DurableObject, ws: WebSocket | CF.WebSocket | WebSocket$1, code: number, reason: string, wasClean: boolean): Promise<void>;
|
|
41
41
|
}
|
|
42
|
-
export { CloudflareOptions
|
|
42
|
+
export { CloudflareDurableAdapter, CloudflareOptions, cloudflareAdapter };
|
package/dist/_chunks/deno.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Adapter, AdapterInstance, AdapterOptions } from "./adapter.mjs";
|
|
2
2
|
interface DenoAdapter extends AdapterInstance {
|
|
3
3
|
handleUpgrade(req: Request, info: ServeHandlerInfo): Promise<Response>;
|
|
4
4
|
}
|
|
@@ -11,4 +11,4 @@ type ServeHandlerInfo = {
|
|
|
11
11
|
};
|
|
12
12
|
};
|
|
13
13
|
declare const denoAdapter: Adapter<DenoAdapter, DenoOptions>;
|
|
14
|
-
export { DenoOptions
|
|
14
|
+
export { DenoAdapter, DenoOptions, denoAdapter };
|
package/dist/_chunks/error.mjs
CHANGED
package/dist/_chunks/libs/ws.mjs
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
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
|
+
});
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
value: mod,
|
|
21
|
+
enumerable: true
|
|
22
|
+
}) : target, mod));
|
|
23
|
+
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
2
24
|
var require_constants = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
3
25
|
const BINARY_TYPES = [
|
|
4
26
|
"nodebuffer",
|
|
@@ -509,6 +531,8 @@ var require_receiver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
509
531
|
this._binaryType = options.binaryType || BINARY_TYPES[0];
|
|
510
532
|
this._extensions = options.extensions || {};
|
|
511
533
|
this._isServer = !!options.isServer;
|
|
534
|
+
this._maxBufferedChunks = options.maxBufferedChunks | 0;
|
|
535
|
+
this._maxFragments = options.maxFragments | 0;
|
|
512
536
|
this._maxPayload = options.maxPayload | 0;
|
|
513
537
|
this._skipUTF8Validation = !!options.skipUTF8Validation;
|
|
514
538
|
this[kWebSocket] = void 0;
|
|
@@ -530,6 +554,10 @@ var require_receiver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
530
554
|
}
|
|
531
555
|
_write(chunk, encoding, cb) {
|
|
532
556
|
if (this._opcode === 8 && this._state == GET_INFO) return cb();
|
|
557
|
+
if (this._maxBufferedChunks > 0 && this._buffers.length >= this._maxBufferedChunks) {
|
|
558
|
+
cb(this.createError(RangeError, "Too many buffered chunks", false, 1008, "WS_ERR_TOO_MANY_BUFFERED_PARTS"));
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
533
561
|
this._bufferedBytes += chunk.length;
|
|
534
562
|
this._buffers.push(chunk);
|
|
535
563
|
this.startLoop(cb);
|
|
@@ -709,6 +737,10 @@ var require_receiver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
709
737
|
return;
|
|
710
738
|
}
|
|
711
739
|
if (data.length) {
|
|
740
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
741
|
+
cb(this.createError(RangeError, "Too many message fragments", false, 1008, "WS_ERR_TOO_MANY_BUFFERED_PARTS"));
|
|
742
|
+
return;
|
|
743
|
+
}
|
|
712
744
|
this._messageLength = this._totalPayloadLength;
|
|
713
745
|
this._fragments.push(data);
|
|
714
746
|
}
|
|
@@ -723,6 +755,10 @@ var require_receiver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
723
755
|
cb(this.createError(RangeError, "Max payload size exceeded", false, 1009, "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"));
|
|
724
756
|
return;
|
|
725
757
|
}
|
|
758
|
+
if (this._maxFragments > 0 && this._fragments.length >= this._maxFragments) {
|
|
759
|
+
cb(this.createError(RangeError, "Too many message fragments", false, 1008, "WS_ERR_TOO_MANY_BUFFERED_PARTS"));
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
726
762
|
this._fragments.push(buf);
|
|
727
763
|
}
|
|
728
764
|
this.dataMessage(cb);
|
|
@@ -827,6 +863,7 @@ var require_receiver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
827
863
|
var require_sender = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
828
864
|
const { Duplex: Duplex$3 } = __require("stream");
|
|
829
865
|
const { randomFillSync } = __require("crypto");
|
|
866
|
+
const { types: { isUint8Array } } = __require("util");
|
|
830
867
|
const PerMessageDeflate = require_permessage_deflate();
|
|
831
868
|
const { EMPTY_BUFFER, kWebSocket, NOOP } = require_constants();
|
|
832
869
|
const { isBlob, isValidStatusCode } = require_validation();
|
|
@@ -931,7 +968,8 @@ var require_sender = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
931
968
|
buf = Buffer.allocUnsafe(2 + length);
|
|
932
969
|
buf.writeUInt16BE(code, 0);
|
|
933
970
|
if (typeof data === "string") buf.write(data, 2);
|
|
934
|
-
else buf.set(data, 2);
|
|
971
|
+
else if (isUint8Array(data)) buf.set(data, 2);
|
|
972
|
+
else throw new TypeError("Second argument must be a string or a Uint8Array");
|
|
935
973
|
}
|
|
936
974
|
const options = {
|
|
937
975
|
[kByteLength]: buf.length,
|
|
@@ -1119,7 +1157,8 @@ var require_sender = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
1119
1157
|
this._state = DEFLATING;
|
|
1120
1158
|
perMessageDeflate.compress(data, options.fin, (_, buf) => {
|
|
1121
1159
|
if (this._socket.destroyed) {
|
|
1122
|
-
|
|
1160
|
+
const err = /* @__PURE__ */ new Error("The socket was closed while data was being compressed");
|
|
1161
|
+
callCallbacks(this, err, cb);
|
|
1123
1162
|
return;
|
|
1124
1163
|
}
|
|
1125
1164
|
this._bufferedBytes -= options[kByteLength];
|
|
@@ -1507,6 +1546,8 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
1507
1546
|
binaryType: this.binaryType,
|
|
1508
1547
|
extensions: this._extensions,
|
|
1509
1548
|
isServer: this._isServer,
|
|
1549
|
+
maxBufferedChunks: options.maxBufferedChunks,
|
|
1550
|
+
maxFragments: options.maxFragments,
|
|
1510
1551
|
maxPayload: options.maxPayload,
|
|
1511
1552
|
skipUTF8Validation: options.skipUTF8Validation
|
|
1512
1553
|
});
|
|
@@ -1714,6 +1755,8 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
1714
1755
|
autoPong: true,
|
|
1715
1756
|
closeTimeout: CLOSE_TIMEOUT,
|
|
1716
1757
|
protocolVersion: protocolVersions[1],
|
|
1758
|
+
maxBufferedChunks: 1024 * 1024,
|
|
1759
|
+
maxFragments: 128 * 1024,
|
|
1717
1760
|
maxPayload: 100 * 1024 * 1024,
|
|
1718
1761
|
skipUTF8Validation: false,
|
|
1719
1762
|
perMessageDeflate: true,
|
|
@@ -1903,6 +1946,8 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
1903
1946
|
websocket.setSocket(socket, head, {
|
|
1904
1947
|
allowSynchronousEvents: opts.allowSynchronousEvents,
|
|
1905
1948
|
generateMask: opts.generateMask,
|
|
1949
|
+
maxBufferedChunks: opts.maxBufferedChunks,
|
|
1950
|
+
maxFragments: opts.maxFragments,
|
|
1906
1951
|
maxPayload: opts.maxPayload,
|
|
1907
1952
|
skipUTF8Validation: opts.skipUTF8Validation
|
|
1908
1953
|
});
|
|
@@ -2188,6 +2233,8 @@ var require_websocket_server = /* @__PURE__ */ __commonJSMin(((exports, module)
|
|
|
2188
2233
|
options = {
|
|
2189
2234
|
allowSynchronousEvents: true,
|
|
2190
2235
|
autoPong: true,
|
|
2236
|
+
maxBufferedChunks: 1024 * 1024,
|
|
2237
|
+
maxFragments: 128 * 1024,
|
|
2191
2238
|
maxPayload: 100 * 1024 * 1024,
|
|
2192
2239
|
skipUTF8Validation: false,
|
|
2193
2240
|
perMessageDeflate: false,
|
|
@@ -2372,6 +2419,8 @@ var require_websocket_server = /* @__PURE__ */ __commonJSMin(((exports, module)
|
|
|
2372
2419
|
socket.removeListener("error", socketOnError);
|
|
2373
2420
|
ws.setSocket(socket, head, {
|
|
2374
2421
|
allowSynchronousEvents: this.options.allowSynchronousEvents,
|
|
2422
|
+
maxBufferedChunks: this.options.maxBufferedChunks,
|
|
2423
|
+
maxFragments: this.options.maxFragments,
|
|
2375
2424
|
maxPayload: this.options.maxPayload,
|
|
2376
2425
|
skipUTF8Validation: this.options.skipUTF8Validation
|
|
2377
2426
|
});
|
|
@@ -2426,4 +2475,4 @@ require_sender();
|
|
|
2426
2475
|
require_subprotocol();
|
|
2427
2476
|
var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
|
|
2428
2477
|
var import_websocket_server = /* @__PURE__ */ __toESM(require_websocket_server(), 1);
|
|
2429
|
-
export {
|
|
2478
|
+
export { import_websocket, import_websocket_server };
|
package/dist/_chunks/node.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Adapter, AdapterInstance, AdapterOptions, Hooks } 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";
|
|
@@ -325,4 +325,4 @@ interface NodeOptions extends AdapterOptions {
|
|
|
325
325
|
serverOptions?: ServerOptions;
|
|
326
326
|
}
|
|
327
327
|
declare const nodeAdapter: Adapter<NodeAdapter, NodeOptions>;
|
|
328
|
-
export {
|
|
328
|
+
export { NodeAdapter, NodeOptions, NodeUpgradeHandler, fromNodeUpgradeHandler, nodeAdapter };
|
package/dist/_chunks/node.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { import_websocket_server } from "./libs/ws.mjs";
|
|
2
|
+
import { AdapterHookable, adapterUtils, getPeers, toBufferLike } from "./adapter.mjs";
|
|
3
|
+
import { Message, Peer } from "./peer.mjs";
|
|
4
|
+
import { WSError } from "./error.mjs";
|
|
5
|
+
import { StubRequest } from "./_request.mjs";
|
|
6
6
|
function fromNodeUpgradeHandler(handler) {
|
|
7
7
|
return { async upgrade(request) {
|
|
8
8
|
const node = request.runtime?.node;
|
|
@@ -15,6 +15,7 @@ const nodeAdapter = (options = {}) => {
|
|
|
15
15
|
if ("Deno" in globalThis || "Bun" in globalThis) throw new Error("[crossws] Using Node.js adapter in an incompatible environment.");
|
|
16
16
|
const hooks = new AdapterHookable(options);
|
|
17
17
|
const globalPeers = /* @__PURE__ */ new Map();
|
|
18
|
+
const baseUtils = adapterUtils(globalPeers, options);
|
|
18
19
|
const wss = options.wss || new import_websocket_server.default({
|
|
19
20
|
noServer: true,
|
|
20
21
|
handleProtocols: () => false,
|
|
@@ -28,7 +29,8 @@ const nodeAdapter = (options = {}) => {
|
|
|
28
29
|
request,
|
|
29
30
|
peers,
|
|
30
31
|
nodeReq,
|
|
31
|
-
namespace: nodeReq._namespace
|
|
32
|
+
namespace: nodeReq._namespace,
|
|
33
|
+
sync: baseUtils.sync
|
|
32
34
|
});
|
|
33
35
|
peers.add(peer);
|
|
34
36
|
hooks.callHook("open", peer);
|
|
@@ -41,8 +43,12 @@ const nodeAdapter = (options = {}) => {
|
|
|
41
43
|
peers.delete(peer);
|
|
42
44
|
hooks.callHook("error", peer, new WSError(error));
|
|
43
45
|
});
|
|
46
|
+
const socket = ws._socket;
|
|
47
|
+
const onDrain = () => hooks.callHook("drain", peer);
|
|
48
|
+
socket?.on("drain", onDrain);
|
|
44
49
|
ws.on("close", (code, reason) => {
|
|
45
50
|
peers.delete(peer);
|
|
51
|
+
socket?.off("drain", onDrain);
|
|
46
52
|
hooks.callHook("close", peer, {
|
|
47
53
|
code,
|
|
48
54
|
reason: reason?.toString()
|
|
@@ -54,7 +60,7 @@ const nodeAdapter = (options = {}) => {
|
|
|
54
60
|
if (upgradeHeaders) for (const [key, value] of new Headers(upgradeHeaders)) outgoingHeaders.push(`${key}: ${value}`);
|
|
55
61
|
});
|
|
56
62
|
return {
|
|
57
|
-
...
|
|
63
|
+
...baseUtils,
|
|
58
64
|
handleUpgrade: async (nodeReq, socket, head, webRequest) => {
|
|
59
65
|
const request = webRequest || new NodeReqProxy(nodeReq);
|
|
60
66
|
const { upgradeHeaders, endResponse, handled, context, namespace } = await hooks.upgrade(request);
|
|
@@ -89,11 +95,11 @@ var NodePeer = class extends Peer {
|
|
|
89
95
|
binary: isBinary,
|
|
90
96
|
...options
|
|
91
97
|
});
|
|
92
|
-
return
|
|
98
|
+
return this._internal.ws.bufferedAmount;
|
|
93
99
|
}
|
|
94
|
-
|
|
100
|
+
_publish(topic, data, options) {
|
|
95
101
|
const dataBuff = toBufferLike(data);
|
|
96
|
-
const isBinary = typeof
|
|
102
|
+
const isBinary = typeof dataBuff !== "string";
|
|
97
103
|
const sendOptions = {
|
|
98
104
|
compress: options?.compress,
|
|
99
105
|
binary: isBinary,
|
|
@@ -126,4 +132,4 @@ async function sendResponse(socket, res) {
|
|
|
126
132
|
});
|
|
127
133
|
});
|
|
128
134
|
}
|
|
129
|
-
export { fromNodeUpgradeHandler
|
|
135
|
+
export { fromNodeUpgradeHandler, nodeAdapter };
|
package/dist/_chunks/peer.mjs
CHANGED
|
@@ -1,28 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function toBufferLike(val) {
|
|
3
|
-
if (val === void 0 || val === null) return "";
|
|
4
|
-
const type = typeof val;
|
|
5
|
-
if (type === "string") return val;
|
|
6
|
-
if (type === "number" || type === "boolean" || type === "bigint") return val.toString();
|
|
7
|
-
if (type === "function" || type === "symbol") return "{}";
|
|
8
|
-
if (val instanceof Uint8Array || val instanceof ArrayBuffer) return val;
|
|
9
|
-
if (isPlainObject(val)) return JSON.stringify(val);
|
|
10
|
-
return val;
|
|
11
|
-
}
|
|
12
|
-
function toString(val) {
|
|
13
|
-
if (typeof val === "string") return val;
|
|
14
|
-
const data = toBufferLike(val);
|
|
15
|
-
if (typeof data === "string") return data;
|
|
16
|
-
return `data:application/octet-stream;base64,${btoa(String.fromCharCode(...new Uint8Array(data)))}`;
|
|
17
|
-
}
|
|
18
|
-
function isPlainObject(value) {
|
|
19
|
-
if (value === null || typeof value !== "object") return false;
|
|
20
|
-
const prototype = Object.getPrototypeOf(value);
|
|
21
|
-
if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) return false;
|
|
22
|
-
if (Symbol.iterator in value) return false;
|
|
23
|
-
if (Symbol.toStringTag in value) return Object.prototype.toString.call(value) === "[object Module]";
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
1
|
+
import { kNodeInspect, serializeMessage } from "./adapter.mjs";
|
|
26
2
|
var Message = class {
|
|
27
3
|
event;
|
|
28
4
|
peer;
|
|
@@ -147,6 +123,34 @@ var Peer = class {
|
|
|
147
123
|
get topics() {
|
|
148
124
|
return this._topics;
|
|
149
125
|
}
|
|
126
|
+
get bufferedAmount() {
|
|
127
|
+
return this._internal.ws?.bufferedAmount ?? 0;
|
|
128
|
+
}
|
|
129
|
+
waitForDrain(opts = {}) {
|
|
130
|
+
const threshold = opts.threshold ?? 0;
|
|
131
|
+
if (this.bufferedAmount <= threshold) return Promise.resolve();
|
|
132
|
+
const signal = opts.signal;
|
|
133
|
+
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
134
|
+
return new Promise((resolve, reject) => {
|
|
135
|
+
const check = () => {
|
|
136
|
+
if (this.bufferedAmount <= threshold || (this.websocket.readyState ?? 1) > 1) {
|
|
137
|
+
cleanup();
|
|
138
|
+
resolve();
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const onAbort = () => {
|
|
142
|
+
cleanup();
|
|
143
|
+
reject(signal.reason);
|
|
144
|
+
};
|
|
145
|
+
const timer = setInterval(check, opts.pollInterval ?? 100);
|
|
146
|
+
timer.unref?.();
|
|
147
|
+
const cleanup = () => {
|
|
148
|
+
clearInterval(timer);
|
|
149
|
+
signal?.removeEventListener("abort", onAbort);
|
|
150
|
+
};
|
|
151
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
152
|
+
});
|
|
153
|
+
}
|
|
150
154
|
terminate() {
|
|
151
155
|
this.close();
|
|
152
156
|
}
|
|
@@ -156,6 +160,14 @@ var Peer = class {
|
|
|
156
160
|
unsubscribe(topic) {
|
|
157
161
|
this._topics.delete(topic);
|
|
158
162
|
}
|
|
163
|
+
publish(topic, data, options) {
|
|
164
|
+
this._publish(topic, data, options);
|
|
165
|
+
this._internal.sync?.publish({
|
|
166
|
+
namespace: this.namespace,
|
|
167
|
+
topic,
|
|
168
|
+
data: serializeMessage(data)
|
|
169
|
+
});
|
|
170
|
+
}
|
|
159
171
|
toString() {
|
|
160
172
|
return this.id;
|
|
161
173
|
}
|
|
@@ -183,4 +195,4 @@ function createWsProxy(ws, request) {
|
|
|
183
195
|
return value;
|
|
184
196
|
} });
|
|
185
197
|
}
|
|
186
|
-
export {
|
|
198
|
+
export { Message, Peer };
|
package/dist/_chunks/sse.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Adapter, AdapterInstance, AdapterOptions } from "./adapter.mjs";
|
|
2
2
|
interface SSEAdapter extends AdapterInstance {
|
|
3
3
|
fetch(req: Request): Promise<Response>;
|
|
4
4
|
}
|
|
@@ -6,4 +6,4 @@ interface SSEOptions extends AdapterOptions {
|
|
|
6
6
|
bidir?: boolean;
|
|
7
7
|
}
|
|
8
8
|
declare const sseAdapter: Adapter<SSEAdapter, SSEOptions>;
|
|
9
|
-
export { SSEOptions
|
|
9
|
+
export { SSEAdapter, SSEOptions, sseAdapter };
|
package/dist/_chunks/web.d.mts
CHANGED
|
@@ -293,4 +293,4 @@ interface WebSocket extends EventTarget {
|
|
|
293
293
|
removeEventListener<K extends keyof WebSocketEventMap>(type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
|
294
294
|
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
|
295
295
|
}
|
|
296
|
-
export {
|
|
296
|
+
export { CloseEvent, Event, EventTarget, MessageEvent, WebSocket };
|
package/dist/adapters/bun.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BunAdapter, BunOptions, bunAdapter } from "../_chunks/bun.mjs";
|
|
2
2
|
export { BunAdapter, BunOptions, bunAdapter as default };
|
package/dist/adapters/bun.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { AdapterHookable, adapterUtils, getPeers, toBufferLike } from "../_chunks/adapter.mjs";
|
|
2
|
+
import { Message, Peer } from "../_chunks/peer.mjs";
|
|
3
3
|
const bunAdapter = (options = {}) => {
|
|
4
4
|
if (typeof Bun === "undefined") throw new Error("[crossws] Using Bun adapter in an incompatible environment.");
|
|
5
5
|
const hooks = new AdapterHookable(options);
|
|
6
6
|
const globalPeers = /* @__PURE__ */ new Map();
|
|
7
|
+
const baseUtils = adapterUtils(globalPeers, options, { nativePubSub: true });
|
|
7
8
|
return {
|
|
8
|
-
...
|
|
9
|
+
...baseUtils,
|
|
9
10
|
async handleUpgrade(request, server) {
|
|
10
11
|
const { upgradeHeaders, endResponse, context, namespace } = await hooks.upgrade(request);
|
|
11
12
|
if (endResponse) return endResponse;
|
|
@@ -21,34 +22,39 @@ const bunAdapter = (options = {}) => {
|
|
|
21
22
|
},
|
|
22
23
|
websocket: {
|
|
23
24
|
message: (ws, message) => {
|
|
24
|
-
const peer = getPeer(ws, getPeers(globalPeers, ws.data.namespace));
|
|
25
|
+
const peer = getPeer(ws, getPeers(globalPeers, ws.data.namespace), baseUtils.sync);
|
|
25
26
|
hooks.callHook("message", peer, new Message(message, peer));
|
|
26
27
|
},
|
|
27
28
|
open: (ws) => {
|
|
28
29
|
const peers = getPeers(globalPeers, ws.data.namespace);
|
|
29
|
-
const peer = getPeer(ws, peers);
|
|
30
|
+
const peer = getPeer(ws, peers, baseUtils.sync);
|
|
30
31
|
peers.add(peer);
|
|
31
32
|
hooks.callHook("open", peer);
|
|
32
33
|
},
|
|
33
34
|
close: (ws, code, reason) => {
|
|
34
35
|
const peers = getPeers(globalPeers, ws.data.namespace);
|
|
35
|
-
const peer = getPeer(ws, peers);
|
|
36
|
+
const peer = getPeer(ws, peers, baseUtils.sync);
|
|
36
37
|
peers.delete(peer);
|
|
37
38
|
hooks.callHook("close", peer, {
|
|
38
39
|
code,
|
|
39
40
|
reason
|
|
40
41
|
});
|
|
42
|
+
},
|
|
43
|
+
drain: (ws) => {
|
|
44
|
+
const peer = getPeer(ws, getPeers(globalPeers, ws.data.namespace));
|
|
45
|
+
hooks.callHook("drain", peer);
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
48
|
};
|
|
44
49
|
};
|
|
45
|
-
function getPeer(ws, peers) {
|
|
50
|
+
function getPeer(ws, peers, sync) {
|
|
46
51
|
if (ws.data.peer) return ws.data.peer;
|
|
47
52
|
const peer = new BunPeer({
|
|
48
53
|
ws,
|
|
49
54
|
request: ws.data.request,
|
|
50
55
|
peers,
|
|
51
|
-
namespace: ws.data.namespace
|
|
56
|
+
namespace: ws.data.namespace,
|
|
57
|
+
sync
|
|
52
58
|
});
|
|
53
59
|
ws.data.peer = peer;
|
|
54
60
|
return peer;
|
|
@@ -60,10 +66,13 @@ var BunPeer = class extends Peer {
|
|
|
60
66
|
get context() {
|
|
61
67
|
return this._internal.ws.data.context;
|
|
62
68
|
}
|
|
69
|
+
get bufferedAmount() {
|
|
70
|
+
return this._internal.ws.getBufferedAmount();
|
|
71
|
+
}
|
|
63
72
|
send(data, options) {
|
|
64
73
|
return this._internal.ws.send(toBufferLike(data), options?.compress);
|
|
65
74
|
}
|
|
66
|
-
|
|
75
|
+
_publish(topic, data, options) {
|
|
67
76
|
return this._internal.ws.publish(topic, toBufferLike(data), options?.compress);
|
|
68
77
|
}
|
|
69
78
|
subscribe(topic) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BunnyAdapter, BunnyOptions, bunnyAdapter } from "../_chunks/bunny.mjs";
|
|
2
2
|
export { BunnyAdapter, BunnyOptions, bunnyAdapter as default };
|
package/dist/adapters/bunny.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { AdapterHookable, adapterUtils, getPeers, toBufferLike } from "../_chunks/adapter.mjs";
|
|
2
|
+
import { Message, Peer } from "../_chunks/peer.mjs";
|
|
3
|
+
import { WSError } from "../_chunks/error.mjs";
|
|
4
4
|
const bunnyAdapter = (options = {}) => {
|
|
5
5
|
const hooks = new AdapterHookable(options);
|
|
6
6
|
const globalPeers = /* @__PURE__ */ new Map();
|
|
7
|
+
const baseUtils = adapterUtils(globalPeers, options);
|
|
7
8
|
return {
|
|
8
|
-
...
|
|
9
|
+
...baseUtils,
|
|
9
10
|
handleUpgrade: async (request) => {
|
|
10
11
|
if (!request.upgradeWebSocket || typeof request.upgradeWebSocket !== "function") throw new Error("[crossws] Bunny adapter requires the request to have an upgradeWebSocket method.");
|
|
11
12
|
const { endResponse, context, namespace, upgradeHeaders } = await hooks.upgrade(request);
|
|
@@ -23,7 +24,8 @@ const bunnyAdapter = (options = {}) => {
|
|
|
23
24
|
namespace,
|
|
24
25
|
remoteAddress,
|
|
25
26
|
peers,
|
|
26
|
-
context
|
|
27
|
+
context,
|
|
28
|
+
sync: baseUtils.sync
|
|
27
29
|
});
|
|
28
30
|
peers.add(peer);
|
|
29
31
|
socket.addEventListener("open", () => {
|
|
@@ -54,7 +56,7 @@ var BunnyPeer = class extends Peer {
|
|
|
54
56
|
send(data) {
|
|
55
57
|
return this._internal.ws.send(toBufferLike(data));
|
|
56
58
|
}
|
|
57
|
-
|
|
59
|
+
_publish(topic, data) {
|
|
58
60
|
const dataBuff = toBufferLike(data);
|
|
59
61
|
for (const peer of this._internal.peers) if (peer !== this && peer._topics.has(topic)) peer._internal.ws.send(dataBuff);
|
|
60
62
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CloudflareDurableAdapter, CloudflareOptions, cloudflareAdapter } from "../_chunks/cloudflare.mjs";
|
|
2
2
|
export { CloudflareDurableAdapter, CloudflareOptions, cloudflareAdapter as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { AdapterHookable, adapterUtils, getPeers, toBufferLike } from "../_chunks/adapter.mjs";
|
|
2
|
+
import { Message, Peer } from "../_chunks/peer.mjs";
|
|
3
|
+
import { WSError } from "../_chunks/error.mjs";
|
|
4
|
+
import { StubRequest } from "../_chunks/_request.mjs";
|
|
5
5
|
import { env } from "cloudflare:workers";
|
|
6
6
|
const cloudflareAdapter = (opts = {}) => {
|
|
7
7
|
const hooks = new AdapterHookable(opts);
|
|
@@ -14,7 +14,8 @@ const cloudflareAdapter = (opts = {}) => {
|
|
|
14
14
|
return binding.get(instanceId);
|
|
15
15
|
}
|
|
16
16
|
});
|
|
17
|
-
const
|
|
17
|
+
const baseUtils = adapterUtils(globalPeers, opts);
|
|
18
|
+
const { publish: durablePublish, ...utils } = baseUtils;
|
|
18
19
|
return {
|
|
19
20
|
...utils,
|
|
20
21
|
handleUpgrade: async (request, cfEnv, cfCtx) => {
|
|
@@ -65,7 +66,7 @@ const cloudflareAdapter = (opts = {}) => {
|
|
|
65
66
|
const pair = new WebSocketPair();
|
|
66
67
|
const client = pair[0];
|
|
67
68
|
const server = pair[1];
|
|
68
|
-
const peer = CloudflareDurablePeer._restore(obj, server, request, namespace);
|
|
69
|
+
const peer = CloudflareDurablePeer._restore(obj, server, request, namespace, baseUtils.sync);
|
|
69
70
|
peers.add(peer);
|
|
70
71
|
obj.ctx.acceptWebSocket(server);
|
|
71
72
|
await hooks.callHook("open", peer);
|
|
@@ -76,11 +77,11 @@ const cloudflareAdapter = (opts = {}) => {
|
|
|
76
77
|
});
|
|
77
78
|
},
|
|
78
79
|
handleDurableMessage: async (obj, ws, message) => {
|
|
79
|
-
const peer = CloudflareDurablePeer._restore(obj, ws);
|
|
80
|
+
const peer = CloudflareDurablePeer._restore(obj, ws, void 0, void 0, baseUtils.sync);
|
|
80
81
|
await hooks.callHook("message", peer, new Message(message, peer));
|
|
81
82
|
},
|
|
82
83
|
handleDurableClose: async (obj, ws, code, reason, wasClean) => {
|
|
83
|
-
const peer = CloudflareDurablePeer._restore(obj, ws);
|
|
84
|
+
const peer = CloudflareDurablePeer._restore(obj, ws, void 0, void 0, baseUtils.sync);
|
|
84
85
|
getPeers(globalPeers, peer.namespace).delete(peer);
|
|
85
86
|
const details = {
|
|
86
87
|
code,
|
|
@@ -106,7 +107,7 @@ const cloudflareAdapter = (opts = {}) => {
|
|
|
106
107
|
};
|
|
107
108
|
var CloudflareDurablePeer = class CloudflareDurablePeer extends Peer {
|
|
108
109
|
get peers() {
|
|
109
|
-
return new Set(this.#getwebsockets().map((ws) => CloudflareDurablePeer._restore(this._internal.durable, ws)));
|
|
110
|
+
return new Set(this.#getwebsockets().map((ws) => CloudflareDurablePeer._restore(this._internal.durable, ws, void 0, void 0, this._internal.sync)));
|
|
110
111
|
}
|
|
111
112
|
#getwebsockets() {
|
|
112
113
|
return this._internal.durable.ctx.getWebSockets();
|
|
@@ -121,7 +122,7 @@ var CloudflareDurablePeer = class CloudflareDurablePeer extends Peer {
|
|
|
121
122
|
state.t.add(topic);
|
|
122
123
|
setAttachedState(this._internal.ws, state);
|
|
123
124
|
}
|
|
124
|
-
|
|
125
|
+
_publish(topic, data) {
|
|
125
126
|
const websockets = this.#getwebsockets();
|
|
126
127
|
if (websockets.length < 2) return;
|
|
127
128
|
const dataBuff = toBufferLike(data);
|
|
@@ -133,7 +134,7 @@ var CloudflareDurablePeer = class CloudflareDurablePeer extends Peer {
|
|
|
133
134
|
close(code, reason) {
|
|
134
135
|
this._internal.ws.close(code, reason);
|
|
135
136
|
}
|
|
136
|
-
static _restore(durable, ws, request, namespace) {
|
|
137
|
+
static _restore(durable, ws, request, namespace, sync) {
|
|
137
138
|
let peer = ws._crosswsPeer;
|
|
138
139
|
if (peer) return peer;
|
|
139
140
|
const state = ws.deserializeAttachment() || {};
|
|
@@ -141,11 +142,13 @@ var CloudflareDurablePeer = class CloudflareDurablePeer extends Peer {
|
|
|
141
142
|
ws,
|
|
142
143
|
request: request || new StubRequest(state.u || ""),
|
|
143
144
|
namespace: namespace || state.n || "",
|
|
144
|
-
durable
|
|
145
|
+
durable,
|
|
146
|
+
sync
|
|
145
147
|
});
|
|
146
148
|
if (state.i) peer._id = state.i;
|
|
147
149
|
if (request?.url) state.u = request.url;
|
|
148
150
|
state.i = peer.id;
|
|
151
|
+
state.n = peer.namespace;
|
|
149
152
|
setAttachedState(ws, state);
|
|
150
153
|
return peer;
|
|
151
154
|
}
|
|
@@ -155,7 +158,7 @@ var CloudflareFallbackPeer = class extends Peer {
|
|
|
155
158
|
this._internal.wsServer.send(toBufferLike(data));
|
|
156
159
|
return 0;
|
|
157
160
|
}
|
|
158
|
-
|
|
161
|
+
_publish(_topic, _message) {
|
|
159
162
|
console.warn("[crossws] [cloudflare] pub/sub support requires Durable Objects.");
|
|
160
163
|
}
|
|
161
164
|
close(code, reason) {
|
package/dist/adapters/deno.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DenoAdapter, DenoOptions, denoAdapter } from "../_chunks/deno.mjs";
|
|
2
2
|
export { DenoAdapter, DenoOptions, denoAdapter as default };
|