@naeemo/capnp 0.9.0 → 0.9.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.
@@ -0,0 +1,4528 @@
1
+ #!/usr/bin/env node
2
+ import { n as MessageBuilder, t as MessageReader } from "./message-reader-_TCBf61G.js";
3
+ import { createRequire } from "node:module";
4
+ import { writeFileSync } from "node:fs";
5
+ import * as os from "node:os";
6
+ import { createConnection } from "node:net";
7
+ import { EventEmitter } from "node:events";
8
+
9
+ //#region \0rolldown/runtime.js
10
+ var __create = Object.create;
11
+ var __defProp = Object.defineProperty;
12
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
13
+ var __getOwnPropNames = Object.getOwnPropertyNames;
14
+ var __getProtoOf = Object.getPrototypeOf;
15
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
16
+ var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
17
+ var __copyProps = (to, from, except, desc) => {
18
+ if (from && typeof from === "object" || typeof from === "function") {
19
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
20
+ key = keys[i];
21
+ if (!__hasOwnProp.call(to, key) && key !== except) {
22
+ __defProp(to, key, {
23
+ get: ((k) => from[k]).bind(null, key),
24
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
25
+ });
26
+ }
27
+ }
28
+ }
29
+ return to;
30
+ };
31
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
32
+ value: mod,
33
+ enumerable: true
34
+ }) : target, mod));
35
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
36
+
37
+ //#endregion
38
+ //#region src/debug/config.ts
39
+ /**
40
+ * Global debug state
41
+ */
42
+ const debugState = {
43
+ enabled: false,
44
+ options: {
45
+ colors: true,
46
+ maxBytes: 256,
47
+ filter: ""
48
+ }
49
+ };
50
+ /**
51
+ * Check if running in Node.js environment
52
+ */
53
+ function isNode$1() {
54
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
55
+ }
56
+ /**
57
+ * Check CAPNP_DEBUG environment variable in Node.js
58
+ */
59
+ function checkEnvVar() {
60
+ if (isNode$1()) try {
61
+ const envValue = process.env.CAPNP_DEBUG;
62
+ return envValue === "1" || envValue === "true";
63
+ } catch {
64
+ return false;
65
+ }
66
+ return false;
67
+ }
68
+ if (checkEnvVar()) debugState.enabled = true;
69
+
70
+ //#endregion
71
+ //#region src/debug/index.ts
72
+ /**
73
+ * Default configuration for debug logging
74
+ */
75
+ const DEFAULT_CONFIG = {
76
+ enabled: false,
77
+ colors: true,
78
+ maxBytesToLog: 1024
79
+ };
80
+ /**
81
+ * ANSI color codes for Node.js output
82
+ */
83
+ const ANSI_COLORS = {
84
+ reset: "\x1B[0m",
85
+ bright: "\x1B[1m",
86
+ dim: "\x1B[2m",
87
+ red: "\x1B[31m",
88
+ green: "\x1B[32m",
89
+ yellow: "\x1B[33m",
90
+ blue: "\x1B[34m",
91
+ magenta: "\x1B[35m",
92
+ cyan: "\x1B[36m",
93
+ white: "\x1B[37m",
94
+ gray: "\x1B[90m"
95
+ };
96
+ /**
97
+ * CSS styles for browser console output
98
+ */
99
+ const BROWSER_STYLES = {
100
+ header: "color: #6c757d; font-weight: bold;",
101
+ send: "color: #28a745; font-weight: bold;",
102
+ recv: "color: #007bff; font-weight: bold;",
103
+ hex: "color: #6c757d;",
104
+ ascii: "color: #495057;",
105
+ arrow: "color: #6c757d;",
106
+ parsed: "color: #17a2b8;"
107
+ };
108
+ /**
109
+ * Check if running in Node.js environment
110
+ */
111
+ function isNode() {
112
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
113
+ }
114
+ /**
115
+ * Format a byte as two-digit hex string
116
+ */
117
+ function byteToHex(byte) {
118
+ return byte.toString(16).padStart(2, "0");
119
+ }
120
+ /**
121
+ * Check if a byte is printable ASCII
122
+ */
123
+ function isPrintable(byte) {
124
+ return byte >= 32 && byte < 127;
125
+ }
126
+ /**
127
+ * Format binary data as hex + ASCII (like hexdump -C)
128
+ *
129
+ * Output format:
130
+ * 00000000: 00 00 00 00 02 00 00 00 │........│
131
+ *
132
+ * @param data - The binary data to format
133
+ * @param maxBytes - Maximum number of bytes to format
134
+ * @param useColors - Whether to include ANSI colors
135
+ * @returns Array of formatted lines
136
+ */
137
+ function formatHexDump(data, maxBytes = 1024, useColors = false) {
138
+ const lines = [];
139
+ const bytesToFormat = Math.min(data.length, maxBytes);
140
+ const bytesPerLine = 16;
141
+ for (let offset = 0; offset < bytesToFormat; offset += bytesPerLine) {
142
+ const chunk = data.slice(offset, Math.min(offset + bytesPerLine, bytesToFormat));
143
+ let line = `${byteToHex(offset >> 24 & 255)}${byteToHex(offset >> 16 & 255)}${byteToHex(offset >> 8 & 255)}${byteToHex(offset & 255)}: `;
144
+ const hexParts = [];
145
+ for (let i = 0; i < bytesPerLine; i++) {
146
+ if (i < chunk.length) hexParts.push(byteToHex(chunk[i]));
147
+ else hexParts.push(" ");
148
+ if (i === 7) hexParts.push("");
149
+ }
150
+ line += hexParts.join(" ");
151
+ let ascii = " │";
152
+ for (let i = 0; i < chunk.length; i++) ascii += isPrintable(chunk[i]) ? String.fromCharCode(chunk[i]) : ".";
153
+ ascii += "│";
154
+ line += ascii;
155
+ if (useColors && isNode()) {
156
+ const hexStart = line.indexOf(":") + 2;
157
+ const delimiterIndex = line.indexOf("│");
158
+ const hexPart = line.slice(hexStart, delimiterIndex);
159
+ const asciiPart = line.slice(delimiterIndex);
160
+ line = line.slice(0, hexStart) + ANSI_COLORS.gray + hexPart + ANSI_COLORS.reset + ANSI_COLORS.dim + asciiPart + ANSI_COLORS.reset;
161
+ }
162
+ lines.push(line);
163
+ }
164
+ if (data.length > maxBytes) {
165
+ const remaining = data.length - maxBytes;
166
+ lines.push(`... (${remaining} more bytes)`);
167
+ }
168
+ return lines;
169
+ }
170
+ /**
171
+ * Debug logger for Cap'n Proto RPC messages
172
+ */
173
+ var DebugLogger = class {
174
+ config;
175
+ /**
176
+ * Create a new DebugLogger instance
177
+ * @param config - Partial configuration to override defaults
178
+ */
179
+ constructor(config = {}) {
180
+ this.config = {
181
+ ...DEFAULT_CONFIG,
182
+ ...config
183
+ };
184
+ }
185
+ /**
186
+ * Update the logger configuration
187
+ * @param config - Partial configuration to merge
188
+ */
189
+ setConfig(config) {
190
+ this.config = {
191
+ ...this.config,
192
+ ...config
193
+ };
194
+ }
195
+ /**
196
+ * Get current configuration
197
+ */
198
+ getConfig() {
199
+ return { ...this.config };
200
+ }
201
+ /**
202
+ * Check if debugging is enabled
203
+ */
204
+ isEnabled() {
205
+ return this.config.enabled;
206
+ }
207
+ /**
208
+ * Enable debug logging
209
+ */
210
+ enable() {
211
+ this.config.enabled = true;
212
+ }
213
+ /**
214
+ * Disable debug logging
215
+ */
216
+ disable() {
217
+ this.config.enabled = false;
218
+ }
219
+ /**
220
+ * Format the header for a log message
221
+ * @param direction - 'send' or 'recv'
222
+ * @param byteLength - Number of bytes
223
+ * @returns Formatted header string
224
+ */
225
+ formatHeader(direction, byteLength) {
226
+ const prefix = direction === "send" ? "CAPNP:SEND" : "CAPNP:RECV";
227
+ if (isNode() && this.config.colors) return `${direction === "send" ? ANSI_COLORS.green : ANSI_COLORS.blue}[${prefix}]${ANSI_COLORS.reset} ${byteLength} bytes`;
228
+ return `[${prefix}] ${byteLength} bytes`;
229
+ }
230
+ /**
231
+ * Log a Cap'n Proto message
232
+ *
233
+ * Output format:
234
+ * [CAPNP:SEND] 64 bytes
235
+ * 00000000: 00 00 00 00 02 00 00 00 │........│
236
+ * → { messageType: 'Bootstrap', ... }
237
+ *
238
+ * @param direction - 'send' for outgoing, 'recv' for incoming
239
+ * @param data - The raw binary message data
240
+ * @param parsed - Optional parsed message object to display
241
+ */
242
+ logMessage(direction, data, parsed) {
243
+ if (!this.config.enabled) return;
244
+ const isNodeEnv = isNode();
245
+ const useColors = this.config.colors;
246
+ const header = this.formatHeader(direction, data.length);
247
+ const hexLines = formatHexDump(data, this.config.maxBytesToLog, useColors);
248
+ if (isNodeEnv) {
249
+ console.log(header);
250
+ for (const line of hexLines) console.log(line);
251
+ if (parsed !== void 0) {
252
+ const arrow = useColors ? `${ANSI_COLORS.gray}→${ANSI_COLORS.reset}` : "→";
253
+ const parsedStr = JSON.stringify(parsed, null, 2);
254
+ const coloredParsed = useColors ? `${ANSI_COLORS.cyan}${parsedStr}${ANSI_COLORS.reset}` : parsedStr;
255
+ console.log(`${arrow} ${coloredParsed}`);
256
+ }
257
+ } else if (useColors) {
258
+ const style = direction === "send" ? BROWSER_STYLES.send : BROWSER_STYLES.recv;
259
+ console.log(`%c[CAPNP:${direction.toUpperCase()}]%c ${data.length} bytes`, style, "color: inherit;");
260
+ for (const line of hexLines) console.log(`%c${line}`, BROWSER_STYLES.hex);
261
+ if (parsed !== void 0) console.log("%c→%c %o", BROWSER_STYLES.arrow, BROWSER_STYLES.parsed, parsed);
262
+ } else {
263
+ console.log(header);
264
+ for (const line of hexLines) console.log(line);
265
+ if (parsed !== void 0) console.log("→", parsed);
266
+ }
267
+ }
268
+ /**
269
+ * Log a generic debug message (only if enabled)
270
+ * @param message - Message to log
271
+ * @param args - Additional arguments
272
+ */
273
+ log(message, ...args) {
274
+ if (!this.config.enabled) return;
275
+ if (isNode() && this.config.colors) console.log(`${ANSI_COLORS.gray}[CAPNP:DEBUG]${ANSI_COLORS.reset} ${message}`, ...args);
276
+ else console.log(`[CAPNP:DEBUG] ${message}`, ...args);
277
+ }
278
+ /**
279
+ * Log an error message (always shown if debug is enabled)
280
+ * @param message - Error message
281
+ * @param error - Optional error object
282
+ */
283
+ error(message, error) {
284
+ if (!this.config.enabled) return;
285
+ if (isNode() && this.config.colors) console.error(`${ANSI_COLORS.red}[CAPNP:ERROR]${ANSI_COLORS.reset} ${message}`, error ?? "");
286
+ else console.error(`[CAPNP:ERROR] ${message}`, error ?? "");
287
+ }
288
+ };
289
+ /**
290
+ * Global debug logger instance for convenience
291
+ */
292
+ const debug = new DebugLogger();
293
+
294
+ //#endregion
295
+ //#region src/rpc/stream.ts
296
+ /** Stream priority levels */
297
+ let StreamPriority = /* @__PURE__ */ function(StreamPriority) {
298
+ StreamPriority[StreamPriority["CRITICAL"] = 0] = "CRITICAL";
299
+ StreamPriority[StreamPriority["HIGH"] = 1] = "HIGH";
300
+ StreamPriority[StreamPriority["NORMAL"] = 2] = "NORMAL";
301
+ StreamPriority[StreamPriority["LOW"] = 3] = "LOW";
302
+ StreamPriority[StreamPriority["BACKGROUND"] = 4] = "BACKGROUND";
303
+ return StreamPriority;
304
+ }({});
305
+
306
+ //#endregion
307
+ //#region src/rpc/realtime.ts
308
+ /** Message drop policy for latency-sensitive scenarios */
309
+ let DropPolicy = /* @__PURE__ */ function(DropPolicy) {
310
+ /** Never drop messages */
311
+ DropPolicy["NEVER"] = "never";
312
+ /** Drop oldest messages when queue is full */
313
+ DropPolicy["DROP_OLDEST"] = "drop_oldest";
314
+ /** Drop newest messages when queue is full */
315
+ DropPolicy["DROP_NEWEST"] = "drop_newest";
316
+ /** Drop low priority messages first */
317
+ DropPolicy["DROP_LOW_PRIORITY"] = "drop_low_priority";
318
+ /** Drop messages that exceed max latency */
319
+ DropPolicy["DROP_STALE"] = "drop_stale";
320
+ return DropPolicy;
321
+ }({});
322
+ /** Default realtime configuration */
323
+ const DEFAULT_REALTIME_CONFIG = {
324
+ targetLatencyMs: 50,
325
+ maxLatencyMs: 200,
326
+ jitterBufferMs: 30,
327
+ maxQueueSize: 1e3,
328
+ dropPolicy: DropPolicy.DROP_STALE,
329
+ adaptiveBitrate: true,
330
+ minBitrate: 16e3,
331
+ maxBitrate: 10485760,
332
+ bandwidthWindowMs: 1e3
333
+ };
334
+
335
+ //#endregion
336
+ //#region src/rpc/stream-manager.ts
337
+ /** Default stream manager configuration */
338
+ const DEFAULT_STREAM_MANAGER_CONFIG = {
339
+ maxStreams: 100,
340
+ defaultPriority: StreamPriority.NORMAL,
341
+ enableMultiplexing: true,
342
+ idleTimeoutMs: 3e5
343
+ };
344
+
345
+ //#endregion
346
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js
347
+ var require_constants = /* @__PURE__ */ __commonJSMin(((exports, module) => {
348
+ const BINARY_TYPES = [
349
+ "nodebuffer",
350
+ "arraybuffer",
351
+ "fragments"
352
+ ];
353
+ const hasBlob = typeof Blob !== "undefined";
354
+ if (hasBlob) BINARY_TYPES.push("blob");
355
+ module.exports = {
356
+ BINARY_TYPES,
357
+ CLOSE_TIMEOUT: 3e4,
358
+ EMPTY_BUFFER: Buffer.alloc(0),
359
+ GUID: "258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
360
+ hasBlob,
361
+ kForOnEventAttribute: Symbol("kIsForOnEventAttribute"),
362
+ kListener: Symbol("kListener"),
363
+ kStatusCode: Symbol("status-code"),
364
+ kWebSocket: Symbol("websocket"),
365
+ NOOP: () => {}
366
+ };
367
+ }));
368
+
369
+ //#endregion
370
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js
371
+ var require_buffer_util = /* @__PURE__ */ __commonJSMin(((exports, module) => {
372
+ const { EMPTY_BUFFER } = require_constants();
373
+ const FastBuffer = Buffer[Symbol.species];
374
+ /**
375
+ * Merges an array of buffers into a new buffer.
376
+ *
377
+ * @param {Buffer[]} list The array of buffers to concat
378
+ * @param {Number} totalLength The total length of buffers in the list
379
+ * @return {Buffer} The resulting buffer
380
+ * @public
381
+ */
382
+ function concat(list, totalLength) {
383
+ if (list.length === 0) return EMPTY_BUFFER;
384
+ if (list.length === 1) return list[0];
385
+ const target = Buffer.allocUnsafe(totalLength);
386
+ let offset = 0;
387
+ for (let i = 0; i < list.length; i++) {
388
+ const buf = list[i];
389
+ target.set(buf, offset);
390
+ offset += buf.length;
391
+ }
392
+ if (offset < totalLength) return new FastBuffer(target.buffer, target.byteOffset, offset);
393
+ return target;
394
+ }
395
+ /**
396
+ * Masks a buffer using the given mask.
397
+ *
398
+ * @param {Buffer} source The buffer to mask
399
+ * @param {Buffer} mask The mask to use
400
+ * @param {Buffer} output The buffer where to store the result
401
+ * @param {Number} offset The offset at which to start writing
402
+ * @param {Number} length The number of bytes to mask.
403
+ * @public
404
+ */
405
+ function _mask(source, mask, output, offset, length) {
406
+ for (let i = 0; i < length; i++) output[offset + i] = source[i] ^ mask[i & 3];
407
+ }
408
+ /**
409
+ * Unmasks a buffer using the given mask.
410
+ *
411
+ * @param {Buffer} buffer The buffer to unmask
412
+ * @param {Buffer} mask The mask to use
413
+ * @public
414
+ */
415
+ function _unmask(buffer, mask) {
416
+ for (let i = 0; i < buffer.length; i++) buffer[i] ^= mask[i & 3];
417
+ }
418
+ /**
419
+ * Converts a buffer to an `ArrayBuffer`.
420
+ *
421
+ * @param {Buffer} buf The buffer to convert
422
+ * @return {ArrayBuffer} Converted buffer
423
+ * @public
424
+ */
425
+ function toArrayBuffer(buf) {
426
+ if (buf.length === buf.buffer.byteLength) return buf.buffer;
427
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);
428
+ }
429
+ /**
430
+ * Converts `data` to a `Buffer`.
431
+ *
432
+ * @param {*} data The data to convert
433
+ * @return {Buffer} The buffer
434
+ * @throws {TypeError}
435
+ * @public
436
+ */
437
+ function toBuffer(data) {
438
+ toBuffer.readOnly = true;
439
+ if (Buffer.isBuffer(data)) return data;
440
+ let buf;
441
+ if (data instanceof ArrayBuffer) buf = new FastBuffer(data);
442
+ else if (ArrayBuffer.isView(data)) buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);
443
+ else {
444
+ buf = Buffer.from(data);
445
+ toBuffer.readOnly = false;
446
+ }
447
+ return buf;
448
+ }
449
+ module.exports = {
450
+ concat,
451
+ mask: _mask,
452
+ toArrayBuffer,
453
+ toBuffer,
454
+ unmask: _unmask
455
+ };
456
+ /* istanbul ignore else */
457
+ if (!process.env.WS_NO_BUFFER_UTIL) try {
458
+ const bufferUtil = __require("bufferutil");
459
+ module.exports.mask = function(source, mask, output, offset, length) {
460
+ if (length < 48) _mask(source, mask, output, offset, length);
461
+ else bufferUtil.mask(source, mask, output, offset, length);
462
+ };
463
+ module.exports.unmask = function(buffer, mask) {
464
+ if (buffer.length < 32) _unmask(buffer, mask);
465
+ else bufferUtil.unmask(buffer, mask);
466
+ };
467
+ } catch (e) {}
468
+ }));
469
+
470
+ //#endregion
471
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js
472
+ var require_limiter = /* @__PURE__ */ __commonJSMin(((exports, module) => {
473
+ const kDone = Symbol("kDone");
474
+ const kRun = Symbol("kRun");
475
+ /**
476
+ * A very simple job queue with adjustable concurrency. Adapted from
477
+ * https://github.com/STRML/async-limiter
478
+ */
479
+ var Limiter = class {
480
+ /**
481
+ * Creates a new `Limiter`.
482
+ *
483
+ * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
484
+ * to run concurrently
485
+ */
486
+ constructor(concurrency) {
487
+ this[kDone] = () => {
488
+ this.pending--;
489
+ this[kRun]();
490
+ };
491
+ this.concurrency = concurrency || Infinity;
492
+ this.jobs = [];
493
+ this.pending = 0;
494
+ }
495
+ /**
496
+ * Adds a job to the queue.
497
+ *
498
+ * @param {Function} job The job to run
499
+ * @public
500
+ */
501
+ add(job) {
502
+ this.jobs.push(job);
503
+ this[kRun]();
504
+ }
505
+ /**
506
+ * Removes a job from the queue and runs it if possible.
507
+ *
508
+ * @private
509
+ */
510
+ [kRun]() {
511
+ if (this.pending === this.concurrency) return;
512
+ if (this.jobs.length) {
513
+ const job = this.jobs.shift();
514
+ this.pending++;
515
+ job(this[kDone]);
516
+ }
517
+ }
518
+ };
519
+ module.exports = Limiter;
520
+ }));
521
+
522
+ //#endregion
523
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js
524
+ var require_permessage_deflate = /* @__PURE__ */ __commonJSMin(((exports, module) => {
525
+ const zlib = __require("zlib");
526
+ const bufferUtil = require_buffer_util();
527
+ const Limiter = require_limiter();
528
+ const { kStatusCode } = require_constants();
529
+ const FastBuffer = Buffer[Symbol.species];
530
+ const TRAILER = Buffer.from([
531
+ 0,
532
+ 0,
533
+ 255,
534
+ 255
535
+ ]);
536
+ const kPerMessageDeflate = Symbol("permessage-deflate");
537
+ const kTotalLength = Symbol("total-length");
538
+ const kCallback = Symbol("callback");
539
+ const kBuffers = Symbol("buffers");
540
+ const kError = Symbol("error");
541
+ let zlibLimiter;
542
+ /**
543
+ * permessage-deflate implementation.
544
+ */
545
+ var PerMessageDeflate = class {
546
+ /**
547
+ * Creates a PerMessageDeflate instance.
548
+ *
549
+ * @param {Object} [options] Configuration options
550
+ * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
551
+ * for, or request, a custom client window size
552
+ * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
553
+ * acknowledge disabling of client context takeover
554
+ * @param {Number} [options.concurrencyLimit=10] The number of concurrent
555
+ * calls to zlib
556
+ * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
557
+ * use of a custom server window size
558
+ * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
559
+ * disabling of server context takeover
560
+ * @param {Number} [options.threshold=1024] Size (in bytes) below which
561
+ * messages should not be compressed if context takeover is disabled
562
+ * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
563
+ * deflate
564
+ * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
565
+ * inflate
566
+ * @param {Boolean} [isServer=false] Create the instance in either server or
567
+ * client mode
568
+ * @param {Number} [maxPayload=0] The maximum allowed message length
569
+ */
570
+ constructor(options, isServer, maxPayload) {
571
+ this._maxPayload = maxPayload | 0;
572
+ this._options = options || {};
573
+ this._threshold = this._options.threshold !== void 0 ? this._options.threshold : 1024;
574
+ this._isServer = !!isServer;
575
+ this._deflate = null;
576
+ this._inflate = null;
577
+ this.params = null;
578
+ if (!zlibLimiter) zlibLimiter = new Limiter(this._options.concurrencyLimit !== void 0 ? this._options.concurrencyLimit : 10);
579
+ }
580
+ /**
581
+ * @type {String}
582
+ */
583
+ static get extensionName() {
584
+ return "permessage-deflate";
585
+ }
586
+ /**
587
+ * Create an extension negotiation offer.
588
+ *
589
+ * @return {Object} Extension parameters
590
+ * @public
591
+ */
592
+ offer() {
593
+ const params = {};
594
+ if (this._options.serverNoContextTakeover) params.server_no_context_takeover = true;
595
+ if (this._options.clientNoContextTakeover) params.client_no_context_takeover = true;
596
+ if (this._options.serverMaxWindowBits) params.server_max_window_bits = this._options.serverMaxWindowBits;
597
+ if (this._options.clientMaxWindowBits) params.client_max_window_bits = this._options.clientMaxWindowBits;
598
+ else if (this._options.clientMaxWindowBits == null) params.client_max_window_bits = true;
599
+ return params;
600
+ }
601
+ /**
602
+ * Accept an extension negotiation offer/response.
603
+ *
604
+ * @param {Array} configurations The extension negotiation offers/reponse
605
+ * @return {Object} Accepted configuration
606
+ * @public
607
+ */
608
+ accept(configurations) {
609
+ configurations = this.normalizeParams(configurations);
610
+ this.params = this._isServer ? this.acceptAsServer(configurations) : this.acceptAsClient(configurations);
611
+ return this.params;
612
+ }
613
+ /**
614
+ * Releases all resources used by the extension.
615
+ *
616
+ * @public
617
+ */
618
+ cleanup() {
619
+ if (this._inflate) {
620
+ this._inflate.close();
621
+ this._inflate = null;
622
+ }
623
+ if (this._deflate) {
624
+ const callback = this._deflate[kCallback];
625
+ this._deflate.close();
626
+ this._deflate = null;
627
+ if (callback) callback(/* @__PURE__ */ new Error("The deflate stream was closed while data was being processed"));
628
+ }
629
+ }
630
+ /**
631
+ * Accept an extension negotiation offer.
632
+ *
633
+ * @param {Array} offers The extension negotiation offers
634
+ * @return {Object} Accepted configuration
635
+ * @private
636
+ */
637
+ acceptAsServer(offers) {
638
+ const opts = this._options;
639
+ const accepted = offers.find((params) => {
640
+ if (opts.serverNoContextTakeover === false && params.server_no_context_takeover || params.server_max_window_bits && (opts.serverMaxWindowBits === false || typeof opts.serverMaxWindowBits === "number" && opts.serverMaxWindowBits > params.server_max_window_bits) || typeof opts.clientMaxWindowBits === "number" && !params.client_max_window_bits) return false;
641
+ return true;
642
+ });
643
+ if (!accepted) throw new Error("None of the extension offers can be accepted");
644
+ if (opts.serverNoContextTakeover) accepted.server_no_context_takeover = true;
645
+ if (opts.clientNoContextTakeover) accepted.client_no_context_takeover = true;
646
+ if (typeof opts.serverMaxWindowBits === "number") accepted.server_max_window_bits = opts.serverMaxWindowBits;
647
+ if (typeof opts.clientMaxWindowBits === "number") accepted.client_max_window_bits = opts.clientMaxWindowBits;
648
+ else if (accepted.client_max_window_bits === true || opts.clientMaxWindowBits === false) delete accepted.client_max_window_bits;
649
+ return accepted;
650
+ }
651
+ /**
652
+ * Accept the extension negotiation response.
653
+ *
654
+ * @param {Array} response The extension negotiation response
655
+ * @return {Object} Accepted configuration
656
+ * @private
657
+ */
658
+ acceptAsClient(response) {
659
+ const params = response[0];
660
+ if (this._options.clientNoContextTakeover === false && params.client_no_context_takeover) throw new Error("Unexpected parameter \"client_no_context_takeover\"");
661
+ if (!params.client_max_window_bits) {
662
+ if (typeof this._options.clientMaxWindowBits === "number") params.client_max_window_bits = this._options.clientMaxWindowBits;
663
+ } else if (this._options.clientMaxWindowBits === false || typeof this._options.clientMaxWindowBits === "number" && params.client_max_window_bits > this._options.clientMaxWindowBits) throw new Error("Unexpected or invalid parameter \"client_max_window_bits\"");
664
+ return params;
665
+ }
666
+ /**
667
+ * Normalize parameters.
668
+ *
669
+ * @param {Array} configurations The extension negotiation offers/reponse
670
+ * @return {Array} The offers/response with normalized parameters
671
+ * @private
672
+ */
673
+ normalizeParams(configurations) {
674
+ configurations.forEach((params) => {
675
+ Object.keys(params).forEach((key) => {
676
+ let value = params[key];
677
+ if (value.length > 1) throw new Error(`Parameter "${key}" must have only a single value`);
678
+ value = value[0];
679
+ if (key === "client_max_window_bits") {
680
+ if (value !== true) {
681
+ const num = +value;
682
+ if (!Number.isInteger(num) || num < 8 || num > 15) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
683
+ value = num;
684
+ } else if (!this._isServer) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
685
+ } else if (key === "server_max_window_bits") {
686
+ const num = +value;
687
+ if (!Number.isInteger(num) || num < 8 || num > 15) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
688
+ value = num;
689
+ } else if (key === "client_no_context_takeover" || key === "server_no_context_takeover") {
690
+ if (value !== true) throw new TypeError(`Invalid value for parameter "${key}": ${value}`);
691
+ } else throw new Error(`Unknown parameter "${key}"`);
692
+ params[key] = value;
693
+ });
694
+ });
695
+ return configurations;
696
+ }
697
+ /**
698
+ * Decompress data. Concurrency limited.
699
+ *
700
+ * @param {Buffer} data Compressed data
701
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
702
+ * @param {Function} callback Callback
703
+ * @public
704
+ */
705
+ decompress(data, fin, callback) {
706
+ zlibLimiter.add((done) => {
707
+ this._decompress(data, fin, (err, result) => {
708
+ done();
709
+ callback(err, result);
710
+ });
711
+ });
712
+ }
713
+ /**
714
+ * Compress data. Concurrency limited.
715
+ *
716
+ * @param {(Buffer|String)} data Data to compress
717
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
718
+ * @param {Function} callback Callback
719
+ * @public
720
+ */
721
+ compress(data, fin, callback) {
722
+ zlibLimiter.add((done) => {
723
+ this._compress(data, fin, (err, result) => {
724
+ done();
725
+ callback(err, result);
726
+ });
727
+ });
728
+ }
729
+ /**
730
+ * Decompress data.
731
+ *
732
+ * @param {Buffer} data Compressed data
733
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
734
+ * @param {Function} callback Callback
735
+ * @private
736
+ */
737
+ _decompress(data, fin, callback) {
738
+ const endpoint = this._isServer ? "client" : "server";
739
+ if (!this._inflate) {
740
+ const key = `${endpoint}_max_window_bits`;
741
+ const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key];
742
+ this._inflate = zlib.createInflateRaw({
743
+ ...this._options.zlibInflateOptions,
744
+ windowBits
745
+ });
746
+ this._inflate[kPerMessageDeflate] = this;
747
+ this._inflate[kTotalLength] = 0;
748
+ this._inflate[kBuffers] = [];
749
+ this._inflate.on("error", inflateOnError);
750
+ this._inflate.on("data", inflateOnData);
751
+ }
752
+ this._inflate[kCallback] = callback;
753
+ this._inflate.write(data);
754
+ if (fin) this._inflate.write(TRAILER);
755
+ this._inflate.flush(() => {
756
+ const err = this._inflate[kError];
757
+ if (err) {
758
+ this._inflate.close();
759
+ this._inflate = null;
760
+ callback(err);
761
+ return;
762
+ }
763
+ const data = bufferUtil.concat(this._inflate[kBuffers], this._inflate[kTotalLength]);
764
+ if (this._inflate._readableState.endEmitted) {
765
+ this._inflate.close();
766
+ this._inflate = null;
767
+ } else {
768
+ this._inflate[kTotalLength] = 0;
769
+ this._inflate[kBuffers] = [];
770
+ if (fin && this.params[`${endpoint}_no_context_takeover`]) this._inflate.reset();
771
+ }
772
+ callback(null, data);
773
+ });
774
+ }
775
+ /**
776
+ * Compress data.
777
+ *
778
+ * @param {(Buffer|String)} data Data to compress
779
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
780
+ * @param {Function} callback Callback
781
+ * @private
782
+ */
783
+ _compress(data, fin, callback) {
784
+ const endpoint = this._isServer ? "server" : "client";
785
+ if (!this._deflate) {
786
+ const key = `${endpoint}_max_window_bits`;
787
+ const windowBits = typeof this.params[key] !== "number" ? zlib.Z_DEFAULT_WINDOWBITS : this.params[key];
788
+ this._deflate = zlib.createDeflateRaw({
789
+ ...this._options.zlibDeflateOptions,
790
+ windowBits
791
+ });
792
+ this._deflate[kTotalLength] = 0;
793
+ this._deflate[kBuffers] = [];
794
+ this._deflate.on("data", deflateOnData);
795
+ }
796
+ this._deflate[kCallback] = callback;
797
+ this._deflate.write(data);
798
+ this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
799
+ if (!this._deflate) return;
800
+ let data = bufferUtil.concat(this._deflate[kBuffers], this._deflate[kTotalLength]);
801
+ if (fin) data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
802
+ this._deflate[kCallback] = null;
803
+ this._deflate[kTotalLength] = 0;
804
+ this._deflate[kBuffers] = [];
805
+ if (fin && this.params[`${endpoint}_no_context_takeover`]) this._deflate.reset();
806
+ callback(null, data);
807
+ });
808
+ }
809
+ };
810
+ module.exports = PerMessageDeflate;
811
+ /**
812
+ * The listener of the `zlib.DeflateRaw` stream `'data'` event.
813
+ *
814
+ * @param {Buffer} chunk A chunk of data
815
+ * @private
816
+ */
817
+ function deflateOnData(chunk) {
818
+ this[kBuffers].push(chunk);
819
+ this[kTotalLength] += chunk.length;
820
+ }
821
+ /**
822
+ * The listener of the `zlib.InflateRaw` stream `'data'` event.
823
+ *
824
+ * @param {Buffer} chunk A chunk of data
825
+ * @private
826
+ */
827
+ function inflateOnData(chunk) {
828
+ this[kTotalLength] += chunk.length;
829
+ if (this[kPerMessageDeflate]._maxPayload < 1 || this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload) {
830
+ this[kBuffers].push(chunk);
831
+ return;
832
+ }
833
+ this[kError] = /* @__PURE__ */ new RangeError("Max payload size exceeded");
834
+ this[kError].code = "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH";
835
+ this[kError][kStatusCode] = 1009;
836
+ this.removeListener("data", inflateOnData);
837
+ this.reset();
838
+ }
839
+ /**
840
+ * The listener of the `zlib.InflateRaw` stream `'error'` event.
841
+ *
842
+ * @param {Error} err The emitted error
843
+ * @private
844
+ */
845
+ function inflateOnError(err) {
846
+ this[kPerMessageDeflate]._inflate = null;
847
+ if (this[kError]) {
848
+ this[kCallback](this[kError]);
849
+ return;
850
+ }
851
+ err[kStatusCode] = 1007;
852
+ this[kCallback](err);
853
+ }
854
+ }));
855
+
856
+ //#endregion
857
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js
858
+ var require_validation = /* @__PURE__ */ __commonJSMin(((exports, module) => {
859
+ const { isUtf8 } = __require("buffer");
860
+ const { hasBlob } = require_constants();
861
+ const tokenChars = [
862
+ 0,
863
+ 0,
864
+ 0,
865
+ 0,
866
+ 0,
867
+ 0,
868
+ 0,
869
+ 0,
870
+ 0,
871
+ 0,
872
+ 0,
873
+ 0,
874
+ 0,
875
+ 0,
876
+ 0,
877
+ 0,
878
+ 0,
879
+ 0,
880
+ 0,
881
+ 0,
882
+ 0,
883
+ 0,
884
+ 0,
885
+ 0,
886
+ 0,
887
+ 0,
888
+ 0,
889
+ 0,
890
+ 0,
891
+ 0,
892
+ 0,
893
+ 0,
894
+ 0,
895
+ 1,
896
+ 0,
897
+ 1,
898
+ 1,
899
+ 1,
900
+ 1,
901
+ 1,
902
+ 0,
903
+ 0,
904
+ 1,
905
+ 1,
906
+ 0,
907
+ 1,
908
+ 1,
909
+ 0,
910
+ 1,
911
+ 1,
912
+ 1,
913
+ 1,
914
+ 1,
915
+ 1,
916
+ 1,
917
+ 1,
918
+ 1,
919
+ 1,
920
+ 0,
921
+ 0,
922
+ 0,
923
+ 0,
924
+ 0,
925
+ 0,
926
+ 0,
927
+ 1,
928
+ 1,
929
+ 1,
930
+ 1,
931
+ 1,
932
+ 1,
933
+ 1,
934
+ 1,
935
+ 1,
936
+ 1,
937
+ 1,
938
+ 1,
939
+ 1,
940
+ 1,
941
+ 1,
942
+ 1,
943
+ 1,
944
+ 1,
945
+ 1,
946
+ 1,
947
+ 1,
948
+ 1,
949
+ 1,
950
+ 1,
951
+ 1,
952
+ 1,
953
+ 0,
954
+ 0,
955
+ 0,
956
+ 1,
957
+ 1,
958
+ 1,
959
+ 1,
960
+ 1,
961
+ 1,
962
+ 1,
963
+ 1,
964
+ 1,
965
+ 1,
966
+ 1,
967
+ 1,
968
+ 1,
969
+ 1,
970
+ 1,
971
+ 1,
972
+ 1,
973
+ 1,
974
+ 1,
975
+ 1,
976
+ 1,
977
+ 1,
978
+ 1,
979
+ 1,
980
+ 1,
981
+ 1,
982
+ 1,
983
+ 1,
984
+ 1,
985
+ 0,
986
+ 1,
987
+ 0,
988
+ 1,
989
+ 0
990
+ ];
991
+ /**
992
+ * Checks if a status code is allowed in a close frame.
993
+ *
994
+ * @param {Number} code The status code
995
+ * @return {Boolean} `true` if the status code is valid, else `false`
996
+ * @public
997
+ */
998
+ function isValidStatusCode(code) {
999
+ return code >= 1e3 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006 || code >= 3e3 && code <= 4999;
1000
+ }
1001
+ /**
1002
+ * Checks if a given buffer contains only correct UTF-8.
1003
+ * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
1004
+ * Markus Kuhn.
1005
+ *
1006
+ * @param {Buffer} buf The buffer to check
1007
+ * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
1008
+ * @public
1009
+ */
1010
+ function _isValidUTF8(buf) {
1011
+ const len = buf.length;
1012
+ let i = 0;
1013
+ while (i < len) if ((buf[i] & 128) === 0) i++;
1014
+ else if ((buf[i] & 224) === 192) {
1015
+ if (i + 1 === len || (buf[i + 1] & 192) !== 128 || (buf[i] & 254) === 192) return false;
1016
+ i += 2;
1017
+ } else if ((buf[i] & 240) === 224) {
1018
+ if (i + 2 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || buf[i] === 224 && (buf[i + 1] & 224) === 128 || buf[i] === 237 && (buf[i + 1] & 224) === 160) return false;
1019
+ i += 3;
1020
+ } else if ((buf[i] & 248) === 240) {
1021
+ if (i + 3 >= len || (buf[i + 1] & 192) !== 128 || (buf[i + 2] & 192) !== 128 || (buf[i + 3] & 192) !== 128 || buf[i] === 240 && (buf[i + 1] & 240) === 128 || buf[i] === 244 && buf[i + 1] > 143 || buf[i] > 244) return false;
1022
+ i += 4;
1023
+ } else return false;
1024
+ return true;
1025
+ }
1026
+ /**
1027
+ * Determines whether a value is a `Blob`.
1028
+ *
1029
+ * @param {*} value The value to be tested
1030
+ * @return {Boolean} `true` if `value` is a `Blob`, else `false`
1031
+ * @private
1032
+ */
1033
+ function isBlob(value) {
1034
+ return hasBlob && typeof value === "object" && typeof value.arrayBuffer === "function" && typeof value.type === "string" && typeof value.stream === "function" && (value[Symbol.toStringTag] === "Blob" || value[Symbol.toStringTag] === "File");
1035
+ }
1036
+ module.exports = {
1037
+ isBlob,
1038
+ isValidStatusCode,
1039
+ isValidUTF8: _isValidUTF8,
1040
+ tokenChars
1041
+ };
1042
+ if (isUtf8) module.exports.isValidUTF8 = function(buf) {
1043
+ return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);
1044
+ };
1045
+ else if (!process.env.WS_NO_UTF_8_VALIDATE) try {
1046
+ const isValidUTF8 = __require("utf-8-validate");
1047
+ module.exports.isValidUTF8 = function(buf) {
1048
+ return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);
1049
+ };
1050
+ } catch (e) {}
1051
+ }));
1052
+
1053
+ //#endregion
1054
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js
1055
+ var require_receiver = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1056
+ const { Writable } = __require("stream");
1057
+ const PerMessageDeflate = require_permessage_deflate();
1058
+ const { BINARY_TYPES, EMPTY_BUFFER, kStatusCode, kWebSocket } = require_constants();
1059
+ const { concat, toArrayBuffer, unmask } = require_buffer_util();
1060
+ const { isValidStatusCode, isValidUTF8 } = require_validation();
1061
+ const FastBuffer = Buffer[Symbol.species];
1062
+ const GET_INFO = 0;
1063
+ const GET_PAYLOAD_LENGTH_16 = 1;
1064
+ const GET_PAYLOAD_LENGTH_64 = 2;
1065
+ const GET_MASK = 3;
1066
+ const GET_DATA = 4;
1067
+ const INFLATING = 5;
1068
+ const DEFER_EVENT = 6;
1069
+ /**
1070
+ * HyBi Receiver implementation.
1071
+ *
1072
+ * @extends Writable
1073
+ */
1074
+ var Receiver = class extends Writable {
1075
+ /**
1076
+ * Creates a Receiver instance.
1077
+ *
1078
+ * @param {Object} [options] Options object
1079
+ * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
1080
+ * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
1081
+ * multiple times in the same tick
1082
+ * @param {String} [options.binaryType=nodebuffer] The type for binary data
1083
+ * @param {Object} [options.extensions] An object containing the negotiated
1084
+ * extensions
1085
+ * @param {Boolean} [options.isServer=false] Specifies whether to operate in
1086
+ * client or server mode
1087
+ * @param {Number} [options.maxPayload=0] The maximum allowed message length
1088
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
1089
+ * not to skip UTF-8 validation for text and close messages
1090
+ */
1091
+ constructor(options = {}) {
1092
+ super();
1093
+ this._allowSynchronousEvents = options.allowSynchronousEvents !== void 0 ? options.allowSynchronousEvents : true;
1094
+ this._binaryType = options.binaryType || BINARY_TYPES[0];
1095
+ this._extensions = options.extensions || {};
1096
+ this._isServer = !!options.isServer;
1097
+ this._maxPayload = options.maxPayload | 0;
1098
+ this._skipUTF8Validation = !!options.skipUTF8Validation;
1099
+ this[kWebSocket] = void 0;
1100
+ this._bufferedBytes = 0;
1101
+ this._buffers = [];
1102
+ this._compressed = false;
1103
+ this._payloadLength = 0;
1104
+ this._mask = void 0;
1105
+ this._fragmented = 0;
1106
+ this._masked = false;
1107
+ this._fin = false;
1108
+ this._opcode = 0;
1109
+ this._totalPayloadLength = 0;
1110
+ this._messageLength = 0;
1111
+ this._fragments = [];
1112
+ this._errored = false;
1113
+ this._loop = false;
1114
+ this._state = GET_INFO;
1115
+ }
1116
+ /**
1117
+ * Implements `Writable.prototype._write()`.
1118
+ *
1119
+ * @param {Buffer} chunk The chunk of data to write
1120
+ * @param {String} encoding The character encoding of `chunk`
1121
+ * @param {Function} cb Callback
1122
+ * @private
1123
+ */
1124
+ _write(chunk, encoding, cb) {
1125
+ if (this._opcode === 8 && this._state == GET_INFO) return cb();
1126
+ this._bufferedBytes += chunk.length;
1127
+ this._buffers.push(chunk);
1128
+ this.startLoop(cb);
1129
+ }
1130
+ /**
1131
+ * Consumes `n` bytes from the buffered data.
1132
+ *
1133
+ * @param {Number} n The number of bytes to consume
1134
+ * @return {Buffer} The consumed bytes
1135
+ * @private
1136
+ */
1137
+ consume(n) {
1138
+ this._bufferedBytes -= n;
1139
+ if (n === this._buffers[0].length) return this._buffers.shift();
1140
+ if (n < this._buffers[0].length) {
1141
+ const buf = this._buffers[0];
1142
+ this._buffers[0] = new FastBuffer(buf.buffer, buf.byteOffset + n, buf.length - n);
1143
+ return new FastBuffer(buf.buffer, buf.byteOffset, n);
1144
+ }
1145
+ const dst = Buffer.allocUnsafe(n);
1146
+ do {
1147
+ const buf = this._buffers[0];
1148
+ const offset = dst.length - n;
1149
+ if (n >= buf.length) dst.set(this._buffers.shift(), offset);
1150
+ else {
1151
+ dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
1152
+ this._buffers[0] = new FastBuffer(buf.buffer, buf.byteOffset + n, buf.length - n);
1153
+ }
1154
+ n -= buf.length;
1155
+ } while (n > 0);
1156
+ return dst;
1157
+ }
1158
+ /**
1159
+ * Starts the parsing loop.
1160
+ *
1161
+ * @param {Function} cb Callback
1162
+ * @private
1163
+ */
1164
+ startLoop(cb) {
1165
+ this._loop = true;
1166
+ do
1167
+ switch (this._state) {
1168
+ case GET_INFO:
1169
+ this.getInfo(cb);
1170
+ break;
1171
+ case GET_PAYLOAD_LENGTH_16:
1172
+ this.getPayloadLength16(cb);
1173
+ break;
1174
+ case GET_PAYLOAD_LENGTH_64:
1175
+ this.getPayloadLength64(cb);
1176
+ break;
1177
+ case GET_MASK:
1178
+ this.getMask();
1179
+ break;
1180
+ case GET_DATA:
1181
+ this.getData(cb);
1182
+ break;
1183
+ case INFLATING:
1184
+ case DEFER_EVENT:
1185
+ this._loop = false;
1186
+ return;
1187
+ }
1188
+ while (this._loop);
1189
+ if (!this._errored) cb();
1190
+ }
1191
+ /**
1192
+ * Reads the first two bytes of a frame.
1193
+ *
1194
+ * @param {Function} cb Callback
1195
+ * @private
1196
+ */
1197
+ getInfo(cb) {
1198
+ if (this._bufferedBytes < 2) {
1199
+ this._loop = false;
1200
+ return;
1201
+ }
1202
+ const buf = this.consume(2);
1203
+ if ((buf[0] & 48) !== 0) {
1204
+ cb(this.createError(RangeError, "RSV2 and RSV3 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_2_3"));
1205
+ return;
1206
+ }
1207
+ const compressed = (buf[0] & 64) === 64;
1208
+ if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
1209
+ cb(this.createError(RangeError, "RSV1 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_1"));
1210
+ return;
1211
+ }
1212
+ this._fin = (buf[0] & 128) === 128;
1213
+ this._opcode = buf[0] & 15;
1214
+ this._payloadLength = buf[1] & 127;
1215
+ if (this._opcode === 0) {
1216
+ if (compressed) {
1217
+ cb(this.createError(RangeError, "RSV1 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_1"));
1218
+ return;
1219
+ }
1220
+ if (!this._fragmented) {
1221
+ cb(this.createError(RangeError, "invalid opcode 0", true, 1002, "WS_ERR_INVALID_OPCODE"));
1222
+ return;
1223
+ }
1224
+ this._opcode = this._fragmented;
1225
+ } else if (this._opcode === 1 || this._opcode === 2) {
1226
+ if (this._fragmented) {
1227
+ cb(this.createError(RangeError, `invalid opcode ${this._opcode}`, true, 1002, "WS_ERR_INVALID_OPCODE"));
1228
+ return;
1229
+ }
1230
+ this._compressed = compressed;
1231
+ } else if (this._opcode > 7 && this._opcode < 11) {
1232
+ if (!this._fin) {
1233
+ cb(this.createError(RangeError, "FIN must be set", true, 1002, "WS_ERR_EXPECTED_FIN"));
1234
+ return;
1235
+ }
1236
+ if (compressed) {
1237
+ cb(this.createError(RangeError, "RSV1 must be clear", true, 1002, "WS_ERR_UNEXPECTED_RSV_1"));
1238
+ return;
1239
+ }
1240
+ if (this._payloadLength > 125 || this._opcode === 8 && this._payloadLength === 1) {
1241
+ cb(this.createError(RangeError, `invalid payload length ${this._payloadLength}`, true, 1002, "WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH"));
1242
+ return;
1243
+ }
1244
+ } else {
1245
+ cb(this.createError(RangeError, `invalid opcode ${this._opcode}`, true, 1002, "WS_ERR_INVALID_OPCODE"));
1246
+ return;
1247
+ }
1248
+ if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
1249
+ this._masked = (buf[1] & 128) === 128;
1250
+ if (this._isServer) {
1251
+ if (!this._masked) {
1252
+ cb(this.createError(RangeError, "MASK must be set", true, 1002, "WS_ERR_EXPECTED_MASK"));
1253
+ return;
1254
+ }
1255
+ } else if (this._masked) {
1256
+ cb(this.createError(RangeError, "MASK must be clear", true, 1002, "WS_ERR_UNEXPECTED_MASK"));
1257
+ return;
1258
+ }
1259
+ if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
1260
+ else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
1261
+ else this.haveLength(cb);
1262
+ }
1263
+ /**
1264
+ * Gets extended payload length (7+16).
1265
+ *
1266
+ * @param {Function} cb Callback
1267
+ * @private
1268
+ */
1269
+ getPayloadLength16(cb) {
1270
+ if (this._bufferedBytes < 2) {
1271
+ this._loop = false;
1272
+ return;
1273
+ }
1274
+ this._payloadLength = this.consume(2).readUInt16BE(0);
1275
+ this.haveLength(cb);
1276
+ }
1277
+ /**
1278
+ * Gets extended payload length (7+64).
1279
+ *
1280
+ * @param {Function} cb Callback
1281
+ * @private
1282
+ */
1283
+ getPayloadLength64(cb) {
1284
+ if (this._bufferedBytes < 8) {
1285
+ this._loop = false;
1286
+ return;
1287
+ }
1288
+ const buf = this.consume(8);
1289
+ const num = buf.readUInt32BE(0);
1290
+ if (num > Math.pow(2, 21) - 1) {
1291
+ cb(this.createError(RangeError, "Unsupported WebSocket frame: payload length > 2^53 - 1", false, 1009, "WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH"));
1292
+ return;
1293
+ }
1294
+ this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
1295
+ this.haveLength(cb);
1296
+ }
1297
+ /**
1298
+ * Payload length has been read.
1299
+ *
1300
+ * @param {Function} cb Callback
1301
+ * @private
1302
+ */
1303
+ haveLength(cb) {
1304
+ if (this._payloadLength && this._opcode < 8) {
1305
+ this._totalPayloadLength += this._payloadLength;
1306
+ if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
1307
+ cb(this.createError(RangeError, "Max payload size exceeded", false, 1009, "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"));
1308
+ return;
1309
+ }
1310
+ }
1311
+ if (this._masked) this._state = GET_MASK;
1312
+ else this._state = GET_DATA;
1313
+ }
1314
+ /**
1315
+ * Reads mask bytes.
1316
+ *
1317
+ * @private
1318
+ */
1319
+ getMask() {
1320
+ if (this._bufferedBytes < 4) {
1321
+ this._loop = false;
1322
+ return;
1323
+ }
1324
+ this._mask = this.consume(4);
1325
+ this._state = GET_DATA;
1326
+ }
1327
+ /**
1328
+ * Reads data bytes.
1329
+ *
1330
+ * @param {Function} cb Callback
1331
+ * @private
1332
+ */
1333
+ getData(cb) {
1334
+ let data = EMPTY_BUFFER;
1335
+ if (this._payloadLength) {
1336
+ if (this._bufferedBytes < this._payloadLength) {
1337
+ this._loop = false;
1338
+ return;
1339
+ }
1340
+ data = this.consume(this._payloadLength);
1341
+ if (this._masked && (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0) unmask(data, this._mask);
1342
+ }
1343
+ if (this._opcode > 7) {
1344
+ this.controlMessage(data, cb);
1345
+ return;
1346
+ }
1347
+ if (this._compressed) {
1348
+ this._state = INFLATING;
1349
+ this.decompress(data, cb);
1350
+ return;
1351
+ }
1352
+ if (data.length) {
1353
+ this._messageLength = this._totalPayloadLength;
1354
+ this._fragments.push(data);
1355
+ }
1356
+ this.dataMessage(cb);
1357
+ }
1358
+ /**
1359
+ * Decompresses data.
1360
+ *
1361
+ * @param {Buffer} data Compressed data
1362
+ * @param {Function} cb Callback
1363
+ * @private
1364
+ */
1365
+ decompress(data, cb) {
1366
+ this._extensions[PerMessageDeflate.extensionName].decompress(data, this._fin, (err, buf) => {
1367
+ if (err) return cb(err);
1368
+ if (buf.length) {
1369
+ this._messageLength += buf.length;
1370
+ if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
1371
+ cb(this.createError(RangeError, "Max payload size exceeded", false, 1009, "WS_ERR_UNSUPPORTED_MESSAGE_LENGTH"));
1372
+ return;
1373
+ }
1374
+ this._fragments.push(buf);
1375
+ }
1376
+ this.dataMessage(cb);
1377
+ if (this._state === GET_INFO) this.startLoop(cb);
1378
+ });
1379
+ }
1380
+ /**
1381
+ * Handles a data message.
1382
+ *
1383
+ * @param {Function} cb Callback
1384
+ * @private
1385
+ */
1386
+ dataMessage(cb) {
1387
+ if (!this._fin) {
1388
+ this._state = GET_INFO;
1389
+ return;
1390
+ }
1391
+ const messageLength = this._messageLength;
1392
+ const fragments = this._fragments;
1393
+ this._totalPayloadLength = 0;
1394
+ this._messageLength = 0;
1395
+ this._fragmented = 0;
1396
+ this._fragments = [];
1397
+ if (this._opcode === 2) {
1398
+ let data;
1399
+ if (this._binaryType === "nodebuffer") data = concat(fragments, messageLength);
1400
+ else if (this._binaryType === "arraybuffer") data = toArrayBuffer(concat(fragments, messageLength));
1401
+ else if (this._binaryType === "blob") data = new Blob(fragments);
1402
+ else data = fragments;
1403
+ if (this._allowSynchronousEvents) {
1404
+ this.emit("message", data, true);
1405
+ this._state = GET_INFO;
1406
+ } else {
1407
+ this._state = DEFER_EVENT;
1408
+ setImmediate(() => {
1409
+ this.emit("message", data, true);
1410
+ this._state = GET_INFO;
1411
+ this.startLoop(cb);
1412
+ });
1413
+ }
1414
+ } else {
1415
+ const buf = concat(fragments, messageLength);
1416
+ if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
1417
+ cb(this.createError(Error, "invalid UTF-8 sequence", true, 1007, "WS_ERR_INVALID_UTF8"));
1418
+ return;
1419
+ }
1420
+ if (this._state === INFLATING || this._allowSynchronousEvents) {
1421
+ this.emit("message", buf, false);
1422
+ this._state = GET_INFO;
1423
+ } else {
1424
+ this._state = DEFER_EVENT;
1425
+ setImmediate(() => {
1426
+ this.emit("message", buf, false);
1427
+ this._state = GET_INFO;
1428
+ this.startLoop(cb);
1429
+ });
1430
+ }
1431
+ }
1432
+ }
1433
+ /**
1434
+ * Handles a control message.
1435
+ *
1436
+ * @param {Buffer} data Data to handle
1437
+ * @return {(Error|RangeError|undefined)} A possible error
1438
+ * @private
1439
+ */
1440
+ controlMessage(data, cb) {
1441
+ if (this._opcode === 8) {
1442
+ if (data.length === 0) {
1443
+ this._loop = false;
1444
+ this.emit("conclude", 1005, EMPTY_BUFFER);
1445
+ this.end();
1446
+ } else {
1447
+ const code = data.readUInt16BE(0);
1448
+ if (!isValidStatusCode(code)) {
1449
+ cb(this.createError(RangeError, `invalid status code ${code}`, true, 1002, "WS_ERR_INVALID_CLOSE_CODE"));
1450
+ return;
1451
+ }
1452
+ const buf = new FastBuffer(data.buffer, data.byteOffset + 2, data.length - 2);
1453
+ if (!this._skipUTF8Validation && !isValidUTF8(buf)) {
1454
+ cb(this.createError(Error, "invalid UTF-8 sequence", true, 1007, "WS_ERR_INVALID_UTF8"));
1455
+ return;
1456
+ }
1457
+ this._loop = false;
1458
+ this.emit("conclude", code, buf);
1459
+ this.end();
1460
+ }
1461
+ this._state = GET_INFO;
1462
+ return;
1463
+ }
1464
+ if (this._allowSynchronousEvents) {
1465
+ this.emit(this._opcode === 9 ? "ping" : "pong", data);
1466
+ this._state = GET_INFO;
1467
+ } else {
1468
+ this._state = DEFER_EVENT;
1469
+ setImmediate(() => {
1470
+ this.emit(this._opcode === 9 ? "ping" : "pong", data);
1471
+ this._state = GET_INFO;
1472
+ this.startLoop(cb);
1473
+ });
1474
+ }
1475
+ }
1476
+ /**
1477
+ * Builds an error object.
1478
+ *
1479
+ * @param {function(new:Error|RangeError)} ErrorCtor The error constructor
1480
+ * @param {String} message The error message
1481
+ * @param {Boolean} prefix Specifies whether or not to add a default prefix to
1482
+ * `message`
1483
+ * @param {Number} statusCode The status code
1484
+ * @param {String} errorCode The exposed error code
1485
+ * @return {(Error|RangeError)} The error
1486
+ * @private
1487
+ */
1488
+ createError(ErrorCtor, message, prefix, statusCode, errorCode) {
1489
+ this._loop = false;
1490
+ this._errored = true;
1491
+ const err = new ErrorCtor(prefix ? `Invalid WebSocket frame: ${message}` : message);
1492
+ Error.captureStackTrace(err, this.createError);
1493
+ err.code = errorCode;
1494
+ err[kStatusCode] = statusCode;
1495
+ return err;
1496
+ }
1497
+ };
1498
+ module.exports = Receiver;
1499
+ }));
1500
+
1501
+ //#endregion
1502
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js
1503
+ var require_sender = /* @__PURE__ */ __commonJSMin(((exports, module) => {
1504
+ const { Duplex: Duplex$3 } = __require("stream");
1505
+ const { randomFillSync } = __require("crypto");
1506
+ const PerMessageDeflate = require_permessage_deflate();
1507
+ const { EMPTY_BUFFER, kWebSocket, NOOP } = require_constants();
1508
+ const { isBlob, isValidStatusCode } = require_validation();
1509
+ const { mask: applyMask, toBuffer } = require_buffer_util();
1510
+ const kByteLength = Symbol("kByteLength");
1511
+ const maskBuffer = Buffer.alloc(4);
1512
+ const RANDOM_POOL_SIZE = 8 * 1024;
1513
+ let randomPool;
1514
+ let randomPoolPointer = RANDOM_POOL_SIZE;
1515
+ const DEFAULT = 0;
1516
+ const DEFLATING = 1;
1517
+ const GET_BLOB_DATA = 2;
1518
+ /**
1519
+ * HyBi Sender implementation.
1520
+ */
1521
+ var Sender = class Sender {
1522
+ /**
1523
+ * Creates a Sender instance.
1524
+ *
1525
+ * @param {Duplex} socket The connection socket
1526
+ * @param {Object} [extensions] An object containing the negotiated extensions
1527
+ * @param {Function} [generateMask] The function used to generate the masking
1528
+ * key
1529
+ */
1530
+ constructor(socket, extensions, generateMask) {
1531
+ this._extensions = extensions || {};
1532
+ if (generateMask) {
1533
+ this._generateMask = generateMask;
1534
+ this._maskBuffer = Buffer.alloc(4);
1535
+ }
1536
+ this._socket = socket;
1537
+ this._firstFragment = true;
1538
+ this._compress = false;
1539
+ this._bufferedBytes = 0;
1540
+ this._queue = [];
1541
+ this._state = DEFAULT;
1542
+ this.onerror = NOOP;
1543
+ this[kWebSocket] = void 0;
1544
+ }
1545
+ /**
1546
+ * Frames a piece of data according to the HyBi WebSocket protocol.
1547
+ *
1548
+ * @param {(Buffer|String)} data The data to frame
1549
+ * @param {Object} options Options object
1550
+ * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1551
+ * FIN bit
1552
+ * @param {Function} [options.generateMask] The function used to generate the
1553
+ * masking key
1554
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1555
+ * `data`
1556
+ * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
1557
+ * key
1558
+ * @param {Number} options.opcode The opcode
1559
+ * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1560
+ * modified
1561
+ * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1562
+ * RSV1 bit
1563
+ * @return {(Buffer|String)[]} The framed data
1564
+ * @public
1565
+ */
1566
+ static frame(data, options) {
1567
+ let mask;
1568
+ let merge = false;
1569
+ let offset = 2;
1570
+ let skipMasking = false;
1571
+ if (options.mask) {
1572
+ mask = options.maskBuffer || maskBuffer;
1573
+ if (options.generateMask) options.generateMask(mask);
1574
+ else {
1575
+ if (randomPoolPointer === RANDOM_POOL_SIZE) {
1576
+ /* istanbul ignore else */
1577
+ if (randomPool === void 0) randomPool = Buffer.alloc(RANDOM_POOL_SIZE);
1578
+ randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);
1579
+ randomPoolPointer = 0;
1580
+ }
1581
+ mask[0] = randomPool[randomPoolPointer++];
1582
+ mask[1] = randomPool[randomPoolPointer++];
1583
+ mask[2] = randomPool[randomPoolPointer++];
1584
+ mask[3] = randomPool[randomPoolPointer++];
1585
+ }
1586
+ skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;
1587
+ offset = 6;
1588
+ }
1589
+ let dataLength;
1590
+ if (typeof data === "string") if ((!options.mask || skipMasking) && options[kByteLength] !== void 0) dataLength = options[kByteLength];
1591
+ else {
1592
+ data = Buffer.from(data);
1593
+ dataLength = data.length;
1594
+ }
1595
+ else {
1596
+ dataLength = data.length;
1597
+ merge = options.mask && options.readOnly && !skipMasking;
1598
+ }
1599
+ let payloadLength = dataLength;
1600
+ if (dataLength >= 65536) {
1601
+ offset += 8;
1602
+ payloadLength = 127;
1603
+ } else if (dataLength > 125) {
1604
+ offset += 2;
1605
+ payloadLength = 126;
1606
+ }
1607
+ const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);
1608
+ target[0] = options.fin ? options.opcode | 128 : options.opcode;
1609
+ if (options.rsv1) target[0] |= 64;
1610
+ target[1] = payloadLength;
1611
+ if (payloadLength === 126) target.writeUInt16BE(dataLength, 2);
1612
+ else if (payloadLength === 127) {
1613
+ target[2] = target[3] = 0;
1614
+ target.writeUIntBE(dataLength, 4, 6);
1615
+ }
1616
+ if (!options.mask) return [target, data];
1617
+ target[1] |= 128;
1618
+ target[offset - 4] = mask[0];
1619
+ target[offset - 3] = mask[1];
1620
+ target[offset - 2] = mask[2];
1621
+ target[offset - 1] = mask[3];
1622
+ if (skipMasking) return [target, data];
1623
+ if (merge) {
1624
+ applyMask(data, mask, target, offset, dataLength);
1625
+ return [target];
1626
+ }
1627
+ applyMask(data, mask, data, 0, dataLength);
1628
+ return [target, data];
1629
+ }
1630
+ /**
1631
+ * Sends a close message to the other peer.
1632
+ *
1633
+ * @param {Number} [code] The status code component of the body
1634
+ * @param {(String|Buffer)} [data] The message component of the body
1635
+ * @param {Boolean} [mask=false] Specifies whether or not to mask the message
1636
+ * @param {Function} [cb] Callback
1637
+ * @public
1638
+ */
1639
+ close(code, data, mask, cb) {
1640
+ let buf;
1641
+ if (code === void 0) buf = EMPTY_BUFFER;
1642
+ else if (typeof code !== "number" || !isValidStatusCode(code)) throw new TypeError("First argument must be a valid error code number");
1643
+ else if (data === void 0 || !data.length) {
1644
+ buf = Buffer.allocUnsafe(2);
1645
+ buf.writeUInt16BE(code, 0);
1646
+ } else {
1647
+ const length = Buffer.byteLength(data);
1648
+ if (length > 123) throw new RangeError("The message must not be greater than 123 bytes");
1649
+ buf = Buffer.allocUnsafe(2 + length);
1650
+ buf.writeUInt16BE(code, 0);
1651
+ if (typeof data === "string") buf.write(data, 2);
1652
+ else buf.set(data, 2);
1653
+ }
1654
+ const options = {
1655
+ [kByteLength]: buf.length,
1656
+ fin: true,
1657
+ generateMask: this._generateMask,
1658
+ mask,
1659
+ maskBuffer: this._maskBuffer,
1660
+ opcode: 8,
1661
+ readOnly: false,
1662
+ rsv1: false
1663
+ };
1664
+ if (this._state !== DEFAULT) this.enqueue([
1665
+ this.dispatch,
1666
+ buf,
1667
+ false,
1668
+ options,
1669
+ cb
1670
+ ]);
1671
+ else this.sendFrame(Sender.frame(buf, options), cb);
1672
+ }
1673
+ /**
1674
+ * Sends a ping message to the other peer.
1675
+ *
1676
+ * @param {*} data The message to send
1677
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1678
+ * @param {Function} [cb] Callback
1679
+ * @public
1680
+ */
1681
+ ping(data, mask, cb) {
1682
+ let byteLength;
1683
+ let readOnly;
1684
+ if (typeof data === "string") {
1685
+ byteLength = Buffer.byteLength(data);
1686
+ readOnly = false;
1687
+ } else if (isBlob(data)) {
1688
+ byteLength = data.size;
1689
+ readOnly = false;
1690
+ } else {
1691
+ data = toBuffer(data);
1692
+ byteLength = data.length;
1693
+ readOnly = toBuffer.readOnly;
1694
+ }
1695
+ if (byteLength > 125) throw new RangeError("The data size must not be greater than 125 bytes");
1696
+ const options = {
1697
+ [kByteLength]: byteLength,
1698
+ fin: true,
1699
+ generateMask: this._generateMask,
1700
+ mask,
1701
+ maskBuffer: this._maskBuffer,
1702
+ opcode: 9,
1703
+ readOnly,
1704
+ rsv1: false
1705
+ };
1706
+ if (isBlob(data)) if (this._state !== DEFAULT) this.enqueue([
1707
+ this.getBlobData,
1708
+ data,
1709
+ false,
1710
+ options,
1711
+ cb
1712
+ ]);
1713
+ else this.getBlobData(data, false, options, cb);
1714
+ else if (this._state !== DEFAULT) this.enqueue([
1715
+ this.dispatch,
1716
+ data,
1717
+ false,
1718
+ options,
1719
+ cb
1720
+ ]);
1721
+ else this.sendFrame(Sender.frame(data, options), cb);
1722
+ }
1723
+ /**
1724
+ * Sends a pong message to the other peer.
1725
+ *
1726
+ * @param {*} data The message to send
1727
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1728
+ * @param {Function} [cb] Callback
1729
+ * @public
1730
+ */
1731
+ pong(data, mask, cb) {
1732
+ let byteLength;
1733
+ let readOnly;
1734
+ if (typeof data === "string") {
1735
+ byteLength = Buffer.byteLength(data);
1736
+ readOnly = false;
1737
+ } else if (isBlob(data)) {
1738
+ byteLength = data.size;
1739
+ readOnly = false;
1740
+ } else {
1741
+ data = toBuffer(data);
1742
+ byteLength = data.length;
1743
+ readOnly = toBuffer.readOnly;
1744
+ }
1745
+ if (byteLength > 125) throw new RangeError("The data size must not be greater than 125 bytes");
1746
+ const options = {
1747
+ [kByteLength]: byteLength,
1748
+ fin: true,
1749
+ generateMask: this._generateMask,
1750
+ mask,
1751
+ maskBuffer: this._maskBuffer,
1752
+ opcode: 10,
1753
+ readOnly,
1754
+ rsv1: false
1755
+ };
1756
+ if (isBlob(data)) if (this._state !== DEFAULT) this.enqueue([
1757
+ this.getBlobData,
1758
+ data,
1759
+ false,
1760
+ options,
1761
+ cb
1762
+ ]);
1763
+ else this.getBlobData(data, false, options, cb);
1764
+ else if (this._state !== DEFAULT) this.enqueue([
1765
+ this.dispatch,
1766
+ data,
1767
+ false,
1768
+ options,
1769
+ cb
1770
+ ]);
1771
+ else this.sendFrame(Sender.frame(data, options), cb);
1772
+ }
1773
+ /**
1774
+ * Sends a data message to the other peer.
1775
+ *
1776
+ * @param {*} data The message to send
1777
+ * @param {Object} options Options object
1778
+ * @param {Boolean} [options.binary=false] Specifies whether `data` is binary
1779
+ * or text
1780
+ * @param {Boolean} [options.compress=false] Specifies whether or not to
1781
+ * compress `data`
1782
+ * @param {Boolean} [options.fin=false] Specifies whether the fragment is the
1783
+ * last one
1784
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1785
+ * `data`
1786
+ * @param {Function} [cb] Callback
1787
+ * @public
1788
+ */
1789
+ send(data, options, cb) {
1790
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
1791
+ let opcode = options.binary ? 2 : 1;
1792
+ let rsv1 = options.compress;
1793
+ let byteLength;
1794
+ let readOnly;
1795
+ if (typeof data === "string") {
1796
+ byteLength = Buffer.byteLength(data);
1797
+ readOnly = false;
1798
+ } else if (isBlob(data)) {
1799
+ byteLength = data.size;
1800
+ readOnly = false;
1801
+ } else {
1802
+ data = toBuffer(data);
1803
+ byteLength = data.length;
1804
+ readOnly = toBuffer.readOnly;
1805
+ }
1806
+ if (this._firstFragment) {
1807
+ this._firstFragment = false;
1808
+ if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) rsv1 = byteLength >= perMessageDeflate._threshold;
1809
+ this._compress = rsv1;
1810
+ } else {
1811
+ rsv1 = false;
1812
+ opcode = 0;
1813
+ }
1814
+ if (options.fin) this._firstFragment = true;
1815
+ const opts = {
1816
+ [kByteLength]: byteLength,
1817
+ fin: options.fin,
1818
+ generateMask: this._generateMask,
1819
+ mask: options.mask,
1820
+ maskBuffer: this._maskBuffer,
1821
+ opcode,
1822
+ readOnly,
1823
+ rsv1
1824
+ };
1825
+ if (isBlob(data)) if (this._state !== DEFAULT) this.enqueue([
1826
+ this.getBlobData,
1827
+ data,
1828
+ this._compress,
1829
+ opts,
1830
+ cb
1831
+ ]);
1832
+ else this.getBlobData(data, this._compress, opts, cb);
1833
+ else if (this._state !== DEFAULT) this.enqueue([
1834
+ this.dispatch,
1835
+ data,
1836
+ this._compress,
1837
+ opts,
1838
+ cb
1839
+ ]);
1840
+ else this.dispatch(data, this._compress, opts, cb);
1841
+ }
1842
+ /**
1843
+ * Gets the contents of a blob as binary data.
1844
+ *
1845
+ * @param {Blob} blob The blob
1846
+ * @param {Boolean} [compress=false] Specifies whether or not to compress
1847
+ * the data
1848
+ * @param {Object} options Options object
1849
+ * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1850
+ * FIN bit
1851
+ * @param {Function} [options.generateMask] The function used to generate the
1852
+ * masking key
1853
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1854
+ * `data`
1855
+ * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
1856
+ * key
1857
+ * @param {Number} options.opcode The opcode
1858
+ * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1859
+ * modified
1860
+ * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1861
+ * RSV1 bit
1862
+ * @param {Function} [cb] Callback
1863
+ * @private
1864
+ */
1865
+ getBlobData(blob, compress, options, cb) {
1866
+ this._bufferedBytes += options[kByteLength];
1867
+ this._state = GET_BLOB_DATA;
1868
+ blob.arrayBuffer().then((arrayBuffer) => {
1869
+ if (this._socket.destroyed) {
1870
+ const err = /* @__PURE__ */ new Error("The socket was closed while the blob was being read");
1871
+ process.nextTick(callCallbacks, this, err, cb);
1872
+ return;
1873
+ }
1874
+ this._bufferedBytes -= options[kByteLength];
1875
+ const data = toBuffer(arrayBuffer);
1876
+ if (!compress) {
1877
+ this._state = DEFAULT;
1878
+ this.sendFrame(Sender.frame(data, options), cb);
1879
+ this.dequeue();
1880
+ } else this.dispatch(data, compress, options, cb);
1881
+ }).catch((err) => {
1882
+ process.nextTick(onError, this, err, cb);
1883
+ });
1884
+ }
1885
+ /**
1886
+ * Dispatches a message.
1887
+ *
1888
+ * @param {(Buffer|String)} data The message to send
1889
+ * @param {Boolean} [compress=false] Specifies whether or not to compress
1890
+ * `data`
1891
+ * @param {Object} options Options object
1892
+ * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1893
+ * FIN bit
1894
+ * @param {Function} [options.generateMask] The function used to generate the
1895
+ * masking key
1896
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1897
+ * `data`
1898
+ * @param {Buffer} [options.maskBuffer] The buffer used to store the masking
1899
+ * key
1900
+ * @param {Number} options.opcode The opcode
1901
+ * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1902
+ * modified
1903
+ * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1904
+ * RSV1 bit
1905
+ * @param {Function} [cb] Callback
1906
+ * @private
1907
+ */
1908
+ dispatch(data, compress, options, cb) {
1909
+ if (!compress) {
1910
+ this.sendFrame(Sender.frame(data, options), cb);
1911
+ return;
1912
+ }
1913
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
1914
+ this._bufferedBytes += options[kByteLength];
1915
+ this._state = DEFLATING;
1916
+ perMessageDeflate.compress(data, options.fin, (_, buf) => {
1917
+ if (this._socket.destroyed) {
1918
+ callCallbacks(this, /* @__PURE__ */ new Error("The socket was closed while data was being compressed"), cb);
1919
+ return;
1920
+ }
1921
+ this._bufferedBytes -= options[kByteLength];
1922
+ this._state = DEFAULT;
1923
+ options.readOnly = false;
1924
+ this.sendFrame(Sender.frame(buf, options), cb);
1925
+ this.dequeue();
1926
+ });
1927
+ }
1928
+ /**
1929
+ * Executes queued send operations.
1930
+ *
1931
+ * @private
1932
+ */
1933
+ dequeue() {
1934
+ while (this._state === DEFAULT && this._queue.length) {
1935
+ const params = this._queue.shift();
1936
+ this._bufferedBytes -= params[3][kByteLength];
1937
+ Reflect.apply(params[0], this, params.slice(1));
1938
+ }
1939
+ }
1940
+ /**
1941
+ * Enqueues a send operation.
1942
+ *
1943
+ * @param {Array} params Send operation parameters.
1944
+ * @private
1945
+ */
1946
+ enqueue(params) {
1947
+ this._bufferedBytes += params[3][kByteLength];
1948
+ this._queue.push(params);
1949
+ }
1950
+ /**
1951
+ * Sends a frame.
1952
+ *
1953
+ * @param {(Buffer | String)[]} list The frame to send
1954
+ * @param {Function} [cb] Callback
1955
+ * @private
1956
+ */
1957
+ sendFrame(list, cb) {
1958
+ if (list.length === 2) {
1959
+ this._socket.cork();
1960
+ this._socket.write(list[0]);
1961
+ this._socket.write(list[1], cb);
1962
+ this._socket.uncork();
1963
+ } else this._socket.write(list[0], cb);
1964
+ }
1965
+ };
1966
+ module.exports = Sender;
1967
+ /**
1968
+ * Calls queued callbacks with an error.
1969
+ *
1970
+ * @param {Sender} sender The `Sender` instance
1971
+ * @param {Error} err The error to call the callbacks with
1972
+ * @param {Function} [cb] The first callback
1973
+ * @private
1974
+ */
1975
+ function callCallbacks(sender, err, cb) {
1976
+ if (typeof cb === "function") cb(err);
1977
+ for (let i = 0; i < sender._queue.length; i++) {
1978
+ const params = sender._queue[i];
1979
+ const callback = params[params.length - 1];
1980
+ if (typeof callback === "function") callback(err);
1981
+ }
1982
+ }
1983
+ /**
1984
+ * Handles a `Sender` error.
1985
+ *
1986
+ * @param {Sender} sender The `Sender` instance
1987
+ * @param {Error} err The error
1988
+ * @param {Function} [cb] The first pending callback
1989
+ * @private
1990
+ */
1991
+ function onError(sender, err, cb) {
1992
+ callCallbacks(sender, err, cb);
1993
+ sender.onerror(err);
1994
+ }
1995
+ }));
1996
+
1997
+ //#endregion
1998
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js
1999
+ var require_event_target = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2000
+ const { kForOnEventAttribute, kListener } = require_constants();
2001
+ const kCode = Symbol("kCode");
2002
+ const kData = Symbol("kData");
2003
+ const kError = Symbol("kError");
2004
+ const kMessage = Symbol("kMessage");
2005
+ const kReason = Symbol("kReason");
2006
+ const kTarget = Symbol("kTarget");
2007
+ const kType = Symbol("kType");
2008
+ const kWasClean = Symbol("kWasClean");
2009
+ /**
2010
+ * Class representing an event.
2011
+ */
2012
+ var Event = class {
2013
+ /**
2014
+ * Create a new `Event`.
2015
+ *
2016
+ * @param {String} type The name of the event
2017
+ * @throws {TypeError} If the `type` argument is not specified
2018
+ */
2019
+ constructor(type) {
2020
+ this[kTarget] = null;
2021
+ this[kType] = type;
2022
+ }
2023
+ /**
2024
+ * @type {*}
2025
+ */
2026
+ get target() {
2027
+ return this[kTarget];
2028
+ }
2029
+ /**
2030
+ * @type {String}
2031
+ */
2032
+ get type() {
2033
+ return this[kType];
2034
+ }
2035
+ };
2036
+ Object.defineProperty(Event.prototype, "target", { enumerable: true });
2037
+ Object.defineProperty(Event.prototype, "type", { enumerable: true });
2038
+ /**
2039
+ * Class representing a close event.
2040
+ *
2041
+ * @extends Event
2042
+ */
2043
+ var CloseEvent = class extends Event {
2044
+ /**
2045
+ * Create a new `CloseEvent`.
2046
+ *
2047
+ * @param {String} type The name of the event
2048
+ * @param {Object} [options] A dictionary object that allows for setting
2049
+ * attributes via object members of the same name
2050
+ * @param {Number} [options.code=0] The status code explaining why the
2051
+ * connection was closed
2052
+ * @param {String} [options.reason=''] A human-readable string explaining why
2053
+ * the connection was closed
2054
+ * @param {Boolean} [options.wasClean=false] Indicates whether or not the
2055
+ * connection was cleanly closed
2056
+ */
2057
+ constructor(type, options = {}) {
2058
+ super(type);
2059
+ this[kCode] = options.code === void 0 ? 0 : options.code;
2060
+ this[kReason] = options.reason === void 0 ? "" : options.reason;
2061
+ this[kWasClean] = options.wasClean === void 0 ? false : options.wasClean;
2062
+ }
2063
+ /**
2064
+ * @type {Number}
2065
+ */
2066
+ get code() {
2067
+ return this[kCode];
2068
+ }
2069
+ /**
2070
+ * @type {String}
2071
+ */
2072
+ get reason() {
2073
+ return this[kReason];
2074
+ }
2075
+ /**
2076
+ * @type {Boolean}
2077
+ */
2078
+ get wasClean() {
2079
+ return this[kWasClean];
2080
+ }
2081
+ };
2082
+ Object.defineProperty(CloseEvent.prototype, "code", { enumerable: true });
2083
+ Object.defineProperty(CloseEvent.prototype, "reason", { enumerable: true });
2084
+ Object.defineProperty(CloseEvent.prototype, "wasClean", { enumerable: true });
2085
+ /**
2086
+ * Class representing an error event.
2087
+ *
2088
+ * @extends Event
2089
+ */
2090
+ var ErrorEvent = class extends Event {
2091
+ /**
2092
+ * Create a new `ErrorEvent`.
2093
+ *
2094
+ * @param {String} type The name of the event
2095
+ * @param {Object} [options] A dictionary object that allows for setting
2096
+ * attributes via object members of the same name
2097
+ * @param {*} [options.error=null] The error that generated this event
2098
+ * @param {String} [options.message=''] The error message
2099
+ */
2100
+ constructor(type, options = {}) {
2101
+ super(type);
2102
+ this[kError] = options.error === void 0 ? null : options.error;
2103
+ this[kMessage] = options.message === void 0 ? "" : options.message;
2104
+ }
2105
+ /**
2106
+ * @type {*}
2107
+ */
2108
+ get error() {
2109
+ return this[kError];
2110
+ }
2111
+ /**
2112
+ * @type {String}
2113
+ */
2114
+ get message() {
2115
+ return this[kMessage];
2116
+ }
2117
+ };
2118
+ Object.defineProperty(ErrorEvent.prototype, "error", { enumerable: true });
2119
+ Object.defineProperty(ErrorEvent.prototype, "message", { enumerable: true });
2120
+ /**
2121
+ * Class representing a message event.
2122
+ *
2123
+ * @extends Event
2124
+ */
2125
+ var MessageEvent = class extends Event {
2126
+ /**
2127
+ * Create a new `MessageEvent`.
2128
+ *
2129
+ * @param {String} type The name of the event
2130
+ * @param {Object} [options] A dictionary object that allows for setting
2131
+ * attributes via object members of the same name
2132
+ * @param {*} [options.data=null] The message content
2133
+ */
2134
+ constructor(type, options = {}) {
2135
+ super(type);
2136
+ this[kData] = options.data === void 0 ? null : options.data;
2137
+ }
2138
+ /**
2139
+ * @type {*}
2140
+ */
2141
+ get data() {
2142
+ return this[kData];
2143
+ }
2144
+ };
2145
+ Object.defineProperty(MessageEvent.prototype, "data", { enumerable: true });
2146
+ /**
2147
+ * This provides methods for emulating the `EventTarget` interface. It's not
2148
+ * meant to be used directly.
2149
+ *
2150
+ * @mixin
2151
+ */
2152
+ const EventTarget = {
2153
+ addEventListener(type, handler, options = {}) {
2154
+ for (const listener of this.listeners(type)) if (!options[kForOnEventAttribute] && listener[kListener] === handler && !listener[kForOnEventAttribute]) return;
2155
+ let wrapper;
2156
+ if (type === "message") wrapper = function onMessage(data, isBinary) {
2157
+ const event = new MessageEvent("message", { data: isBinary ? data : data.toString() });
2158
+ event[kTarget] = this;
2159
+ callListener(handler, this, event);
2160
+ };
2161
+ else if (type === "close") wrapper = function onClose(code, message) {
2162
+ const event = new CloseEvent("close", {
2163
+ code,
2164
+ reason: message.toString(),
2165
+ wasClean: this._closeFrameReceived && this._closeFrameSent
2166
+ });
2167
+ event[kTarget] = this;
2168
+ callListener(handler, this, event);
2169
+ };
2170
+ else if (type === "error") wrapper = function onError(error) {
2171
+ const event = new ErrorEvent("error", {
2172
+ error,
2173
+ message: error.message
2174
+ });
2175
+ event[kTarget] = this;
2176
+ callListener(handler, this, event);
2177
+ };
2178
+ else if (type === "open") wrapper = function onOpen() {
2179
+ const event = new Event("open");
2180
+ event[kTarget] = this;
2181
+ callListener(handler, this, event);
2182
+ };
2183
+ else return;
2184
+ wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
2185
+ wrapper[kListener] = handler;
2186
+ if (options.once) this.once(type, wrapper);
2187
+ else this.on(type, wrapper);
2188
+ },
2189
+ removeEventListener(type, handler) {
2190
+ for (const listener of this.listeners(type)) if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {
2191
+ this.removeListener(type, listener);
2192
+ break;
2193
+ }
2194
+ }
2195
+ };
2196
+ module.exports = {
2197
+ CloseEvent,
2198
+ ErrorEvent,
2199
+ Event,
2200
+ EventTarget,
2201
+ MessageEvent
2202
+ };
2203
+ /**
2204
+ * Call an event listener
2205
+ *
2206
+ * @param {(Function|Object)} listener The listener to call
2207
+ * @param {*} thisArg The value to use as `this`` when calling the listener
2208
+ * @param {Event} event The event to pass to the listener
2209
+ * @private
2210
+ */
2211
+ function callListener(listener, thisArg, event) {
2212
+ if (typeof listener === "object" && listener.handleEvent) listener.handleEvent.call(listener, event);
2213
+ else listener.call(thisArg, event);
2214
+ }
2215
+ }));
2216
+
2217
+ //#endregion
2218
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js
2219
+ var require_extension = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2220
+ const { tokenChars } = require_validation();
2221
+ /**
2222
+ * Adds an offer to the map of extension offers or a parameter to the map of
2223
+ * parameters.
2224
+ *
2225
+ * @param {Object} dest The map of extension offers or parameters
2226
+ * @param {String} name The extension or parameter name
2227
+ * @param {(Object|Boolean|String)} elem The extension parameters or the
2228
+ * parameter value
2229
+ * @private
2230
+ */
2231
+ function push(dest, name, elem) {
2232
+ if (dest[name] === void 0) dest[name] = [elem];
2233
+ else dest[name].push(elem);
2234
+ }
2235
+ /**
2236
+ * Parses the `Sec-WebSocket-Extensions` header into an object.
2237
+ *
2238
+ * @param {String} header The field value of the header
2239
+ * @return {Object} The parsed object
2240
+ * @public
2241
+ */
2242
+ function parse(header) {
2243
+ const offers = Object.create(null);
2244
+ let params = Object.create(null);
2245
+ let mustUnescape = false;
2246
+ let isEscaping = false;
2247
+ let inQuotes = false;
2248
+ let extensionName;
2249
+ let paramName;
2250
+ let start = -1;
2251
+ let code = -1;
2252
+ let end = -1;
2253
+ let i = 0;
2254
+ for (; i < header.length; i++) {
2255
+ code = header.charCodeAt(i);
2256
+ if (extensionName === void 0) if (end === -1 && tokenChars[code] === 1) {
2257
+ if (start === -1) start = i;
2258
+ } else if (i !== 0 && (code === 32 || code === 9)) {
2259
+ if (end === -1 && start !== -1) end = i;
2260
+ } else if (code === 59 || code === 44) {
2261
+ if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
2262
+ if (end === -1) end = i;
2263
+ const name = header.slice(start, end);
2264
+ if (code === 44) {
2265
+ push(offers, name, params);
2266
+ params = Object.create(null);
2267
+ } else extensionName = name;
2268
+ start = end = -1;
2269
+ } else throw new SyntaxError(`Unexpected character at index ${i}`);
2270
+ else if (paramName === void 0) if (end === -1 && tokenChars[code] === 1) {
2271
+ if (start === -1) start = i;
2272
+ } else if (code === 32 || code === 9) {
2273
+ if (end === -1 && start !== -1) end = i;
2274
+ } else if (code === 59 || code === 44) {
2275
+ if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
2276
+ if (end === -1) end = i;
2277
+ push(params, header.slice(start, end), true);
2278
+ if (code === 44) {
2279
+ push(offers, extensionName, params);
2280
+ params = Object.create(null);
2281
+ extensionName = void 0;
2282
+ }
2283
+ start = end = -1;
2284
+ } else if (code === 61 && start !== -1 && end === -1) {
2285
+ paramName = header.slice(start, i);
2286
+ start = end = -1;
2287
+ } else throw new SyntaxError(`Unexpected character at index ${i}`);
2288
+ else if (isEscaping) {
2289
+ if (tokenChars[code] !== 1) throw new SyntaxError(`Unexpected character at index ${i}`);
2290
+ if (start === -1) start = i;
2291
+ else if (!mustUnescape) mustUnescape = true;
2292
+ isEscaping = false;
2293
+ } else if (inQuotes) if (tokenChars[code] === 1) {
2294
+ if (start === -1) start = i;
2295
+ } else if (code === 34 && start !== -1) {
2296
+ inQuotes = false;
2297
+ end = i;
2298
+ } else if (code === 92) isEscaping = true;
2299
+ else throw new SyntaxError(`Unexpected character at index ${i}`);
2300
+ else if (code === 34 && header.charCodeAt(i - 1) === 61) inQuotes = true;
2301
+ else if (end === -1 && tokenChars[code] === 1) {
2302
+ if (start === -1) start = i;
2303
+ } else if (start !== -1 && (code === 32 || code === 9)) {
2304
+ if (end === -1) end = i;
2305
+ } else if (code === 59 || code === 44) {
2306
+ if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
2307
+ if (end === -1) end = i;
2308
+ let value = header.slice(start, end);
2309
+ if (mustUnescape) {
2310
+ value = value.replace(/\\/g, "");
2311
+ mustUnescape = false;
2312
+ }
2313
+ push(params, paramName, value);
2314
+ if (code === 44) {
2315
+ push(offers, extensionName, params);
2316
+ params = Object.create(null);
2317
+ extensionName = void 0;
2318
+ }
2319
+ paramName = void 0;
2320
+ start = end = -1;
2321
+ } else throw new SyntaxError(`Unexpected character at index ${i}`);
2322
+ }
2323
+ if (start === -1 || inQuotes || code === 32 || code === 9) throw new SyntaxError("Unexpected end of input");
2324
+ if (end === -1) end = i;
2325
+ const token = header.slice(start, end);
2326
+ if (extensionName === void 0) push(offers, token, params);
2327
+ else {
2328
+ if (paramName === void 0) push(params, token, true);
2329
+ else if (mustUnescape) push(params, paramName, token.replace(/\\/g, ""));
2330
+ else push(params, paramName, token);
2331
+ push(offers, extensionName, params);
2332
+ }
2333
+ return offers;
2334
+ }
2335
+ /**
2336
+ * Builds the `Sec-WebSocket-Extensions` header field value.
2337
+ *
2338
+ * @param {Object} extensions The map of extensions and parameters to format
2339
+ * @return {String} A string representing the given object
2340
+ * @public
2341
+ */
2342
+ function format(extensions) {
2343
+ return Object.keys(extensions).map((extension) => {
2344
+ let configurations = extensions[extension];
2345
+ if (!Array.isArray(configurations)) configurations = [configurations];
2346
+ return configurations.map((params) => {
2347
+ return [extension].concat(Object.keys(params).map((k) => {
2348
+ let values = params[k];
2349
+ if (!Array.isArray(values)) values = [values];
2350
+ return values.map((v) => v === true ? k : `${k}=${v}`).join("; ");
2351
+ })).join("; ");
2352
+ }).join(", ");
2353
+ }).join(", ");
2354
+ }
2355
+ module.exports = {
2356
+ format,
2357
+ parse
2358
+ };
2359
+ }));
2360
+
2361
+ //#endregion
2362
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js
2363
+ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
2364
+ const EventEmitter$2 = __require("events");
2365
+ const https = __require("https");
2366
+ const http$1 = __require("http");
2367
+ const net = __require("net");
2368
+ const tls = __require("tls");
2369
+ const { randomBytes, createHash: createHash$1 } = __require("crypto");
2370
+ const { Duplex: Duplex$2, Readable } = __require("stream");
2371
+ const { URL } = __require("url");
2372
+ const PerMessageDeflate = require_permessage_deflate();
2373
+ const Receiver = require_receiver();
2374
+ const Sender = require_sender();
2375
+ const { isBlob } = require_validation();
2376
+ const { BINARY_TYPES, CLOSE_TIMEOUT, EMPTY_BUFFER, GUID, kForOnEventAttribute, kListener, kStatusCode, kWebSocket, NOOP } = require_constants();
2377
+ const { EventTarget: { addEventListener, removeEventListener } } = require_event_target();
2378
+ const { format, parse } = require_extension();
2379
+ const { toBuffer } = require_buffer_util();
2380
+ const kAborted = Symbol("kAborted");
2381
+ const protocolVersions = [8, 13];
2382
+ const readyStates = [
2383
+ "CONNECTING",
2384
+ "OPEN",
2385
+ "CLOSING",
2386
+ "CLOSED"
2387
+ ];
2388
+ const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
2389
+ /**
2390
+ * Class representing a WebSocket.
2391
+ *
2392
+ * @extends EventEmitter
2393
+ */
2394
+ var WebSocket = class WebSocket extends EventEmitter$2 {
2395
+ /**
2396
+ * Create a new `WebSocket`.
2397
+ *
2398
+ * @param {(String|URL)} address The URL to which to connect
2399
+ * @param {(String|String[])} [protocols] The subprotocols
2400
+ * @param {Object} [options] Connection options
2401
+ */
2402
+ constructor(address, protocols, options) {
2403
+ super();
2404
+ this._binaryType = BINARY_TYPES[0];
2405
+ this._closeCode = 1006;
2406
+ this._closeFrameReceived = false;
2407
+ this._closeFrameSent = false;
2408
+ this._closeMessage = EMPTY_BUFFER;
2409
+ this._closeTimer = null;
2410
+ this._errorEmitted = false;
2411
+ this._extensions = {};
2412
+ this._paused = false;
2413
+ this._protocol = "";
2414
+ this._readyState = WebSocket.CONNECTING;
2415
+ this._receiver = null;
2416
+ this._sender = null;
2417
+ this._socket = null;
2418
+ if (address !== null) {
2419
+ this._bufferedAmount = 0;
2420
+ this._isServer = false;
2421
+ this._redirects = 0;
2422
+ if (protocols === void 0) protocols = [];
2423
+ else if (!Array.isArray(protocols)) if (typeof protocols === "object" && protocols !== null) {
2424
+ options = protocols;
2425
+ protocols = [];
2426
+ } else protocols = [protocols];
2427
+ initAsClient(this, address, protocols, options);
2428
+ } else {
2429
+ this._autoPong = options.autoPong;
2430
+ this._closeTimeout = options.closeTimeout;
2431
+ this._isServer = true;
2432
+ }
2433
+ }
2434
+ /**
2435
+ * For historical reasons, the custom "nodebuffer" type is used by the default
2436
+ * instead of "blob".
2437
+ *
2438
+ * @type {String}
2439
+ */
2440
+ get binaryType() {
2441
+ return this._binaryType;
2442
+ }
2443
+ set binaryType(type) {
2444
+ if (!BINARY_TYPES.includes(type)) return;
2445
+ this._binaryType = type;
2446
+ if (this._receiver) this._receiver._binaryType = type;
2447
+ }
2448
+ /**
2449
+ * @type {Number}
2450
+ */
2451
+ get bufferedAmount() {
2452
+ if (!this._socket) return this._bufferedAmount;
2453
+ return this._socket._writableState.length + this._sender._bufferedBytes;
2454
+ }
2455
+ /**
2456
+ * @type {String}
2457
+ */
2458
+ get extensions() {
2459
+ return Object.keys(this._extensions).join();
2460
+ }
2461
+ /**
2462
+ * @type {Boolean}
2463
+ */
2464
+ get isPaused() {
2465
+ return this._paused;
2466
+ }
2467
+ /**
2468
+ * @type {Function}
2469
+ */
2470
+ /* istanbul ignore next */
2471
+ get onclose() {
2472
+ return null;
2473
+ }
2474
+ /**
2475
+ * @type {Function}
2476
+ */
2477
+ /* istanbul ignore next */
2478
+ get onerror() {
2479
+ return null;
2480
+ }
2481
+ /**
2482
+ * @type {Function}
2483
+ */
2484
+ /* istanbul ignore next */
2485
+ get onopen() {
2486
+ return null;
2487
+ }
2488
+ /**
2489
+ * @type {Function}
2490
+ */
2491
+ /* istanbul ignore next */
2492
+ get onmessage() {
2493
+ return null;
2494
+ }
2495
+ /**
2496
+ * @type {String}
2497
+ */
2498
+ get protocol() {
2499
+ return this._protocol;
2500
+ }
2501
+ /**
2502
+ * @type {Number}
2503
+ */
2504
+ get readyState() {
2505
+ return this._readyState;
2506
+ }
2507
+ /**
2508
+ * @type {String}
2509
+ */
2510
+ get url() {
2511
+ return this._url;
2512
+ }
2513
+ /**
2514
+ * Set up the socket and the internal resources.
2515
+ *
2516
+ * @param {Duplex} socket The network socket between the server and client
2517
+ * @param {Buffer} head The first packet of the upgraded stream
2518
+ * @param {Object} options Options object
2519
+ * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether
2520
+ * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
2521
+ * multiple times in the same tick
2522
+ * @param {Function} [options.generateMask] The function used to generate the
2523
+ * masking key
2524
+ * @param {Number} [options.maxPayload=0] The maximum allowed message size
2525
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
2526
+ * not to skip UTF-8 validation for text and close messages
2527
+ * @private
2528
+ */
2529
+ setSocket(socket, head, options) {
2530
+ const receiver = new Receiver({
2531
+ allowSynchronousEvents: options.allowSynchronousEvents,
2532
+ binaryType: this.binaryType,
2533
+ extensions: this._extensions,
2534
+ isServer: this._isServer,
2535
+ maxPayload: options.maxPayload,
2536
+ skipUTF8Validation: options.skipUTF8Validation
2537
+ });
2538
+ const sender = new Sender(socket, this._extensions, options.generateMask);
2539
+ this._receiver = receiver;
2540
+ this._sender = sender;
2541
+ this._socket = socket;
2542
+ receiver[kWebSocket] = this;
2543
+ sender[kWebSocket] = this;
2544
+ socket[kWebSocket] = this;
2545
+ receiver.on("conclude", receiverOnConclude);
2546
+ receiver.on("drain", receiverOnDrain);
2547
+ receiver.on("error", receiverOnError);
2548
+ receiver.on("message", receiverOnMessage);
2549
+ receiver.on("ping", receiverOnPing);
2550
+ receiver.on("pong", receiverOnPong);
2551
+ sender.onerror = senderOnError;
2552
+ if (socket.setTimeout) socket.setTimeout(0);
2553
+ if (socket.setNoDelay) socket.setNoDelay();
2554
+ if (head.length > 0) socket.unshift(head);
2555
+ socket.on("close", socketOnClose);
2556
+ socket.on("data", socketOnData);
2557
+ socket.on("end", socketOnEnd);
2558
+ socket.on("error", socketOnError);
2559
+ this._readyState = WebSocket.OPEN;
2560
+ this.emit("open");
2561
+ }
2562
+ /**
2563
+ * Emit the `'close'` event.
2564
+ *
2565
+ * @private
2566
+ */
2567
+ emitClose() {
2568
+ if (!this._socket) {
2569
+ this._readyState = WebSocket.CLOSED;
2570
+ this.emit("close", this._closeCode, this._closeMessage);
2571
+ return;
2572
+ }
2573
+ if (this._extensions[PerMessageDeflate.extensionName]) this._extensions[PerMessageDeflate.extensionName].cleanup();
2574
+ this._receiver.removeAllListeners();
2575
+ this._readyState = WebSocket.CLOSED;
2576
+ this.emit("close", this._closeCode, this._closeMessage);
2577
+ }
2578
+ /**
2579
+ * Start a closing handshake.
2580
+ *
2581
+ * +----------+ +-----------+ +----------+
2582
+ * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
2583
+ * | +----------+ +-----------+ +----------+ |
2584
+ * +----------+ +-----------+ |
2585
+ * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
2586
+ * +----------+ +-----------+ |
2587
+ * | | | +---+ |
2588
+ * +------------------------+-->|fin| - - - -
2589
+ * | +---+ | +---+
2590
+ * - - - - -|fin|<---------------------+
2591
+ * +---+
2592
+ *
2593
+ * @param {Number} [code] Status code explaining why the connection is closing
2594
+ * @param {(String|Buffer)} [data] The reason why the connection is
2595
+ * closing
2596
+ * @public
2597
+ */
2598
+ close(code, data) {
2599
+ if (this.readyState === WebSocket.CLOSED) return;
2600
+ if (this.readyState === WebSocket.CONNECTING) {
2601
+ abortHandshake(this, this._req, "WebSocket was closed before the connection was established");
2602
+ return;
2603
+ }
2604
+ if (this.readyState === WebSocket.CLOSING) {
2605
+ if (this._closeFrameSent && (this._closeFrameReceived || this._receiver._writableState.errorEmitted)) this._socket.end();
2606
+ return;
2607
+ }
2608
+ this._readyState = WebSocket.CLOSING;
2609
+ this._sender.close(code, data, !this._isServer, (err) => {
2610
+ if (err) return;
2611
+ this._closeFrameSent = true;
2612
+ if (this._closeFrameReceived || this._receiver._writableState.errorEmitted) this._socket.end();
2613
+ });
2614
+ setCloseTimer(this);
2615
+ }
2616
+ /**
2617
+ * Pause the socket.
2618
+ *
2619
+ * @public
2620
+ */
2621
+ pause() {
2622
+ if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) return;
2623
+ this._paused = true;
2624
+ this._socket.pause();
2625
+ }
2626
+ /**
2627
+ * Send a ping.
2628
+ *
2629
+ * @param {*} [data] The data to send
2630
+ * @param {Boolean} [mask] Indicates whether or not to mask `data`
2631
+ * @param {Function} [cb] Callback which is executed when the ping is sent
2632
+ * @public
2633
+ */
2634
+ ping(data, mask, cb) {
2635
+ if (this.readyState === WebSocket.CONNECTING) throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
2636
+ if (typeof data === "function") {
2637
+ cb = data;
2638
+ data = mask = void 0;
2639
+ } else if (typeof mask === "function") {
2640
+ cb = mask;
2641
+ mask = void 0;
2642
+ }
2643
+ if (typeof data === "number") data = data.toString();
2644
+ if (this.readyState !== WebSocket.OPEN) {
2645
+ sendAfterClose(this, data, cb);
2646
+ return;
2647
+ }
2648
+ if (mask === void 0) mask = !this._isServer;
2649
+ this._sender.ping(data || EMPTY_BUFFER, mask, cb);
2650
+ }
2651
+ /**
2652
+ * Send a pong.
2653
+ *
2654
+ * @param {*} [data] The data to send
2655
+ * @param {Boolean} [mask] Indicates whether or not to mask `data`
2656
+ * @param {Function} [cb] Callback which is executed when the pong is sent
2657
+ * @public
2658
+ */
2659
+ pong(data, mask, cb) {
2660
+ if (this.readyState === WebSocket.CONNECTING) throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
2661
+ if (typeof data === "function") {
2662
+ cb = data;
2663
+ data = mask = void 0;
2664
+ } else if (typeof mask === "function") {
2665
+ cb = mask;
2666
+ mask = void 0;
2667
+ }
2668
+ if (typeof data === "number") data = data.toString();
2669
+ if (this.readyState !== WebSocket.OPEN) {
2670
+ sendAfterClose(this, data, cb);
2671
+ return;
2672
+ }
2673
+ if (mask === void 0) mask = !this._isServer;
2674
+ this._sender.pong(data || EMPTY_BUFFER, mask, cb);
2675
+ }
2676
+ /**
2677
+ * Resume the socket.
2678
+ *
2679
+ * @public
2680
+ */
2681
+ resume() {
2682
+ if (this.readyState === WebSocket.CONNECTING || this.readyState === WebSocket.CLOSED) return;
2683
+ this._paused = false;
2684
+ if (!this._receiver._writableState.needDrain) this._socket.resume();
2685
+ }
2686
+ /**
2687
+ * Send a data message.
2688
+ *
2689
+ * @param {*} data The message to send
2690
+ * @param {Object} [options] Options object
2691
+ * @param {Boolean} [options.binary] Specifies whether `data` is binary or
2692
+ * text
2693
+ * @param {Boolean} [options.compress] Specifies whether or not to compress
2694
+ * `data`
2695
+ * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
2696
+ * last one
2697
+ * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
2698
+ * @param {Function} [cb] Callback which is executed when data is written out
2699
+ * @public
2700
+ */
2701
+ send(data, options, cb) {
2702
+ if (this.readyState === WebSocket.CONNECTING) throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");
2703
+ if (typeof options === "function") {
2704
+ cb = options;
2705
+ options = {};
2706
+ }
2707
+ if (typeof data === "number") data = data.toString();
2708
+ if (this.readyState !== WebSocket.OPEN) {
2709
+ sendAfterClose(this, data, cb);
2710
+ return;
2711
+ }
2712
+ const opts = {
2713
+ binary: typeof data !== "string",
2714
+ mask: !this._isServer,
2715
+ compress: true,
2716
+ fin: true,
2717
+ ...options
2718
+ };
2719
+ if (!this._extensions[PerMessageDeflate.extensionName]) opts.compress = false;
2720
+ this._sender.send(data || EMPTY_BUFFER, opts, cb);
2721
+ }
2722
+ /**
2723
+ * Forcibly close the connection.
2724
+ *
2725
+ * @public
2726
+ */
2727
+ terminate() {
2728
+ if (this.readyState === WebSocket.CLOSED) return;
2729
+ if (this.readyState === WebSocket.CONNECTING) {
2730
+ abortHandshake(this, this._req, "WebSocket was closed before the connection was established");
2731
+ return;
2732
+ }
2733
+ if (this._socket) {
2734
+ this._readyState = WebSocket.CLOSING;
2735
+ this._socket.destroy();
2736
+ }
2737
+ }
2738
+ };
2739
+ /**
2740
+ * @constant {Number} CONNECTING
2741
+ * @memberof WebSocket
2742
+ */
2743
+ Object.defineProperty(WebSocket, "CONNECTING", {
2744
+ enumerable: true,
2745
+ value: readyStates.indexOf("CONNECTING")
2746
+ });
2747
+ /**
2748
+ * @constant {Number} CONNECTING
2749
+ * @memberof WebSocket.prototype
2750
+ */
2751
+ Object.defineProperty(WebSocket.prototype, "CONNECTING", {
2752
+ enumerable: true,
2753
+ value: readyStates.indexOf("CONNECTING")
2754
+ });
2755
+ /**
2756
+ * @constant {Number} OPEN
2757
+ * @memberof WebSocket
2758
+ */
2759
+ Object.defineProperty(WebSocket, "OPEN", {
2760
+ enumerable: true,
2761
+ value: readyStates.indexOf("OPEN")
2762
+ });
2763
+ /**
2764
+ * @constant {Number} OPEN
2765
+ * @memberof WebSocket.prototype
2766
+ */
2767
+ Object.defineProperty(WebSocket.prototype, "OPEN", {
2768
+ enumerable: true,
2769
+ value: readyStates.indexOf("OPEN")
2770
+ });
2771
+ /**
2772
+ * @constant {Number} CLOSING
2773
+ * @memberof WebSocket
2774
+ */
2775
+ Object.defineProperty(WebSocket, "CLOSING", {
2776
+ enumerable: true,
2777
+ value: readyStates.indexOf("CLOSING")
2778
+ });
2779
+ /**
2780
+ * @constant {Number} CLOSING
2781
+ * @memberof WebSocket.prototype
2782
+ */
2783
+ Object.defineProperty(WebSocket.prototype, "CLOSING", {
2784
+ enumerable: true,
2785
+ value: readyStates.indexOf("CLOSING")
2786
+ });
2787
+ /**
2788
+ * @constant {Number} CLOSED
2789
+ * @memberof WebSocket
2790
+ */
2791
+ Object.defineProperty(WebSocket, "CLOSED", {
2792
+ enumerable: true,
2793
+ value: readyStates.indexOf("CLOSED")
2794
+ });
2795
+ /**
2796
+ * @constant {Number} CLOSED
2797
+ * @memberof WebSocket.prototype
2798
+ */
2799
+ Object.defineProperty(WebSocket.prototype, "CLOSED", {
2800
+ enumerable: true,
2801
+ value: readyStates.indexOf("CLOSED")
2802
+ });
2803
+ [
2804
+ "binaryType",
2805
+ "bufferedAmount",
2806
+ "extensions",
2807
+ "isPaused",
2808
+ "protocol",
2809
+ "readyState",
2810
+ "url"
2811
+ ].forEach((property) => {
2812
+ Object.defineProperty(WebSocket.prototype, property, { enumerable: true });
2813
+ });
2814
+ [
2815
+ "open",
2816
+ "error",
2817
+ "close",
2818
+ "message"
2819
+ ].forEach((method) => {
2820
+ Object.defineProperty(WebSocket.prototype, `on${method}`, {
2821
+ enumerable: true,
2822
+ get() {
2823
+ for (const listener of this.listeners(method)) if (listener[kForOnEventAttribute]) return listener[kListener];
2824
+ return null;
2825
+ },
2826
+ set(handler) {
2827
+ for (const listener of this.listeners(method)) if (listener[kForOnEventAttribute]) {
2828
+ this.removeListener(method, listener);
2829
+ break;
2830
+ }
2831
+ if (typeof handler !== "function") return;
2832
+ this.addEventListener(method, handler, { [kForOnEventAttribute]: true });
2833
+ }
2834
+ });
2835
+ });
2836
+ WebSocket.prototype.addEventListener = addEventListener;
2837
+ WebSocket.prototype.removeEventListener = removeEventListener;
2838
+ module.exports = WebSocket;
2839
+ /**
2840
+ * Initialize a WebSocket client.
2841
+ *
2842
+ * @param {WebSocket} websocket The client to initialize
2843
+ * @param {(String|URL)} address The URL to which to connect
2844
+ * @param {Array} protocols The subprotocols
2845
+ * @param {Object} [options] Connection options
2846
+ * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any
2847
+ * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple
2848
+ * times in the same tick
2849
+ * @param {Boolean} [options.autoPong=true] Specifies whether or not to
2850
+ * automatically send a pong in response to a ping
2851
+ * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait
2852
+ * for the closing handshake to finish after `websocket.close()` is called
2853
+ * @param {Function} [options.finishRequest] A function which can be used to
2854
+ * customize the headers of each http request before it is sent
2855
+ * @param {Boolean} [options.followRedirects=false] Whether or not to follow
2856
+ * redirects
2857
+ * @param {Function} [options.generateMask] The function used to generate the
2858
+ * masking key
2859
+ * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
2860
+ * handshake request
2861
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
2862
+ * size
2863
+ * @param {Number} [options.maxRedirects=10] The maximum number of redirects
2864
+ * allowed
2865
+ * @param {String} [options.origin] Value of the `Origin` or
2866
+ * `Sec-WebSocket-Origin` header
2867
+ * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
2868
+ * permessage-deflate
2869
+ * @param {Number} [options.protocolVersion=13] Value of the
2870
+ * `Sec-WebSocket-Version` header
2871
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
2872
+ * not to skip UTF-8 validation for text and close messages
2873
+ * @private
2874
+ */
2875
+ function initAsClient(websocket, address, protocols, options) {
2876
+ const opts = {
2877
+ allowSynchronousEvents: true,
2878
+ autoPong: true,
2879
+ closeTimeout: CLOSE_TIMEOUT,
2880
+ protocolVersion: protocolVersions[1],
2881
+ maxPayload: 100 * 1024 * 1024,
2882
+ skipUTF8Validation: false,
2883
+ perMessageDeflate: true,
2884
+ followRedirects: false,
2885
+ maxRedirects: 10,
2886
+ ...options,
2887
+ socketPath: void 0,
2888
+ hostname: void 0,
2889
+ protocol: void 0,
2890
+ timeout: void 0,
2891
+ method: "GET",
2892
+ host: void 0,
2893
+ path: void 0,
2894
+ port: void 0
2895
+ };
2896
+ websocket._autoPong = opts.autoPong;
2897
+ websocket._closeTimeout = opts.closeTimeout;
2898
+ if (!protocolVersions.includes(opts.protocolVersion)) throw new RangeError(`Unsupported protocol version: ${opts.protocolVersion} (supported versions: ${protocolVersions.join(", ")})`);
2899
+ let parsedUrl;
2900
+ if (address instanceof URL) parsedUrl = address;
2901
+ else try {
2902
+ parsedUrl = new URL(address);
2903
+ } catch (e) {
2904
+ throw new SyntaxError(`Invalid URL: ${address}`);
2905
+ }
2906
+ if (parsedUrl.protocol === "http:") parsedUrl.protocol = "ws:";
2907
+ else if (parsedUrl.protocol === "https:") parsedUrl.protocol = "wss:";
2908
+ websocket._url = parsedUrl.href;
2909
+ const isSecure = parsedUrl.protocol === "wss:";
2910
+ const isIpcUrl = parsedUrl.protocol === "ws+unix:";
2911
+ let invalidUrlMessage;
2912
+ if (parsedUrl.protocol !== "ws:" && !isSecure && !isIpcUrl) invalidUrlMessage = "The URL's protocol must be one of \"ws:\", \"wss:\", \"http:\", \"https:\", or \"ws+unix:\"";
2913
+ else if (isIpcUrl && !parsedUrl.pathname) invalidUrlMessage = "The URL's pathname is empty";
2914
+ else if (parsedUrl.hash) invalidUrlMessage = "The URL contains a fragment identifier";
2915
+ if (invalidUrlMessage) {
2916
+ const err = new SyntaxError(invalidUrlMessage);
2917
+ if (websocket._redirects === 0) throw err;
2918
+ else {
2919
+ emitErrorAndClose(websocket, err);
2920
+ return;
2921
+ }
2922
+ }
2923
+ const defaultPort = isSecure ? 443 : 80;
2924
+ const key = randomBytes(16).toString("base64");
2925
+ const request = isSecure ? https.request : http$1.request;
2926
+ const protocolSet = /* @__PURE__ */ new Set();
2927
+ let perMessageDeflate;
2928
+ opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
2929
+ opts.defaultPort = opts.defaultPort || defaultPort;
2930
+ opts.port = parsedUrl.port || defaultPort;
2931
+ opts.host = parsedUrl.hostname.startsWith("[") ? parsedUrl.hostname.slice(1, -1) : parsedUrl.hostname;
2932
+ opts.headers = {
2933
+ ...opts.headers,
2934
+ "Sec-WebSocket-Version": opts.protocolVersion,
2935
+ "Sec-WebSocket-Key": key,
2936
+ Connection: "Upgrade",
2937
+ Upgrade: "websocket"
2938
+ };
2939
+ opts.path = parsedUrl.pathname + parsedUrl.search;
2940
+ opts.timeout = opts.handshakeTimeout;
2941
+ if (opts.perMessageDeflate) {
2942
+ perMessageDeflate = new PerMessageDeflate(opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, false, opts.maxPayload);
2943
+ opts.headers["Sec-WebSocket-Extensions"] = format({ [PerMessageDeflate.extensionName]: perMessageDeflate.offer() });
2944
+ }
2945
+ if (protocols.length) {
2946
+ for (const protocol of protocols) {
2947
+ if (typeof protocol !== "string" || !subprotocolRegex.test(protocol) || protocolSet.has(protocol)) throw new SyntaxError("An invalid or duplicated subprotocol was specified");
2948
+ protocolSet.add(protocol);
2949
+ }
2950
+ opts.headers["Sec-WebSocket-Protocol"] = protocols.join(",");
2951
+ }
2952
+ if (opts.origin) if (opts.protocolVersion < 13) opts.headers["Sec-WebSocket-Origin"] = opts.origin;
2953
+ else opts.headers.Origin = opts.origin;
2954
+ if (parsedUrl.username || parsedUrl.password) opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
2955
+ if (isIpcUrl) {
2956
+ const parts = opts.path.split(":");
2957
+ opts.socketPath = parts[0];
2958
+ opts.path = parts[1];
2959
+ }
2960
+ let req;
2961
+ if (opts.followRedirects) {
2962
+ if (websocket._redirects === 0) {
2963
+ websocket._originalIpc = isIpcUrl;
2964
+ websocket._originalSecure = isSecure;
2965
+ websocket._originalHostOrSocketPath = isIpcUrl ? opts.socketPath : parsedUrl.host;
2966
+ const headers = options && options.headers;
2967
+ options = {
2968
+ ...options,
2969
+ headers: {}
2970
+ };
2971
+ if (headers) for (const [key, value] of Object.entries(headers)) options.headers[key.toLowerCase()] = value;
2972
+ } else if (websocket.listenerCount("redirect") === 0) {
2973
+ const isSameHost = isIpcUrl ? websocket._originalIpc ? opts.socketPath === websocket._originalHostOrSocketPath : false : websocket._originalIpc ? false : parsedUrl.host === websocket._originalHostOrSocketPath;
2974
+ if (!isSameHost || websocket._originalSecure && !isSecure) {
2975
+ delete opts.headers.authorization;
2976
+ delete opts.headers.cookie;
2977
+ if (!isSameHost) delete opts.headers.host;
2978
+ opts.auth = void 0;
2979
+ }
2980
+ }
2981
+ if (opts.auth && !options.headers.authorization) options.headers.authorization = "Basic " + Buffer.from(opts.auth).toString("base64");
2982
+ req = websocket._req = request(opts);
2983
+ if (websocket._redirects) websocket.emit("redirect", websocket.url, req);
2984
+ } else req = websocket._req = request(opts);
2985
+ if (opts.timeout) req.on("timeout", () => {
2986
+ abortHandshake(websocket, req, "Opening handshake has timed out");
2987
+ });
2988
+ req.on("error", (err) => {
2989
+ if (req === null || req[kAborted]) return;
2990
+ req = websocket._req = null;
2991
+ emitErrorAndClose(websocket, err);
2992
+ });
2993
+ req.on("response", (res) => {
2994
+ const location = res.headers.location;
2995
+ const statusCode = res.statusCode;
2996
+ if (location && opts.followRedirects && statusCode >= 300 && statusCode < 400) {
2997
+ if (++websocket._redirects > opts.maxRedirects) {
2998
+ abortHandshake(websocket, req, "Maximum redirects exceeded");
2999
+ return;
3000
+ }
3001
+ req.abort();
3002
+ let addr;
3003
+ try {
3004
+ addr = new URL(location, address);
3005
+ } catch (e) {
3006
+ emitErrorAndClose(websocket, /* @__PURE__ */ new SyntaxError(`Invalid URL: ${location}`));
3007
+ return;
3008
+ }
3009
+ initAsClient(websocket, addr, protocols, options);
3010
+ } else if (!websocket.emit("unexpected-response", req, res)) abortHandshake(websocket, req, `Unexpected server response: ${res.statusCode}`);
3011
+ });
3012
+ req.on("upgrade", (res, socket, head) => {
3013
+ websocket.emit("upgrade", res);
3014
+ if (websocket.readyState !== WebSocket.CONNECTING) return;
3015
+ req = websocket._req = null;
3016
+ const upgrade = res.headers.upgrade;
3017
+ if (upgrade === void 0 || upgrade.toLowerCase() !== "websocket") {
3018
+ abortHandshake(websocket, socket, "Invalid Upgrade header");
3019
+ return;
3020
+ }
3021
+ const digest = createHash$1("sha1").update(key + GUID).digest("base64");
3022
+ if (res.headers["sec-websocket-accept"] !== digest) {
3023
+ abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
3024
+ return;
3025
+ }
3026
+ const serverProt = res.headers["sec-websocket-protocol"];
3027
+ let protError;
3028
+ if (serverProt !== void 0) {
3029
+ if (!protocolSet.size) protError = "Server sent a subprotocol but none was requested";
3030
+ else if (!protocolSet.has(serverProt)) protError = "Server sent an invalid subprotocol";
3031
+ } else if (protocolSet.size) protError = "Server sent no subprotocol";
3032
+ if (protError) {
3033
+ abortHandshake(websocket, socket, protError);
3034
+ return;
3035
+ }
3036
+ if (serverProt) websocket._protocol = serverProt;
3037
+ const secWebSocketExtensions = res.headers["sec-websocket-extensions"];
3038
+ if (secWebSocketExtensions !== void 0) {
3039
+ if (!perMessageDeflate) {
3040
+ abortHandshake(websocket, socket, "Server sent a Sec-WebSocket-Extensions header but no extension was requested");
3041
+ return;
3042
+ }
3043
+ let extensions;
3044
+ try {
3045
+ extensions = parse(secWebSocketExtensions);
3046
+ } catch (err) {
3047
+ abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Extensions header");
3048
+ return;
3049
+ }
3050
+ const extensionNames = Object.keys(extensions);
3051
+ if (extensionNames.length !== 1 || extensionNames[0] !== PerMessageDeflate.extensionName) {
3052
+ abortHandshake(websocket, socket, "Server indicated an extension that was not requested");
3053
+ return;
3054
+ }
3055
+ try {
3056
+ perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);
3057
+ } catch (err) {
3058
+ abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Extensions header");
3059
+ return;
3060
+ }
3061
+ websocket._extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
3062
+ }
3063
+ websocket.setSocket(socket, head, {
3064
+ allowSynchronousEvents: opts.allowSynchronousEvents,
3065
+ generateMask: opts.generateMask,
3066
+ maxPayload: opts.maxPayload,
3067
+ skipUTF8Validation: opts.skipUTF8Validation
3068
+ });
3069
+ });
3070
+ if (opts.finishRequest) opts.finishRequest(req, websocket);
3071
+ else req.end();
3072
+ }
3073
+ /**
3074
+ * Emit the `'error'` and `'close'` events.
3075
+ *
3076
+ * @param {WebSocket} websocket The WebSocket instance
3077
+ * @param {Error} The error to emit
3078
+ * @private
3079
+ */
3080
+ function emitErrorAndClose(websocket, err) {
3081
+ websocket._readyState = WebSocket.CLOSING;
3082
+ websocket._errorEmitted = true;
3083
+ websocket.emit("error", err);
3084
+ websocket.emitClose();
3085
+ }
3086
+ /**
3087
+ * Create a `net.Socket` and initiate a connection.
3088
+ *
3089
+ * @param {Object} options Connection options
3090
+ * @return {net.Socket} The newly created socket used to start the connection
3091
+ * @private
3092
+ */
3093
+ function netConnect(options) {
3094
+ options.path = options.socketPath;
3095
+ return net.connect(options);
3096
+ }
3097
+ /**
3098
+ * Create a `tls.TLSSocket` and initiate a connection.
3099
+ *
3100
+ * @param {Object} options Connection options
3101
+ * @return {tls.TLSSocket} The newly created socket used to start the connection
3102
+ * @private
3103
+ */
3104
+ function tlsConnect(options) {
3105
+ options.path = void 0;
3106
+ if (!options.servername && options.servername !== "") options.servername = net.isIP(options.host) ? "" : options.host;
3107
+ return tls.connect(options);
3108
+ }
3109
+ /**
3110
+ * Abort the handshake and emit an error.
3111
+ *
3112
+ * @param {WebSocket} websocket The WebSocket instance
3113
+ * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
3114
+ * abort or the socket to destroy
3115
+ * @param {String} message The error message
3116
+ * @private
3117
+ */
3118
+ function abortHandshake(websocket, stream, message) {
3119
+ websocket._readyState = WebSocket.CLOSING;
3120
+ const err = new Error(message);
3121
+ Error.captureStackTrace(err, abortHandshake);
3122
+ if (stream.setHeader) {
3123
+ stream[kAborted] = true;
3124
+ stream.abort();
3125
+ if (stream.socket && !stream.socket.destroyed) stream.socket.destroy();
3126
+ process.nextTick(emitErrorAndClose, websocket, err);
3127
+ } else {
3128
+ stream.destroy(err);
3129
+ stream.once("error", websocket.emit.bind(websocket, "error"));
3130
+ stream.once("close", websocket.emitClose.bind(websocket));
3131
+ }
3132
+ }
3133
+ /**
3134
+ * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
3135
+ * when the `readyState` attribute is `CLOSING` or `CLOSED`.
3136
+ *
3137
+ * @param {WebSocket} websocket The WebSocket instance
3138
+ * @param {*} [data] The data to send
3139
+ * @param {Function} [cb] Callback
3140
+ * @private
3141
+ */
3142
+ function sendAfterClose(websocket, data, cb) {
3143
+ if (data) {
3144
+ const length = isBlob(data) ? data.size : toBuffer(data).length;
3145
+ if (websocket._socket) websocket._sender._bufferedBytes += length;
3146
+ else websocket._bufferedAmount += length;
3147
+ }
3148
+ if (cb) {
3149
+ const err = /* @__PURE__ */ new Error(`WebSocket is not open: readyState ${websocket.readyState} (${readyStates[websocket.readyState]})`);
3150
+ process.nextTick(cb, err);
3151
+ }
3152
+ }
3153
+ /**
3154
+ * The listener of the `Receiver` `'conclude'` event.
3155
+ *
3156
+ * @param {Number} code The status code
3157
+ * @param {Buffer} reason The reason for closing
3158
+ * @private
3159
+ */
3160
+ function receiverOnConclude(code, reason) {
3161
+ const websocket = this[kWebSocket];
3162
+ websocket._closeFrameReceived = true;
3163
+ websocket._closeMessage = reason;
3164
+ websocket._closeCode = code;
3165
+ if (websocket._socket[kWebSocket] === void 0) return;
3166
+ websocket._socket.removeListener("data", socketOnData);
3167
+ process.nextTick(resume, websocket._socket);
3168
+ if (code === 1005) websocket.close();
3169
+ else websocket.close(code, reason);
3170
+ }
3171
+ /**
3172
+ * The listener of the `Receiver` `'drain'` event.
3173
+ *
3174
+ * @private
3175
+ */
3176
+ function receiverOnDrain() {
3177
+ const websocket = this[kWebSocket];
3178
+ if (!websocket.isPaused) websocket._socket.resume();
3179
+ }
3180
+ /**
3181
+ * The listener of the `Receiver` `'error'` event.
3182
+ *
3183
+ * @param {(RangeError|Error)} err The emitted error
3184
+ * @private
3185
+ */
3186
+ function receiverOnError(err) {
3187
+ const websocket = this[kWebSocket];
3188
+ if (websocket._socket[kWebSocket] !== void 0) {
3189
+ websocket._socket.removeListener("data", socketOnData);
3190
+ process.nextTick(resume, websocket._socket);
3191
+ websocket.close(err[kStatusCode]);
3192
+ }
3193
+ if (!websocket._errorEmitted) {
3194
+ websocket._errorEmitted = true;
3195
+ websocket.emit("error", err);
3196
+ }
3197
+ }
3198
+ /**
3199
+ * The listener of the `Receiver` `'finish'` event.
3200
+ *
3201
+ * @private
3202
+ */
3203
+ function receiverOnFinish() {
3204
+ this[kWebSocket].emitClose();
3205
+ }
3206
+ /**
3207
+ * The listener of the `Receiver` `'message'` event.
3208
+ *
3209
+ * @param {Buffer|ArrayBuffer|Buffer[])} data The message
3210
+ * @param {Boolean} isBinary Specifies whether the message is binary or not
3211
+ * @private
3212
+ */
3213
+ function receiverOnMessage(data, isBinary) {
3214
+ this[kWebSocket].emit("message", data, isBinary);
3215
+ }
3216
+ /**
3217
+ * The listener of the `Receiver` `'ping'` event.
3218
+ *
3219
+ * @param {Buffer} data The data included in the ping frame
3220
+ * @private
3221
+ */
3222
+ function receiverOnPing(data) {
3223
+ const websocket = this[kWebSocket];
3224
+ if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);
3225
+ websocket.emit("ping", data);
3226
+ }
3227
+ /**
3228
+ * The listener of the `Receiver` `'pong'` event.
3229
+ *
3230
+ * @param {Buffer} data The data included in the pong frame
3231
+ * @private
3232
+ */
3233
+ function receiverOnPong(data) {
3234
+ this[kWebSocket].emit("pong", data);
3235
+ }
3236
+ /**
3237
+ * Resume a readable stream
3238
+ *
3239
+ * @param {Readable} stream The readable stream
3240
+ * @private
3241
+ */
3242
+ function resume(stream) {
3243
+ stream.resume();
3244
+ }
3245
+ /**
3246
+ * The `Sender` error event handler.
3247
+ *
3248
+ * @param {Error} The error
3249
+ * @private
3250
+ */
3251
+ function senderOnError(err) {
3252
+ const websocket = this[kWebSocket];
3253
+ if (websocket.readyState === WebSocket.CLOSED) return;
3254
+ if (websocket.readyState === WebSocket.OPEN) {
3255
+ websocket._readyState = WebSocket.CLOSING;
3256
+ setCloseTimer(websocket);
3257
+ }
3258
+ this._socket.end();
3259
+ if (!websocket._errorEmitted) {
3260
+ websocket._errorEmitted = true;
3261
+ websocket.emit("error", err);
3262
+ }
3263
+ }
3264
+ /**
3265
+ * Set a timer to destroy the underlying raw socket of a WebSocket.
3266
+ *
3267
+ * @param {WebSocket} websocket The WebSocket instance
3268
+ * @private
3269
+ */
3270
+ function setCloseTimer(websocket) {
3271
+ websocket._closeTimer = setTimeout(websocket._socket.destroy.bind(websocket._socket), websocket._closeTimeout);
3272
+ }
3273
+ /**
3274
+ * The listener of the socket `'close'` event.
3275
+ *
3276
+ * @private
3277
+ */
3278
+ function socketOnClose() {
3279
+ const websocket = this[kWebSocket];
3280
+ this.removeListener("close", socketOnClose);
3281
+ this.removeListener("data", socketOnData);
3282
+ this.removeListener("end", socketOnEnd);
3283
+ websocket._readyState = WebSocket.CLOSING;
3284
+ if (!this._readableState.endEmitted && !websocket._closeFrameReceived && !websocket._receiver._writableState.errorEmitted && this._readableState.length !== 0) {
3285
+ const chunk = this.read(this._readableState.length);
3286
+ websocket._receiver.write(chunk);
3287
+ }
3288
+ websocket._receiver.end();
3289
+ this[kWebSocket] = void 0;
3290
+ clearTimeout(websocket._closeTimer);
3291
+ if (websocket._receiver._writableState.finished || websocket._receiver._writableState.errorEmitted) websocket.emitClose();
3292
+ else {
3293
+ websocket._receiver.on("error", receiverOnFinish);
3294
+ websocket._receiver.on("finish", receiverOnFinish);
3295
+ }
3296
+ }
3297
+ /**
3298
+ * The listener of the socket `'data'` event.
3299
+ *
3300
+ * @param {Buffer} chunk A chunk of data
3301
+ * @private
3302
+ */
3303
+ function socketOnData(chunk) {
3304
+ if (!this[kWebSocket]._receiver.write(chunk)) this.pause();
3305
+ }
3306
+ /**
3307
+ * The listener of the socket `'end'` event.
3308
+ *
3309
+ * @private
3310
+ */
3311
+ function socketOnEnd() {
3312
+ const websocket = this[kWebSocket];
3313
+ websocket._readyState = WebSocket.CLOSING;
3314
+ websocket._receiver.end();
3315
+ this.end();
3316
+ }
3317
+ /**
3318
+ * The listener of the socket `'error'` event.
3319
+ *
3320
+ * @private
3321
+ */
3322
+ function socketOnError() {
3323
+ const websocket = this[kWebSocket];
3324
+ this.removeListener("error", socketOnError);
3325
+ this.on("error", NOOP);
3326
+ if (websocket) {
3327
+ websocket._readyState = WebSocket.CLOSING;
3328
+ this.destroy();
3329
+ }
3330
+ }
3331
+ }));
3332
+
3333
+ //#endregion
3334
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js
3335
+ var require_stream = /* @__PURE__ */ __commonJSMin(((exports, module) => {
3336
+ require_websocket();
3337
+ const { Duplex: Duplex$1 } = __require("stream");
3338
+ /**
3339
+ * Emits the `'close'` event on a stream.
3340
+ *
3341
+ * @param {Duplex} stream The stream.
3342
+ * @private
3343
+ */
3344
+ function emitClose(stream) {
3345
+ stream.emit("close");
3346
+ }
3347
+ /**
3348
+ * The listener of the `'end'` event.
3349
+ *
3350
+ * @private
3351
+ */
3352
+ function duplexOnEnd() {
3353
+ if (!this.destroyed && this._writableState.finished) this.destroy();
3354
+ }
3355
+ /**
3356
+ * The listener of the `'error'` event.
3357
+ *
3358
+ * @param {Error} err The error
3359
+ * @private
3360
+ */
3361
+ function duplexOnError(err) {
3362
+ this.removeListener("error", duplexOnError);
3363
+ this.destroy();
3364
+ if (this.listenerCount("error") === 0) this.emit("error", err);
3365
+ }
3366
+ /**
3367
+ * Wraps a `WebSocket` in a duplex stream.
3368
+ *
3369
+ * @param {WebSocket} ws The `WebSocket` to wrap
3370
+ * @param {Object} [options] The options for the `Duplex` constructor
3371
+ * @return {Duplex} The duplex stream
3372
+ * @public
3373
+ */
3374
+ function createWebSocketStream(ws, options) {
3375
+ let terminateOnDestroy = true;
3376
+ const duplex = new Duplex$1({
3377
+ ...options,
3378
+ autoDestroy: false,
3379
+ emitClose: false,
3380
+ objectMode: false,
3381
+ writableObjectMode: false
3382
+ });
3383
+ ws.on("message", function message(msg, isBinary) {
3384
+ const data = !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;
3385
+ if (!duplex.push(data)) ws.pause();
3386
+ });
3387
+ ws.once("error", function error(err) {
3388
+ if (duplex.destroyed) return;
3389
+ terminateOnDestroy = false;
3390
+ duplex.destroy(err);
3391
+ });
3392
+ ws.once("close", function close() {
3393
+ if (duplex.destroyed) return;
3394
+ duplex.push(null);
3395
+ });
3396
+ duplex._destroy = function(err, callback) {
3397
+ if (ws.readyState === ws.CLOSED) {
3398
+ callback(err);
3399
+ process.nextTick(emitClose, duplex);
3400
+ return;
3401
+ }
3402
+ let called = false;
3403
+ ws.once("error", function error(err) {
3404
+ called = true;
3405
+ callback(err);
3406
+ });
3407
+ ws.once("close", function close() {
3408
+ if (!called) callback(err);
3409
+ process.nextTick(emitClose, duplex);
3410
+ });
3411
+ if (terminateOnDestroy) ws.terminate();
3412
+ };
3413
+ duplex._final = function(callback) {
3414
+ if (ws.readyState === ws.CONNECTING) {
3415
+ ws.once("open", function open() {
3416
+ duplex._final(callback);
3417
+ });
3418
+ return;
3419
+ }
3420
+ if (ws._socket === null) return;
3421
+ if (ws._socket._writableState.finished) {
3422
+ callback();
3423
+ if (duplex._readableState.endEmitted) duplex.destroy();
3424
+ } else {
3425
+ ws._socket.once("finish", function finish() {
3426
+ callback();
3427
+ });
3428
+ ws.close();
3429
+ }
3430
+ };
3431
+ duplex._read = function() {
3432
+ if (ws.isPaused) ws.resume();
3433
+ };
3434
+ duplex._write = function(chunk, encoding, callback) {
3435
+ if (ws.readyState === ws.CONNECTING) {
3436
+ ws.once("open", function open() {
3437
+ duplex._write(chunk, encoding, callback);
3438
+ });
3439
+ return;
3440
+ }
3441
+ ws.send(chunk, callback);
3442
+ };
3443
+ duplex.on("end", duplexOnEnd);
3444
+ duplex.on("error", duplexOnError);
3445
+ return duplex;
3446
+ }
3447
+ module.exports = createWebSocketStream;
3448
+ }));
3449
+
3450
+ //#endregion
3451
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js
3452
+ var require_subprotocol = /* @__PURE__ */ __commonJSMin(((exports, module) => {
3453
+ const { tokenChars } = require_validation();
3454
+ /**
3455
+ * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.
3456
+ *
3457
+ * @param {String} header The field value of the header
3458
+ * @return {Set} The subprotocol names
3459
+ * @public
3460
+ */
3461
+ function parse(header) {
3462
+ const protocols = /* @__PURE__ */ new Set();
3463
+ let start = -1;
3464
+ let end = -1;
3465
+ let i = 0;
3466
+ for (; i < header.length; i++) {
3467
+ const code = header.charCodeAt(i);
3468
+ if (end === -1 && tokenChars[code] === 1) {
3469
+ if (start === -1) start = i;
3470
+ } else if (i !== 0 && (code === 32 || code === 9)) {
3471
+ if (end === -1 && start !== -1) end = i;
3472
+ } else if (code === 44) {
3473
+ if (start === -1) throw new SyntaxError(`Unexpected character at index ${i}`);
3474
+ if (end === -1) end = i;
3475
+ const protocol = header.slice(start, end);
3476
+ if (protocols.has(protocol)) throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
3477
+ protocols.add(protocol);
3478
+ start = end = -1;
3479
+ } else throw new SyntaxError(`Unexpected character at index ${i}`);
3480
+ }
3481
+ if (start === -1 || end !== -1) throw new SyntaxError("Unexpected end of input");
3482
+ const protocol = header.slice(start, i);
3483
+ if (protocols.has(protocol)) throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`);
3484
+ protocols.add(protocol);
3485
+ return protocols;
3486
+ }
3487
+ module.exports = { parse };
3488
+ }));
3489
+
3490
+ //#endregion
3491
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js
3492
+ var require_websocket_server = /* @__PURE__ */ __commonJSMin(((exports, module) => {
3493
+ const EventEmitter$1 = __require("events");
3494
+ const http = __require("http");
3495
+ const { Duplex } = __require("stream");
3496
+ const { createHash } = __require("crypto");
3497
+ const extension = require_extension();
3498
+ const PerMessageDeflate = require_permessage_deflate();
3499
+ const subprotocol = require_subprotocol();
3500
+ const WebSocket = require_websocket();
3501
+ const { CLOSE_TIMEOUT, GUID, kWebSocket } = require_constants();
3502
+ const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
3503
+ const RUNNING = 0;
3504
+ const CLOSING = 1;
3505
+ const CLOSED = 2;
3506
+ /**
3507
+ * Class representing a WebSocket server.
3508
+ *
3509
+ * @extends EventEmitter
3510
+ */
3511
+ var WebSocketServer = class extends EventEmitter$1 {
3512
+ /**
3513
+ * Create a `WebSocketServer` instance.
3514
+ *
3515
+ * @param {Object} options Configuration options
3516
+ * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether
3517
+ * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted
3518
+ * multiple times in the same tick
3519
+ * @param {Boolean} [options.autoPong=true] Specifies whether or not to
3520
+ * automatically send a pong in response to a ping
3521
+ * @param {Number} [options.backlog=511] The maximum length of the queue of
3522
+ * pending connections
3523
+ * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
3524
+ * track clients
3525
+ * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to
3526
+ * wait for the closing handshake to finish after `websocket.close()` is
3527
+ * called
3528
+ * @param {Function} [options.handleProtocols] A hook to handle protocols
3529
+ * @param {String} [options.host] The hostname where to bind the server
3530
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
3531
+ * size
3532
+ * @param {Boolean} [options.noServer=false] Enable no server mode
3533
+ * @param {String} [options.path] Accept only connections matching this path
3534
+ * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
3535
+ * permessage-deflate
3536
+ * @param {Number} [options.port] The port where to bind the server
3537
+ * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
3538
+ * server to use
3539
+ * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or
3540
+ * not to skip UTF-8 validation for text and close messages
3541
+ * @param {Function} [options.verifyClient] A hook to reject connections
3542
+ * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`
3543
+ * class to use. It must be the `WebSocket` class or class that extends it
3544
+ * @param {Function} [callback] A listener for the `listening` event
3545
+ */
3546
+ constructor(options, callback) {
3547
+ super();
3548
+ options = {
3549
+ allowSynchronousEvents: true,
3550
+ autoPong: true,
3551
+ maxPayload: 100 * 1024 * 1024,
3552
+ skipUTF8Validation: false,
3553
+ perMessageDeflate: false,
3554
+ handleProtocols: null,
3555
+ clientTracking: true,
3556
+ closeTimeout: CLOSE_TIMEOUT,
3557
+ verifyClient: null,
3558
+ noServer: false,
3559
+ backlog: null,
3560
+ server: null,
3561
+ host: null,
3562
+ path: null,
3563
+ port: null,
3564
+ WebSocket,
3565
+ ...options
3566
+ };
3567
+ if (options.port == null && !options.server && !options.noServer || options.port != null && (options.server || options.noServer) || options.server && options.noServer) throw new TypeError("One and only one of the \"port\", \"server\", or \"noServer\" options must be specified");
3568
+ if (options.port != null) {
3569
+ this._server = http.createServer((req, res) => {
3570
+ const body = http.STATUS_CODES[426];
3571
+ res.writeHead(426, {
3572
+ "Content-Length": body.length,
3573
+ "Content-Type": "text/plain"
3574
+ });
3575
+ res.end(body);
3576
+ });
3577
+ this._server.listen(options.port, options.host, options.backlog, callback);
3578
+ } else if (options.server) this._server = options.server;
3579
+ if (this._server) {
3580
+ const emitConnection = this.emit.bind(this, "connection");
3581
+ this._removeListeners = addListeners(this._server, {
3582
+ listening: this.emit.bind(this, "listening"),
3583
+ error: this.emit.bind(this, "error"),
3584
+ upgrade: (req, socket, head) => {
3585
+ this.handleUpgrade(req, socket, head, emitConnection);
3586
+ }
3587
+ });
3588
+ }
3589
+ if (options.perMessageDeflate === true) options.perMessageDeflate = {};
3590
+ if (options.clientTracking) {
3591
+ this.clients = /* @__PURE__ */ new Set();
3592
+ this._shouldEmitClose = false;
3593
+ }
3594
+ this.options = options;
3595
+ this._state = RUNNING;
3596
+ }
3597
+ /**
3598
+ * Returns the bound address, the address family name, and port of the server
3599
+ * as reported by the operating system if listening on an IP socket.
3600
+ * If the server is listening on a pipe or UNIX domain socket, the name is
3601
+ * returned as a string.
3602
+ *
3603
+ * @return {(Object|String|null)} The address of the server
3604
+ * @public
3605
+ */
3606
+ address() {
3607
+ if (this.options.noServer) throw new Error("The server is operating in \"noServer\" mode");
3608
+ if (!this._server) return null;
3609
+ return this._server.address();
3610
+ }
3611
+ /**
3612
+ * Stop the server from accepting new connections and emit the `'close'` event
3613
+ * when all existing connections are closed.
3614
+ *
3615
+ * @param {Function} [cb] A one-time listener for the `'close'` event
3616
+ * @public
3617
+ */
3618
+ close(cb) {
3619
+ if (this._state === CLOSED) {
3620
+ if (cb) this.once("close", () => {
3621
+ cb(/* @__PURE__ */ new Error("The server is not running"));
3622
+ });
3623
+ process.nextTick(emitClose, this);
3624
+ return;
3625
+ }
3626
+ if (cb) this.once("close", cb);
3627
+ if (this._state === CLOSING) return;
3628
+ this._state = CLOSING;
3629
+ if (this.options.noServer || this.options.server) {
3630
+ if (this._server) {
3631
+ this._removeListeners();
3632
+ this._removeListeners = this._server = null;
3633
+ }
3634
+ if (this.clients) if (!this.clients.size) process.nextTick(emitClose, this);
3635
+ else this._shouldEmitClose = true;
3636
+ else process.nextTick(emitClose, this);
3637
+ } else {
3638
+ const server = this._server;
3639
+ this._removeListeners();
3640
+ this._removeListeners = this._server = null;
3641
+ server.close(() => {
3642
+ emitClose(this);
3643
+ });
3644
+ }
3645
+ }
3646
+ /**
3647
+ * See if a given request should be handled by this server instance.
3648
+ *
3649
+ * @param {http.IncomingMessage} req Request object to inspect
3650
+ * @return {Boolean} `true` if the request is valid, else `false`
3651
+ * @public
3652
+ */
3653
+ shouldHandle(req) {
3654
+ if (this.options.path) {
3655
+ const index = req.url.indexOf("?");
3656
+ if ((index !== -1 ? req.url.slice(0, index) : req.url) !== this.options.path) return false;
3657
+ }
3658
+ return true;
3659
+ }
3660
+ /**
3661
+ * Handle a HTTP Upgrade request.
3662
+ *
3663
+ * @param {http.IncomingMessage} req The request object
3664
+ * @param {Duplex} socket The network socket between the server and client
3665
+ * @param {Buffer} head The first packet of the upgraded stream
3666
+ * @param {Function} cb Callback
3667
+ * @public
3668
+ */
3669
+ handleUpgrade(req, socket, head, cb) {
3670
+ socket.on("error", socketOnError);
3671
+ const key = req.headers["sec-websocket-key"];
3672
+ const upgrade = req.headers.upgrade;
3673
+ const version = +req.headers["sec-websocket-version"];
3674
+ if (req.method !== "GET") {
3675
+ abortHandshakeOrEmitwsClientError(this, req, socket, 405, "Invalid HTTP method");
3676
+ return;
3677
+ }
3678
+ if (upgrade === void 0 || upgrade.toLowerCase() !== "websocket") {
3679
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Invalid Upgrade header");
3680
+ return;
3681
+ }
3682
+ if (key === void 0 || !keyRegex.test(key)) {
3683
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Missing or invalid Sec-WebSocket-Key header");
3684
+ return;
3685
+ }
3686
+ if (version !== 13 && version !== 8) {
3687
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Missing or invalid Sec-WebSocket-Version header", { "Sec-WebSocket-Version": "13, 8" });
3688
+ return;
3689
+ }
3690
+ if (!this.shouldHandle(req)) {
3691
+ abortHandshake(socket, 400);
3692
+ return;
3693
+ }
3694
+ const secWebSocketProtocol = req.headers["sec-websocket-protocol"];
3695
+ let protocols = /* @__PURE__ */ new Set();
3696
+ if (secWebSocketProtocol !== void 0) try {
3697
+ protocols = subprotocol.parse(secWebSocketProtocol);
3698
+ } catch (err) {
3699
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Invalid Sec-WebSocket-Protocol header");
3700
+ return;
3701
+ }
3702
+ const secWebSocketExtensions = req.headers["sec-websocket-extensions"];
3703
+ const extensions = {};
3704
+ if (this.options.perMessageDeflate && secWebSocketExtensions !== void 0) {
3705
+ const perMessageDeflate = new PerMessageDeflate(this.options.perMessageDeflate, true, this.options.maxPayload);
3706
+ try {
3707
+ const offers = extension.parse(secWebSocketExtensions);
3708
+ if (offers[PerMessageDeflate.extensionName]) {
3709
+ perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
3710
+ extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
3711
+ }
3712
+ } catch (err) {
3713
+ abortHandshakeOrEmitwsClientError(this, req, socket, 400, "Invalid or unacceptable Sec-WebSocket-Extensions header");
3714
+ return;
3715
+ }
3716
+ }
3717
+ if (this.options.verifyClient) {
3718
+ const info = {
3719
+ origin: req.headers[`${version === 8 ? "sec-websocket-origin" : "origin"}`],
3720
+ secure: !!(req.socket.authorized || req.socket.encrypted),
3721
+ req
3722
+ };
3723
+ if (this.options.verifyClient.length === 2) {
3724
+ this.options.verifyClient(info, (verified, code, message, headers) => {
3725
+ if (!verified) return abortHandshake(socket, code || 401, message, headers);
3726
+ this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
3727
+ });
3728
+ return;
3729
+ }
3730
+ if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
3731
+ }
3732
+ this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);
3733
+ }
3734
+ /**
3735
+ * Upgrade the connection to WebSocket.
3736
+ *
3737
+ * @param {Object} extensions The accepted extensions
3738
+ * @param {String} key The value of the `Sec-WebSocket-Key` header
3739
+ * @param {Set} protocols The subprotocols
3740
+ * @param {http.IncomingMessage} req The request object
3741
+ * @param {Duplex} socket The network socket between the server and client
3742
+ * @param {Buffer} head The first packet of the upgraded stream
3743
+ * @param {Function} cb Callback
3744
+ * @throws {Error} If called more than once with the same socket
3745
+ * @private
3746
+ */
3747
+ completeUpgrade(extensions, key, protocols, req, socket, head, cb) {
3748
+ if (!socket.readable || !socket.writable) return socket.destroy();
3749
+ if (socket[kWebSocket]) throw new Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");
3750
+ if (this._state > RUNNING) return abortHandshake(socket, 503);
3751
+ const headers = [
3752
+ "HTTP/1.1 101 Switching Protocols",
3753
+ "Upgrade: websocket",
3754
+ "Connection: Upgrade",
3755
+ `Sec-WebSocket-Accept: ${createHash("sha1").update(key + GUID).digest("base64")}`
3756
+ ];
3757
+ const ws = new this.options.WebSocket(null, void 0, this.options);
3758
+ if (protocols.size) {
3759
+ const protocol = this.options.handleProtocols ? this.options.handleProtocols(protocols, req) : protocols.values().next().value;
3760
+ if (protocol) {
3761
+ headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
3762
+ ws._protocol = protocol;
3763
+ }
3764
+ }
3765
+ if (extensions[PerMessageDeflate.extensionName]) {
3766
+ const params = extensions[PerMessageDeflate.extensionName].params;
3767
+ const value = extension.format({ [PerMessageDeflate.extensionName]: [params] });
3768
+ headers.push(`Sec-WebSocket-Extensions: ${value}`);
3769
+ ws._extensions = extensions;
3770
+ }
3771
+ this.emit("headers", headers, req);
3772
+ socket.write(headers.concat("\r\n").join("\r\n"));
3773
+ socket.removeListener("error", socketOnError);
3774
+ ws.setSocket(socket, head, {
3775
+ allowSynchronousEvents: this.options.allowSynchronousEvents,
3776
+ maxPayload: this.options.maxPayload,
3777
+ skipUTF8Validation: this.options.skipUTF8Validation
3778
+ });
3779
+ if (this.clients) {
3780
+ this.clients.add(ws);
3781
+ ws.on("close", () => {
3782
+ this.clients.delete(ws);
3783
+ if (this._shouldEmitClose && !this.clients.size) process.nextTick(emitClose, this);
3784
+ });
3785
+ }
3786
+ cb(ws, req);
3787
+ }
3788
+ };
3789
+ module.exports = WebSocketServer;
3790
+ /**
3791
+ * Add event listeners on an `EventEmitter` using a map of <event, listener>
3792
+ * pairs.
3793
+ *
3794
+ * @param {EventEmitter} server The event emitter
3795
+ * @param {Object.<String, Function>} map The listeners to add
3796
+ * @return {Function} A function that will remove the added listeners when
3797
+ * called
3798
+ * @private
3799
+ */
3800
+ function addListeners(server, map) {
3801
+ for (const event of Object.keys(map)) server.on(event, map[event]);
3802
+ return function removeListeners() {
3803
+ for (const event of Object.keys(map)) server.removeListener(event, map[event]);
3804
+ };
3805
+ }
3806
+ /**
3807
+ * Emit a `'close'` event on an `EventEmitter`.
3808
+ *
3809
+ * @param {EventEmitter} server The event emitter
3810
+ * @private
3811
+ */
3812
+ function emitClose(server) {
3813
+ server._state = CLOSED;
3814
+ server.emit("close");
3815
+ }
3816
+ /**
3817
+ * Handle socket errors.
3818
+ *
3819
+ * @private
3820
+ */
3821
+ function socketOnError() {
3822
+ this.destroy();
3823
+ }
3824
+ /**
3825
+ * Close the connection when preconditions are not fulfilled.
3826
+ *
3827
+ * @param {Duplex} socket The socket of the upgrade request
3828
+ * @param {Number} code The HTTP response status code
3829
+ * @param {String} [message] The HTTP response body
3830
+ * @param {Object} [headers] Additional HTTP response headers
3831
+ * @private
3832
+ */
3833
+ function abortHandshake(socket, code, message, headers) {
3834
+ message = message || http.STATUS_CODES[code];
3835
+ headers = {
3836
+ Connection: "close",
3837
+ "Content-Type": "text/html",
3838
+ "Content-Length": Buffer.byteLength(message),
3839
+ ...headers
3840
+ };
3841
+ socket.once("finish", socket.destroy);
3842
+ socket.end(`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message);
3843
+ }
3844
+ /**
3845
+ * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
3846
+ * one listener for it, otherwise call `abortHandshake()`.
3847
+ *
3848
+ * @param {WebSocketServer} server The WebSocket server
3849
+ * @param {http.IncomingMessage} req The request object
3850
+ * @param {Duplex} socket The socket of the upgrade request
3851
+ * @param {Number} code The HTTP response status code
3852
+ * @param {String} message The HTTP response body
3853
+ * @param {Object} [headers] The HTTP response headers
3854
+ * @private
3855
+ */
3856
+ function abortHandshakeOrEmitwsClientError(server, req, socket, code, message, headers) {
3857
+ if (server.listenerCount("wsClientError")) {
3858
+ const err = new Error(message);
3859
+ Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
3860
+ server.emit("wsClientError", err, socket, req);
3861
+ } else abortHandshake(socket, code, message, headers);
3862
+ }
3863
+ }));
3864
+
3865
+ //#endregion
3866
+ //#region node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs
3867
+ var import_stream = /* @__PURE__ */ __toESM(require_stream(), 1);
3868
+ var import_receiver = /* @__PURE__ */ __toESM(require_receiver(), 1);
3869
+ var import_sender = /* @__PURE__ */ __toESM(require_sender(), 1);
3870
+ var import_websocket = /* @__PURE__ */ __toESM(require_websocket(), 1);
3871
+ var import_websocket_server = /* @__PURE__ */ __toESM(require_websocket_server(), 1);
3872
+
3873
+ //#endregion
3874
+ //#region src/proxy/websocket-proxy.ts
3875
+ /**
3876
+ * WebSocket-to-TCP Proxy for Cap'n Proto
3877
+ *
3878
+ * Allows browsers to connect to native Cap'n Proto services (C++, etc.)
3879
+ * via WebSocket. Handles the protocol bridging between WebSocket (browser)
3880
+ * and raw TCP (Cap'n Proto services).
3881
+ */
3882
+ var ProxyConnection = class extends EventEmitter {
3883
+ ws;
3884
+ tcpSocket = null;
3885
+ stats;
3886
+ options;
3887
+ closed = false;
3888
+ constructor(ws, options) {
3889
+ super();
3890
+ this.ws = ws;
3891
+ this.options = options;
3892
+ this.stats = {
3893
+ wsMessagesIn: 0,
3894
+ wsMessagesOut: 0,
3895
+ tcpBytesIn: 0,
3896
+ tcpBytesOut: 0,
3897
+ connectedAt: /* @__PURE__ */ new Date()
3898
+ };
3899
+ this.setupWebSocket();
3900
+ }
3901
+ setupWebSocket() {
3902
+ this.ws.on("message", (data) => {
3903
+ this.handleWebSocketMessage(data);
3904
+ });
3905
+ this.ws.on("close", () => {
3906
+ this.log("WebSocket closed");
3907
+ this.close();
3908
+ });
3909
+ this.ws.on("error", (err) => {
3910
+ this.log("WebSocket error:", err);
3911
+ this.emit("error", err);
3912
+ this.close();
3913
+ });
3914
+ this.connectToTarget();
3915
+ }
3916
+ connectToTarget() {
3917
+ const timeout = this.options.connectionTimeout ?? 3e4;
3918
+ this.tcpSocket = createConnection({
3919
+ host: this.options.targetHost,
3920
+ port: this.options.targetPort,
3921
+ timeout
3922
+ });
3923
+ this.tcpSocket.on("connect", () => {
3924
+ this.log("Connected to target TCP service");
3925
+ this.emit("connected");
3926
+ });
3927
+ this.tcpSocket.on("data", (data) => {
3928
+ this.handleTcpData(data);
3929
+ });
3930
+ this.tcpSocket.on("close", () => {
3931
+ this.log("TCP connection closed");
3932
+ this.close();
3933
+ });
3934
+ this.tcpSocket.on("error", (err) => {
3935
+ this.log("TCP error:", err);
3936
+ this.emit("error", err);
3937
+ this.close();
3938
+ });
3939
+ this.tcpSocket.on("timeout", () => {
3940
+ this.log("TCP connection timeout");
3941
+ this.close();
3942
+ });
3943
+ }
3944
+ handleWebSocketMessage(data) {
3945
+ if (this.closed) return;
3946
+ const buffer = Buffer.isBuffer(data) ? data : Array.isArray(data) ? Buffer.concat(data) : Buffer.from(data);
3947
+ const maxSize = this.options.maxMessageSize ?? 16 * 1024 * 1024;
3948
+ if (buffer.length > maxSize) {
3949
+ this.log(`Message too large: ${buffer.length} bytes`);
3950
+ this.close();
3951
+ return;
3952
+ }
3953
+ this.stats.wsMessagesIn++;
3954
+ this.stats.tcpBytesOut += buffer.length;
3955
+ if (this.tcpSocket?.writable) {
3956
+ this.tcpSocket.write(buffer);
3957
+ this.log(`Forwarded ${buffer.length} bytes to TCP`);
3958
+ }
3959
+ }
3960
+ handleTcpData(data) {
3961
+ if (this.closed) return;
3962
+ this.stats.tcpBytesIn += data.length;
3963
+ this.stats.wsMessagesOut++;
3964
+ if (this.ws.readyState === import_websocket.default.OPEN) {
3965
+ this.ws.send(data);
3966
+ this.log(`Forwarded ${data.length} bytes to WebSocket`);
3967
+ }
3968
+ }
3969
+ log(...args) {
3970
+ if (this.options.debug) console.log("[ProxyConnection]", ...args);
3971
+ }
3972
+ getStats() {
3973
+ return { ...this.stats };
3974
+ }
3975
+ close() {
3976
+ if (this.closed) return;
3977
+ this.closed = true;
3978
+ this.ws.close();
3979
+ this.tcpSocket?.destroy();
3980
+ this.emit("closed");
3981
+ }
3982
+ };
3983
+ var CapnpWebSocketProxy = class extends EventEmitter {
3984
+ wss;
3985
+ connections = /* @__PURE__ */ new Map();
3986
+ options;
3987
+ constructor(options) {
3988
+ super();
3989
+ this.options = options;
3990
+ this.wss = new import_websocket_server.default({ port: options.wsPort });
3991
+ this.setupServer();
3992
+ }
3993
+ setupServer() {
3994
+ this.wss.on("connection", (ws, req) => {
3995
+ const clientIp = req.socket.remoteAddress;
3996
+ this.log(`New WebSocket connection from ${clientIp}`);
3997
+ const connection = new ProxyConnection(ws, this.options);
3998
+ this.connections.set(ws, connection);
3999
+ connection.on("connected", () => {
4000
+ this.emit("connection", connection);
4001
+ });
4002
+ connection.on("error", (err) => {
4003
+ this.emit("error", err, connection);
4004
+ });
4005
+ connection.on("closed", () => {
4006
+ this.connections.delete(ws);
4007
+ this.emit("disconnection", connection);
4008
+ });
4009
+ });
4010
+ this.wss.on("error", (err) => {
4011
+ this.emit("error", err);
4012
+ });
4013
+ }
4014
+ log(...args) {
4015
+ if (this.options.debug) console.log("[CapnpWebSocketProxy]", ...args);
4016
+ }
4017
+ getConnectionCount() {
4018
+ return this.connections.size;
4019
+ }
4020
+ getAllStats() {
4021
+ return Array.from(this.connections.values()).map((c) => c.getStats());
4022
+ }
4023
+ close() {
4024
+ return new Promise((resolve) => {
4025
+ for (const connection of this.connections.values()) connection.close();
4026
+ this.connections.clear();
4027
+ this.wss.close(() => {
4028
+ this.emit("closed");
4029
+ resolve();
4030
+ });
4031
+ });
4032
+ }
4033
+ };
4034
+ if (import.meta.url === `file://${process.argv[1]}`) {
4035
+ const args = process.argv.slice(2);
4036
+ let wsPort = 8080;
4037
+ let targetHost = "localhost";
4038
+ let targetPort = 8081;
4039
+ let debug = false;
4040
+ for (let i = 0; i < args.length; i++) switch (args[i]) {
4041
+ case "--ws-port":
4042
+ case "-p":
4043
+ wsPort = Number.parseInt(args[++i], 10);
4044
+ break;
4045
+ case "--target":
4046
+ case "-t": {
4047
+ const [host, port] = args[++i].split(":");
4048
+ targetHost = host;
4049
+ targetPort = Number.parseInt(port, 10);
4050
+ break;
4051
+ }
4052
+ case "--debug":
4053
+ case "-d":
4054
+ debug = true;
4055
+ break;
4056
+ case "--help":
4057
+ case "-h":
4058
+ console.log(`
4059
+ Cap'n Proto WebSocket-to-TCP Proxy
4060
+
4061
+ Usage: npx @naeemo/capnp proxy [options]
4062
+
4063
+ Options:
4064
+ -p, --ws-port <port> WebSocket server port (default: 8080)
4065
+ -t, --target <host:port> Target TCP service (default: localhost:8081)
4066
+ -d, --debug Enable debug logging
4067
+ -h, --help Show this help
4068
+
4069
+ Example:
4070
+ npx @naeemo/capnp proxy -p 9000 -t 192.168.1.100:7000
4071
+ `);
4072
+ process.exit(0);
4073
+ }
4074
+ const proxy = new CapnpWebSocketProxy({
4075
+ wsPort,
4076
+ targetHost,
4077
+ targetPort,
4078
+ debug
4079
+ });
4080
+ console.log("WebSocket-to-TCP Proxy started");
4081
+ console.log(` WebSocket: ws://localhost:${wsPort}`);
4082
+ console.log(` Target: ${targetHost}:${targetPort}`);
4083
+ proxy.on("connection", () => {
4084
+ console.log(`Active connections: ${proxy.getConnectionCount()}`);
4085
+ });
4086
+ proxy.on("disconnection", () => {
4087
+ console.log(`Active connections: ${proxy.getConnectionCount()}`);
4088
+ });
4089
+ process.on("SIGINT", async () => {
4090
+ console.log("\nShutting down...");
4091
+ await proxy.close();
4092
+ process.exit(0);
4093
+ });
4094
+ }
4095
+
4096
+ //#endregion
4097
+ //#region src/cli-bench.ts
4098
+ /**
4099
+ * Cap'n Proto Benchmark CLI
4100
+ *
4101
+ * Usage: capnp bench [options]
4102
+ */
4103
+ const CLI_VERSION = "0.9.0";
4104
+ function nowUs() {
4105
+ return Number(process.hrtime.bigint()) / 1e3;
4106
+ }
4107
+ /**
4108
+ * 获取测试环境信息
4109
+ */
4110
+ function getEnvironmentInfo() {
4111
+ const cpus = os.cpus();
4112
+ const cpuModel = cpus.length > 0 ? cpus[0].model : "Unknown";
4113
+ return {
4114
+ nodeVersion: process.version,
4115
+ platform: process.platform,
4116
+ arch: process.arch,
4117
+ cpu: cpuModel,
4118
+ cpus: cpus.length,
4119
+ totalMemory: formatBytes(os.totalmem()),
4120
+ freeMemory: formatBytes(os.freemem())
4121
+ };
4122
+ }
4123
+ /**
4124
+ * 格式化字节大小
4125
+ */
4126
+ function formatBytes(bytes) {
4127
+ if (bytes === 0) return "0 B";
4128
+ const k = 1024;
4129
+ const sizes = [
4130
+ "B",
4131
+ "KB",
4132
+ "MB",
4133
+ "GB",
4134
+ "TB"
4135
+ ];
4136
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
4137
+ return `${Number.parseFloat((bytes / k ** i).toFixed(2))} ${sizes[i]}`;
4138
+ }
4139
+ /**
4140
+ * 解析大小字符串(如 "64B", "1KB", "1MB")为字节数
4141
+ */
4142
+ function parseSize(sizeStr) {
4143
+ const match = sizeStr.trim().match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB)?$/i);
4144
+ if (!match) throw new Error(`Invalid size format: ${sizeStr}`);
4145
+ const value = Number.parseFloat(match[1]);
4146
+ const unit = (match[2] || "B").toUpperCase();
4147
+ return Math.floor(value * ({
4148
+ B: 1,
4149
+ KB: 1024,
4150
+ MB: 1024 * 1024,
4151
+ GB: 1024 * 1024 * 1024
4152
+ }[unit] || 1));
4153
+ }
4154
+ /**
4155
+ * 生成测试数据
4156
+ */
4157
+ function generateTestData(sizeBytes) {
4158
+ const dataArraySize = Math.max(1, Math.floor((sizeBytes - 200) / 4));
4159
+ return {
4160
+ id: Date.now(),
4161
+ name: `Test User ${Math.random().toString(36).substring(7)}`,
4162
+ data: Array.from({ length: Math.min(dataArraySize, 1e5) }, (_, i) => i),
4163
+ metadata: {
4164
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4165
+ version: "1.0.0",
4166
+ tags: [
4167
+ "benchmark",
4168
+ "test",
4169
+ "performance"
4170
+ ],
4171
+ nested: { level1: { level2: { value: Math.random() } } }
4172
+ }
4173
+ };
4174
+ }
4175
+ /**
4176
+ * 运行单次基准测试
4177
+ */
4178
+ function runBenchmark(name, serialize, deserialize, getSize, iterations = 1e4) {
4179
+ for (let i = 0; i < 100; i++) deserialize(serialize());
4180
+ const serializeStart = nowUs();
4181
+ const samples = [];
4182
+ for (let i = 0; i < iterations; i++) samples.push(serialize());
4183
+ const serializeTime = (nowUs() - serializeStart) / iterations;
4184
+ const deserializeStart = nowUs();
4185
+ for (const sample of samples) deserialize(sample);
4186
+ const deserializeTime = (nowUs() - deserializeStart) / iterations;
4187
+ const dataSize = getSize(samples[0]);
4188
+ const totalTime = serializeTime + deserializeTime;
4189
+ return {
4190
+ name,
4191
+ serializeTime,
4192
+ deserializeTime,
4193
+ dataSize,
4194
+ opsPerSecond: totalTime > 0 ? 1e6 / totalTime : 0
4195
+ };
4196
+ }
4197
+ function capnpSerialize(data) {
4198
+ const builder = new MessageBuilder();
4199
+ const root = builder.initRoot(2, 3);
4200
+ root.setInt32(0, data.id);
4201
+ root.setText(0, data.name);
4202
+ const dataList = root.initList(1, 4, data.data.length);
4203
+ for (let i = 0; i < data.data.length; i++) dataList.setPrimitive(i, data.data[i]);
4204
+ root.initStruct(2, 1, 1).setText(0, data.metadata.timestamp);
4205
+ return builder.toArrayBuffer();
4206
+ }
4207
+ function capnpDeserialize(buffer) {
4208
+ const root = new MessageReader(buffer).getRoot(2, 3);
4209
+ root.getInt32(0);
4210
+ root.getText(0);
4211
+ const list = root.getList(1, 4);
4212
+ if (list) for (let i = 0; i < Math.min(list.length, 100); i++) list.getPrimitive(i);
4213
+ const metadata = root.getStruct(2, 1, 1);
4214
+ if (metadata) metadata.getText(0);
4215
+ return true;
4216
+ }
4217
+ function jsonSerialize(data) {
4218
+ return JSON.stringify(data);
4219
+ }
4220
+ function jsonDeserialize(jsonStr) {
4221
+ return JSON.parse(jsonStr);
4222
+ }
4223
+ function protobufSerialize(data) {
4224
+ const header = Buffer.alloc(8);
4225
+ header.writeUInt32LE((data.id & 4294967295) >>> 0, 0);
4226
+ header.writeUInt32LE(data.data.length, 4);
4227
+ const nameBuf = Buffer.from(data.name, "utf-8");
4228
+ const nameLen = Buffer.alloc(4);
4229
+ nameLen.writeUInt32LE(nameBuf.length, 0);
4230
+ const dataBuf = Buffer.from(new Int32Array(data.data).buffer);
4231
+ return Buffer.concat([
4232
+ header,
4233
+ nameLen,
4234
+ nameBuf,
4235
+ dataBuf
4236
+ ]);
4237
+ }
4238
+ function protobufDeserialize(buffer) {
4239
+ let offset = 0;
4240
+ buffer.readUInt32LE(offset);
4241
+ offset += 4;
4242
+ const dataLen = buffer.readUInt32LE(offset);
4243
+ offset += 4;
4244
+ const nameLen = buffer.readUInt32LE(offset);
4245
+ offset += 4;
4246
+ offset += nameLen;
4247
+ for (let i = 0; i < Math.min(dataLen, 100); i++) buffer.readInt32LE(offset + i * 4);
4248
+ return true;
4249
+ }
4250
+ /**
4251
+ * 运行所有基准测试
4252
+ */
4253
+ function runAllBenchmarks(sizes, includeJson, includeProtobuf) {
4254
+ const results = [];
4255
+ for (const sizeStr of sizes) {
4256
+ const sizeBytes = parseSize(sizeStr);
4257
+ const testData = generateTestData(sizeBytes);
4258
+ const iterations = Math.max(1e3, Math.min(5e4, Math.floor(1e7 / sizeBytes)));
4259
+ const capnpResult = runBenchmark(`Cap'n Proto (${sizeStr})`, () => capnpSerialize(testData), capnpDeserialize, (data) => data.byteLength, iterations);
4260
+ results.push(capnpResult);
4261
+ if (includeJson) {
4262
+ const jsonResult = runBenchmark(`JSON (${sizeStr})`, () => jsonSerialize(testData), jsonDeserialize, (data) => new TextEncoder().encode(data).length, iterations);
4263
+ results.push(jsonResult);
4264
+ }
4265
+ if (includeProtobuf) {
4266
+ const protobufResult = runBenchmark(`Protobuf (${sizeStr})`, () => protobufSerialize(testData), protobufDeserialize, (data) => data.length, iterations);
4267
+ results.push(protobufResult);
4268
+ }
4269
+ }
4270
+ return results;
4271
+ }
4272
+ /**
4273
+ * 格式化基准测试报告为 Markdown
4274
+ */
4275
+ function formatMarkdownReport(report) {
4276
+ const lines = [];
4277
+ lines.push("# Cap'n Proto Benchmark Report");
4278
+ lines.push("");
4279
+ lines.push(`Generated: ${report.generatedAt}`);
4280
+ lines.push("");
4281
+ lines.push("## Environment");
4282
+ lines.push("");
4283
+ lines.push(`- **Node.js**: ${report.environment.nodeVersion}`);
4284
+ lines.push(`- **Platform**: ${report.environment.platform} (${report.environment.arch})`);
4285
+ lines.push(`- **CPU**: ${report.environment.cpu}`);
4286
+ lines.push(`- **CPU Cores**: ${report.environment.cpus}`);
4287
+ lines.push(`- **Total Memory**: ${report.environment.totalMemory}`);
4288
+ lines.push(`- **Free Memory**: ${report.environment.freeMemory}`);
4289
+ lines.push("");
4290
+ lines.push("## Results");
4291
+ lines.push("");
4292
+ lines.push("| Format | Payload Size | Serialize (μs) | Deserialize (μs) | Data Size | Ops/Sec |");
4293
+ lines.push("|--------|--------------|----------------|------------------|-----------|---------|");
4294
+ for (const result of report.results) lines.push(`| ${result.name.padEnd(20)} | ${formatBytes(result.dataSize).padStart(10)} | ${result.serializeTime.toFixed(3).padStart(14)} | ${result.deserializeTime.toFixed(3).padStart(16)} | ${result.dataSize.toString().padStart(9)} | ${result.opsPerSecond.toFixed(0).padStart(7)} |`);
4295
+ lines.push("");
4296
+ if (report.comparisons.length > 1) {
4297
+ lines.push("## Comparison Summary");
4298
+ lines.push("");
4299
+ const groupedBySize = /* @__PURE__ */ new Map();
4300
+ for (const result of report.results) {
4301
+ const sizeMatch = result.name.match(/\(([^)]+)\)/);
4302
+ const size = sizeMatch ? sizeMatch[1] : "unknown";
4303
+ if (!groupedBySize.has(size)) groupedBySize.set(size, []);
4304
+ groupedBySize.get(size).push(result);
4305
+ }
4306
+ for (const [size, results] of groupedBySize) if (results.length > 1) {
4307
+ lines.push(`### ${size} Payload`);
4308
+ lines.push("");
4309
+ const fastest = results.reduce((a, b) => a.opsPerSecond > b.opsPerSecond ? a : b);
4310
+ lines.push(`- **Fastest**: ${fastest.name.split(" ")[0]} (${fastest.opsPerSecond.toFixed(0)} ops/sec)`);
4311
+ const smallest = results.reduce((a, b) => a.dataSize < b.dataSize ? a : b);
4312
+ lines.push(`- **Smallest**: ${smallest.name.split(" ")[0]} (${formatBytes(smallest.dataSize)})`);
4313
+ const capnpResult = results.find((r) => r.name.includes("Cap'n Proto"));
4314
+ if (capnpResult) {
4315
+ for (const result of results) if (result !== capnpResult) {
4316
+ const format = result.name.split(" ")[0];
4317
+ const speedup = capnpResult.opsPerSecond / result.opsPerSecond;
4318
+ const sizeDiff = (capnpResult.dataSize - result.dataSize) / result.dataSize * 100;
4319
+ lines.push(`- vs ${format}: ${speedup > 1 ? `**${speedup.toFixed(2)}x faster**` : `${(1 / speedup).toFixed(2)}x slower`}, data size ${sizeDiff > 0 ? "+" : ""}${sizeDiff.toFixed(1)}%`);
4320
+ }
4321
+ }
4322
+ lines.push("");
4323
+ }
4324
+ }
4325
+ lines.push("## Conclusion");
4326
+ lines.push("");
4327
+ const capnpResults = report.results.filter((r) => r.name.includes("Cap'n Proto"));
4328
+ if (capnpResults.length > 0) {
4329
+ const avgOps = capnpResults.reduce((sum, r) => sum + r.opsPerSecond, 0) / capnpResults.length;
4330
+ lines.push(`Cap'n Proto achieved an average throughput of **${avgOps.toFixed(0)} ops/sec** across all tested payload sizes.`);
4331
+ lines.push("");
4332
+ if (report.comparisons.length > 1) {
4333
+ lines.push("Based on the benchmark results:");
4334
+ lines.push("");
4335
+ lines.push("- Cap'n Proto offers competitive serialization performance");
4336
+ lines.push("- Zero-copy architecture provides advantages for large payloads");
4337
+ lines.push("- Compact binary format reduces network overhead");
4338
+ }
4339
+ }
4340
+ lines.push("");
4341
+ lines.push("---");
4342
+ lines.push(`*Generated by Cap'n Proto Benchmark CLI v${CLI_VERSION}*`);
4343
+ return lines.join("\n");
4344
+ }
4345
+ /**
4346
+ * 格式化为 CSV
4347
+ */
4348
+ function formatCsvReport(report) {
4349
+ const lines = [];
4350
+ lines.push("Format,Payload Size,Serialize (μs),Deserialize (μs),Data Size (bytes),Ops/Sec");
4351
+ for (const result of report.results) lines.push(`${result.name},${result.dataSize},${result.serializeTime},${result.deserializeTime},${result.dataSize},${result.opsPerSecond}`);
4352
+ return lines.join("\n");
4353
+ }
4354
+ /**
4355
+ * 格式化报告为终端输出(类似 audit 命令风格)
4356
+ */
4357
+ function formatTerminalReport(report) {
4358
+ const lines = [];
4359
+ lines.push("=".repeat(70));
4360
+ lines.push("CAP'N PROTO BENCHMARK REPORT");
4361
+ lines.push("=".repeat(70));
4362
+ lines.push("");
4363
+ lines.push("Environment:");
4364
+ lines.push(` Node.js: ${report.environment.nodeVersion}`);
4365
+ lines.push(` Platform: ${report.environment.platform} (${report.environment.arch})`);
4366
+ lines.push(` CPU: ${report.environment.cpu}`);
4367
+ lines.push(` CPU Cores: ${report.environment.cpus}`);
4368
+ lines.push(` Memory: ${report.environment.freeMemory} / ${report.environment.totalMemory}`);
4369
+ lines.push("");
4370
+ lines.push("Benchmark Results:");
4371
+ lines.push("-".repeat(70));
4372
+ lines.push(`${"Format".padEnd(22)} ${"Size".padStart(10)} ${"Serialize".padStart(12)} ${"Deserialize".padStart(12)} ${"Ops/Sec".padStart(12)}`);
4373
+ lines.push("-".repeat(70));
4374
+ for (const result of report.results) {
4375
+ const format = result.name.padEnd(22);
4376
+ const size = formatBytes(result.dataSize).padStart(10);
4377
+ const ser = `${result.serializeTime.toFixed(2)} μs`.padStart(12);
4378
+ const deser = `${result.deserializeTime.toFixed(2)} μs`.padStart(12);
4379
+ const ops = result.opsPerSecond.toFixed(0).padStart(12);
4380
+ lines.push(`${format} ${size} ${ser} ${deser} ${ops}`);
4381
+ }
4382
+ lines.push("-".repeat(70));
4383
+ lines.push("");
4384
+ if (report.comparisons.length > 1) {
4385
+ lines.push("Comparison Summary:");
4386
+ lines.push("");
4387
+ const groupedBySize = /* @__PURE__ */ new Map();
4388
+ for (const result of report.results) {
4389
+ const sizeMatch = result.name.match(/\(([^)]+)\)/);
4390
+ const size = sizeMatch ? sizeMatch[1] : "unknown";
4391
+ if (!groupedBySize.has(size)) groupedBySize.set(size, []);
4392
+ groupedBySize.get(size).push(result);
4393
+ }
4394
+ for (const [size, results] of groupedBySize) if (results.length > 1) {
4395
+ lines.push(` ${size} Payload:`);
4396
+ const capnpResult = results.find((r) => r.name.includes("Cap'n Proto"));
4397
+ if (capnpResult) {
4398
+ for (const result of results) if (result !== capnpResult) {
4399
+ const format = result.name.split(" ")[0];
4400
+ const speedup = capnpResult.opsPerSecond / result.opsPerSecond;
4401
+ const icon = speedup > 1 ? "✅" : "⚠️";
4402
+ lines.push(` ${icon} vs ${format}: ${speedup.toFixed(2)}x ${speedup > 1 ? "faster" : "slower"}`);
4403
+ }
4404
+ }
4405
+ lines.push("");
4406
+ }
4407
+ }
4408
+ lines.push("Conclusion:");
4409
+ const capnpResults = report.results.filter((r) => r.name.includes("Cap'n Proto"));
4410
+ if (capnpResults.length > 0) {
4411
+ const avgOps = capnpResults.reduce((sum, r) => sum + r.opsPerSecond, 0) / capnpResults.length;
4412
+ lines.push(` Cap'n Proto average: ${avgOps.toFixed(0)} ops/sec`);
4413
+ }
4414
+ lines.push("");
4415
+ lines.push("=".repeat(70));
4416
+ return lines.join("\n");
4417
+ }
4418
+ function printUsage() {
4419
+ console.log(`
4420
+ Cap'n Proto Benchmark CLI v${CLI_VERSION}
4421
+
4422
+ Usage: capnp bench [options]
4423
+
4424
+ Options:
4425
+ --sizes <list> Comma-separated payload sizes (default: 1KB,10KB,100KB)
4426
+ Examples: 64B,1KB,1MB or 100B,500B,1KB,10KB
4427
+ --vs-json Include JSON comparison
4428
+ --vs-protobuf Include Protobuf comparison
4429
+ -o, --output <file> Write report to file
4430
+ --format <format> Output format: markdown, json, csv (default: terminal)
4431
+ -h, --help Show this help
4432
+
4433
+ Examples:
4434
+ capnp bench
4435
+ capnp bench --sizes 64B,1KB,1MB --vs-json
4436
+ capnp bench --sizes 100KB --vs-json --vs-protobuf --output report.md --format markdown
4437
+ capnp bench --sizes 10KB,100KB --vs-json --format json -o results.json
4438
+ `);
4439
+ }
4440
+ function parseArgs(args) {
4441
+ const options = {};
4442
+ for (let i = 0; i < args.length; i++) {
4443
+ const arg = args[i];
4444
+ if (arg === "-h" || arg === "--help") {
4445
+ printUsage();
4446
+ process.exit(0);
4447
+ }
4448
+ if (arg === "--sizes") {
4449
+ const sizesStr = args[++i];
4450
+ if (!sizesStr) {
4451
+ console.error("Error: --sizes requires a value");
4452
+ process.exit(1);
4453
+ }
4454
+ options.sizes = sizesStr.split(",").map((s) => s.trim());
4455
+ } else if (arg === "--vs-json") options.vsJson = true;
4456
+ else if (arg === "--vs-protobuf") options.vsProtobuf = true;
4457
+ else if (arg === "-o" || arg === "--output") options.output = args[++i];
4458
+ else if (arg === "--format") {
4459
+ const format = args[++i];
4460
+ if (format !== "markdown" && format !== "json" && format !== "csv" && format !== "terminal") {
4461
+ console.error("Error: --format must be one of: markdown, json, csv, terminal");
4462
+ process.exit(1);
4463
+ }
4464
+ options.format = format;
4465
+ }
4466
+ }
4467
+ if (!options.sizes) options.sizes = [
4468
+ "1KB",
4469
+ "10KB",
4470
+ "100KB"
4471
+ ];
4472
+ if (!options.format) options.format = options.output ? "markdown" : "terminal";
4473
+ return options;
4474
+ }
4475
+ async function run(args) {
4476
+ const options = parseArgs(args);
4477
+ console.log("Running Cap'n Proto Benchmark...");
4478
+ console.log("");
4479
+ const env = getEnvironmentInfo();
4480
+ console.log(`Environment: Node.js ${env.nodeVersion} on ${env.platform} (${env.arch})`);
4481
+ console.log(`CPU: ${env.cpu} (${env.cpus} cores)`);
4482
+ console.log("");
4483
+ const comparisons = ["Cap'n Proto"];
4484
+ if (options.vsJson) comparisons.push("JSON");
4485
+ if (options.vsProtobuf) comparisons.push("Protobuf");
4486
+ console.log(`Testing payload sizes: ${options.sizes?.join(", ")}`);
4487
+ console.log(`Comparisons: ${comparisons.join(", ")}`);
4488
+ console.log("");
4489
+ const report = {
4490
+ environment: env,
4491
+ results: runAllBenchmarks(options.sizes || [
4492
+ "1KB",
4493
+ "10KB",
4494
+ "100KB"
4495
+ ], options.vsJson || false, options.vsProtobuf || false),
4496
+ sizes: options.sizes || [
4497
+ "1KB",
4498
+ "10KB",
4499
+ "100KB"
4500
+ ],
4501
+ comparisons,
4502
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
4503
+ };
4504
+ let output;
4505
+ switch (options.format) {
4506
+ case "json":
4507
+ output = JSON.stringify(report, null, 2);
4508
+ break;
4509
+ case "csv":
4510
+ output = formatCsvReport(report);
4511
+ break;
4512
+ case "markdown":
4513
+ output = formatMarkdownReport(report);
4514
+ break;
4515
+ default:
4516
+ output = formatTerminalReport(report);
4517
+ break;
4518
+ }
4519
+ if (options.output) {
4520
+ writeFileSync(options.output, output, "utf-8");
4521
+ console.log(`Report written to: ${options.output}`);
4522
+ } else console.log(output);
4523
+ process.exit(0);
4524
+ }
4525
+
4526
+ //#endregion
4527
+ export { run };
4528
+ //# sourceMappingURL=cli-bench-bkR1vGK8.js.map