@discordjs/ws 1.1.1 → 1.1.2-dev.1717589074-346d1be72

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.
@@ -119,7 +119,6 @@ import { clearInterval, clearTimeout, setInterval, setTimeout } from "node:timer
119
119
  import { setTimeout as sleep2 } from "node:timers/promises";
120
120
  import { URLSearchParams } from "node:url";
121
121
  import { TextDecoder } from "node:util";
122
- import { inflate } from "node:zlib";
123
122
  import { Collection as Collection6 } from "@discordjs/collection";
124
123
  import { lazy as lazy2, shouldUseGlobalFetchAndWebSocket } from "@discordjs/util";
125
124
  import { AsyncQueue as AsyncQueue2 } from "@sapphire/async-queue";
@@ -274,14 +273,23 @@ var SimpleIdentifyThrottler = class {
274
273
  };
275
274
 
276
275
  // src/utils/constants.ts
276
+ var CompressionMethod = /* @__PURE__ */ ((CompressionMethod2) => {
277
+ CompressionMethod2[CompressionMethod2["ZlibNative"] = 0] = "ZlibNative";
278
+ CompressionMethod2[CompressionMethod2["ZlibSync"] = 1] = "ZlibSync";
279
+ return CompressionMethod2;
280
+ })(CompressionMethod || {});
277
281
  var DefaultDeviceProperty = `@discordjs/ws [VI]{{inject}}[/VI]`;
278
282
  var getDefaultSessionStore = lazy(() => new Collection5());
