vitest 0.0.115 → 0.0.116

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