283
+ var CompressionParameterMap = {
284
+ [0 /* ZlibNative */]: "zlib-stream",
285
+ [1 /* ZlibSync */]: "zlib-stream"
286
+ };
279
287
  var DefaultWebSocketManagerOptions = {
280
288
  async buildIdentifyThrottler(manager) {
281
289
  const info = await manager.fetchGatewayInformation();
282
290
  return new SimpleIdentifyThrottler(info.session_start_limit.max_concurrency);
283
291
  },
284
- buildStrategy: (manager) => new SimpleShardingStrategy(manager),
292
+ buildStrategy: /* @__PURE__ */ __name((manager) => new SimpleShardingStrategy(manager), "buildStrategy"),
285
293
  shardCount: null,
286
294
  shardIds: null,
287
295
  largeThreshold: null,
@@ -294,6 +302,7 @@ var DefaultWebSocketManagerOptions = {
294
302
  version: APIVersion,
295
303
  encoding: "json" /* JSON */,
296
304
  compression: null,
305
+ useIdentifyCompression: false,
297
306
  retrieveSessionInfo(shardId) {
298
307
  const store = getDefaultSessionStore();
299
308
  return store.get(shardId) ?? null;
@@ -325,6 +334,7 @@ __name(getInitialSendRateLimitState, "getInitialSendRateLimitState");
325
334
 
326
335
  // src/ws/WebSocketShard.ts
327
336
  var getZlibSync = lazy2(async () => import("zlib-sync").then((mod) => mod.default).catch(() => null));
337
+ var getNativeZlib = lazy2(async () => import("node:zlib").then((mod) => mod).catch(() => null));
328
338
  var WebSocketShardEvents = /* @__PURE__ */ ((WebSocketShardEvents2) => {
329
339
  WebSocketShardEvents2["Closed"] = "closed";
330
340
  WebSocketShardEvents2["Debug"] = "debug";
@@ -347,8 +357,8 @@ var WebSocketShard = class extends AsyncEventEmitter {
347
357
  __name(this, "WebSocketShard");
348
358
  }
349
359
  connection = null;
350
- useIdentifyCompress = false;
351
- inflate = null;
360
+ nativeInflate = null;
361
+ zLibSyncInflate = null;
352
362
  textDecoder = new TextDecoder();
353
363
  replayedEvents = 0;
354
364
  isAck = true;
@@ -365,6 +375,16 @@ var WebSocketShard = class extends AsyncEventEmitter {
365
375
  strategy;
366
376
  id;
367
377
  #status = 0 /* Idle */;
378
+ identifyCompressionEnabled = false;
379
+ /**
380
+ * @privateRemarks
381
+ *
382
+ * This is needed because `this.strategy.options.compression` is not an actual reflection of the compression method
383
+ * used, but rather the compression method that the user wants to use. This is because the libraries could just be missing.
384
+ */
385
+ get transportCompressionEnabled() {
386
+ return this.strategy.options.compression !== null && (this.nativeInflate ?? this.zLibSyncInflate) !== null;
387
+ }
368
388
  get status() {
369
389
  return this.#status;
370
390
  }
@@ -396,21 +416,53 @@ var WebSocketShard = class extends AsyncEventEmitter {
396
416
  if (this.#status !== 0 /* Idle */) {
397
417
  throw new Error("Tried to connect a shard that wasn't idle");
398
418
  }
399
- const { version, encoding, compression } = this.strategy.options;
419
+ const { version, encoding, compression, useIdentifyCompression } = this.strategy.options;
420
+ this.identifyCompressionEnabled = useIdentifyCompression;
400
421
  const params = new URLSearchParams({ v: version, encoding });
401
- if (compression) {
402
- const zlib = await getZlibSync();
403
- if (zlib) {
404
- params.append("compress", compression);
405
- this.inflate = new zlib.Inflate({
406
- chunkSize: 65535,
407
- to: "string"
408
- });
409
- } else if (!this.useIdentifyCompress) {
410
- this.useIdentifyCompress = true;
411
- console.warn(
412
- "WebSocketShard: Compression is enabled but zlib-sync is not installed, falling back to identify compress"
413
- );
422
+ if (compression !== null) {
423
+ if (useIdentifyCompression) {
424
+ console.warn("WebSocketShard: transport compression is enabled, disabling identify compression");
425
+ this.identifyCompressionEnabled = false;
426
+ }
427
+ params.append("compress", CompressionParameterMap[compression]);
428
+ switch (compression) {
429
+ case 0 /* ZlibNative */: {
430
+ const zlib = await getNativeZlib();
431
+ if (zlib) {
432
+ const inflate = zlib.createInflate({
433
+ chunkSize: 65535,
434
+ flush: zlib.constants.Z_SYNC_FLUSH
435
+ });
436
+ inflate.on("error", (error) => {
437
+ this.emit("error" /* Error */, { error });
438
+ });
439
+ this.nativeInflate = inflate;
440
+ } else {
441
+ console.warn("WebSocketShard: Compression is set to native but node:zlib is not available.");
442
+ params.delete("compress");
443
+ }
444
+ break;
445
+ }
446
+ case 1 /* ZlibSync */: {
447
+ const zlib = await getZlibSync();
448
+ if (zlib) {
449
+ this.zLibSyncInflate = new zlib.Inflate({
450
+ chunkSize: 65535,
451
+ to: "string"
452
+ });
453
+ } else {
454
+ console.warn("WebSocketShard: Compression is set to zlib-sync, but it is not installed.");
455
+ params.delete("compress");
456
+ }
457
+ break;
458
+ }
459
+ }
460
+ }
461
+ if (this.identifyCompressionEnabled) {
462
+ const zlib = await getNativeZlib();
463
+ if (!zlib) {
464
+ console.warn("WebSocketShard: Identify compression is enabled, but node:zlib is not available.");
465
+ this.identifyCompressionEnabled = false;
414
466
  }
415
467
  }
416
468
  const session = await this.strategy.retrieveSessionInfo(this.id);
@@ -604,24 +656,25 @@ var WebSocketShard = class extends AsyncEventEmitter {
604
656
  `shard id: ${this.id.toString()}`,
605
657
  `shard count: ${this.strategy.options.shardCount}`,
606
658
  `intents: ${this.strategy.options.intents}`,
607
- `compression: ${this.inflate ? "zlib-stream" : this.useIdentifyCompress ? "identify" : "none"}`
659
+ `compression: ${this.transportCompressionEnabled ? CompressionParameterMap[this.strategy.options.compression] : this.identifyCompressionEnabled ? "identify" : "none"}`
608
660
  ]);
609
- const d = {
661
+ const data = {
610
662
  token: this.strategy.options.token,
611
663
  properties: this.strategy.options.identifyProperties,
612
664
  intents: this.strategy.options.intents,
613
- compress: this.useIdentifyCompress,
665
+ compress: this.identifyCompressionEnabled,
614
666
  shard: [this.id, this.strategy.options.shardCount]
615
667
  };
616
668
  if (this.strategy.options.largeThreshold) {
617
- d.large_threshold = this.strategy.options.largeThreshold;
669
+ data.large_threshold = this.strategy.options.largeThreshold;
618
670
  }
619
671
  if (this.strategy.options.initialPresence) {
620
- d.presence = this.strategy.options.initialPresence;
672
+ data.presence = this.strategy.options.initialPresence;
621
673
  }
622
674
  await this.send({
623
675
  op: GatewayOpcodes2.Identify,
624
- d
676
+ // eslint-disable-next-line id-length
677
+ d: data
625
678
  });
626
679
  await this.waitForEvent("ready" /* Ready */, this.strategy.options.readyTimeout);
627
680
  }
@@ -636,6 +689,7 @@ var WebSocketShard = class extends AsyncEventEmitter {
636
689
  this.replayedEvents = 0;
637
690
  return this.send({
638
691
  op: GatewayOpcodes2.Resume,
692
+ // eslint-disable-next-line id-length
639
693
  d: {
640
694
  token: this.strategy.options.token,
641
695
  seq: session.sequence,
@@ -650,11 +704,18 @@ var WebSocketShard = class extends AsyncEventEmitter {
650
704
  const session = await this.strategy.retrieveSessionInfo(this.id);
651
705
  await this.send({
652
706
  op: GatewayOpcodes2.Heartbeat,
707
+ // eslint-disable-next-line id-length
653
708
  d: session?.sequence ?? null
654
709
  });
655
710
  this.lastHeartbeatAt = Date.now();
656
711
  this.isAck = false;
657
712
  }
713
+ parseInflateResult(result) {
714
+ if (!result) {
715
+ return null;
716
+ }
717
+ return JSON.parse(typeof result === "string" ? result : this.textDecoder.decode(result));
718
+ }
658
719
  async unpackMessage(data, isBinary) {
659
720
  if (!isBinary) {
660
721
  try {
@@ -664,9 +725,10 @@ var WebSocketShard = class extends AsyncEventEmitter {
664
725
  }
665
726
  }
666
727
  const decompressable = new Uint8Array(data);
667
- if (this.useIdentifyCompress) {
668
- return new Promise((resolve2, reject) => {
669
- inflate(decompressable, { chunkSize: 65535 }, (err, result) => {
728
+ if (this.identifyCompressionEnabled) {
729
+ return new Promise(async (resolve2, reject) => {
730
+ const zlib = await getNativeZlib();
731
+ zlib.inflate(decompressable, { chunkSize: 65535 }, (err, result) => {
670
732
  if (err) {
671
733
  reject(err);
672
734
  return;
@@ -675,30 +737,37 @@ var WebSocketShard = class extends AsyncEventEmitter {
675
737
  });
676
738
  });
677
739
  }
678
- if (this.inflate) {
679
- const l = decompressable.length;
680
- const flush = l >= 4 && decompressable[l - 4] === 0 && decompressable[l - 3] === 0 && decompressable[l - 2] === 255 && decompressable[l - 1] === 255;
681
- const zlib = await getZlibSync();
682
- this.inflate.push(Buffer2.from(decompressable), flush ? zlib.Z_SYNC_FLUSH : zlib.Z_NO_FLUSH);
683
- if (this.inflate.err) {
684
- this.emit("error" /* Error */, {
685
- error: new Error(`${this.inflate.err}${this.inflate.msg ? `: ${this.inflate.msg}` : ""}`)
686
- });
687
- }
688
- if (!flush) {
689
- return null;
690
- }
691
- const { result } = this.inflate;
692
- if (!result) {
693
- return null;
740
+ if (this.transportCompressionEnabled) {
741
+ const flush = decompressable.length >= 4 && decompressable.at(-4) === 0 && decompressable.at(-3) === 0 && decompressable.at(-2) === 255 && decompressable.at(-1) === 255;
742
+ if (this.nativeInflate) {
743
+ this.nativeInflate.write(decompressable, "binary");
744
+ if (!flush) {
745
+ return null;
746
+ }
747
+ const [result] = await once2(this.nativeInflate, "data");
748
+ return this.parseInflateResult(result);
749
+ } else if (this.zLibSyncInflate) {
750
+ const zLibSync = await getZlibSync();
751
+ this.zLibSyncInflate.push(Buffer2.from(decompressable), flush ? zLibSync.Z_SYNC_FLUSH : zLibSync.Z_NO_FLUSH);
752
+ if (this.zLibSyncInflate.err) {
753
+ this.emit("error" /* Error */, {
754
+ error: new Error(
755
+ `${this.zLibSyncInflate.err}${this.zLibSyncInflate.msg ? `: ${this.zLibSyncInflate.msg}` : ""}`
756
+ )
757
+ });
758
+ }
759
+ if (!flush) {
760
+ return null;
761
+ }
762
+ const { result } = this.zLibSyncInflate;
763
+ return this.parseInflateResult(result);
694
764
  }
695
- return JSON.parse(typeof result === "string" ? result : this.textDecoder.decode(result));
696
765
  }
697
766
  this.debug([
698
767
  "Received a message we were unable to decompress",
699
768
  `isBinary: ${isBinary.toString()}`,
700
- `useIdentifyCompress: ${this.useIdentifyCompress.toString()}`,
701
- `inflate: ${Boolean(this.inflate).toString()}`
769
+ `identifyCompressionEnabled: ${this.identifyCompressionEnabled.toString()}`,
770
+ `inflate: ${this.transportCompressionEnabled ? CompressionMethod[this.strategy.options.compression] : "none"}`
702
771
  ]);
703
772
  return null;
704
773
  }
@@ -907,7 +976,7 @@ var WebSocketShard = class extends AsyncEventEmitter {
907
976
  }
908
977
  debug(messages) {
909
978
  const message = `${messages[0]}${messages.length > 1 ? `
910
- ${messages.slice(1).map((m) => ` ${m}`).join("\n")}` : ""}`;
979
+ ${messages.slice(1).map((message2) => ` ${message2}`).join("\n")}` : ""}`;
911
980
  this.emit("debug" /* Debug */, { message });
912
981
  }
913
982
  };