diff --git a/.eslintrc.json b/.eslintrc.json index c6345fc2..adf289db 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -346,6 +346,7 @@ ], "unicorn/prefer-event-target": "off", "@typescript-eslint/no-unsafe-declaration-merging": "off", - "@typescript-eslint/no-unsafe-enum-comparison": "off" + "@typescript-eslint/no-unsafe-enum-comparison": "off", + "unicorn/prefer-ternary": "off" } } diff --git a/README.md b/README.md index c74615f3..09639737 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,10 @@ The documentation under `dev` is always for the latest commit. If something isn'
### Optional Dependencies -* `pako` - Compression (gateway) -* `zlib-sync` - Compression (gateway, faster than pako) +All compression options are mutually exclusive. +* `pako` - zlib Compression (gateway) +* `zlib-sync` - zlib Compression (gateway, faster than pako) +* `fzstd` - Zstandard Compression (gateway) * `erlpack` - Encoding (gateway, alternative to JSON) ## Links diff --git a/lib/gateway/Shard.ts b/lib/gateway/Shard.ts index 36aca7a6..04e35ade 100644 --- a/lib/gateway/Shard.ts +++ b/lib/gateway/Shard.ts @@ -1,5 +1,6 @@ /** @module Shard */ import type ShardManager from "./ShardManager"; +import type Compression from "./compression/base"; import type Client from "../Client"; import TypedEmitter from "../util/TypedEmitter"; import Bucket from "../rest/Bucket"; @@ -23,13 +24,8 @@ import type { ShardEvents } from "../types/events"; import GatewayError, { DependencyError } from "../util/Errors"; import ClientApplication from "../structures/ClientApplication"; import WebSocket, { type Data } from "ws"; -import type Pako from "pako"; -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import type { Inflate } from "zlib-sync"; import { randomBytes } from "node:crypto"; import { inspect } from "node:util"; -import assert from "node:assert"; /* eslint-disable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-redundant-type-constituents, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, unicorn/prefer-module, @typescript-eslint/no-unsafe-member-access */ // @ts-ignore @@ -37,29 +33,17 @@ let Erlpack: typeof import("erlpack") | undefined; try { Erlpack = require("erlpack"); } catch {} -// @ts-ignore -let ZlibSync: typeof import("pako") | typeof import("zlib-sync") | undefined, zlibConstants: typeof import("pako").constants | typeof import("zlib-sync") | undefined; -try { - ZlibSync = require("zlib-sync"); - zlibConstants = require("zlib-sync"); -} catch { - try { - ZlibSync = require("pako"); - zlibConstants = require("pako").constants; - } catch {} -} /* eslint-enable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-redundant-type-constituents, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, unicorn/prefer-module */ /** Represents a gateway connection to Discord. See {@link ShardEvents | Shard Events} for a list of events. */ export default class Shard extends TypedEmitter { + private _compressor: Compression | undefined; private _connectTimeout: NodeJS.Timeout | null; private _getAllUsersCount: Record; private _getAllUsersQueue: Array; private _guildCreateTimeout: NodeJS.Timeout | null; private _heartbeatInterval: NodeJS.Timeout | null; private _requestMembersPromise: Record; received: number; timeout: NodeJS.Timeout; reject(reason?: unknown): void; resolve(value: unknown): void; }>; - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents - private _sharedZLib!: Pako.Inflate | Inflate; client!: Client; connectAttempts: number; connecting: boolean; @@ -156,7 +140,8 @@ export default class Shard extends TypedEmitter { } this.resumeURL = `${url}?v=${GATEWAY_VERSION}&encoding=${Erlpack ? "etf" : "json"}`; if (this.client.shards.options.compress) { - this.resumeURL += "&compress=zlib-stream"; + const type = this.client.shards.options.compress === "zstd-stream" ? "zstd-stream" : "zlib-stream"; + this.resumeURL += `&compress=${type}`; } this.sessionID = data.session_id; @@ -221,12 +206,34 @@ export default class Shard extends TypedEmitter { } this.status = "connecting"; if (this.client.shards.options.compress) { - if (!ZlibSync) { - throw new DependencyError("Cannot use compression without pako or zlib-sync."); + const type = this.client.shards.options.compress; + /* eslint-disable @typescript-eslint/no-var-requires, unicorn/prefer-module */ + if (type === "zstd-stream") { + if (!this.client.util._isModuleInstalled("fzstd")) { + throw new DependencyError("Cannot use zstd based compression without fzstd."); + } + this.client.emit("debug", "Initializing zstd-based compression with fzstd."); + const ZstdCompression = (require(`${__dirname}/compression/zstd`) as { default: new(shard: Shard) => Compression; }).default; + this._compressor = new ZstdCompression(this); + } else if (type === "zlib-stream") { + const hasZlibSync = this.client.util._isModuleInstalled("zlib-sync"); + const hasPako = this.client.util._isModuleInstalled("pako"); + + if (hasZlibSync) { + this.client.emit("debug", "Initializing zlib-based compression with zlib-sync."); + const ZlibSyncCompression = (require(`${__dirname}/compression/zlib-sync`) as { default: new(shard: Shard) => Compression; }).default; + this._compressor = new ZlibSyncCompression(this); + } else if (hasPako) { + this.client.emit("debug", "Initializing zlib-based compression with pako."); + const PakoCompression = (require(`${__dirname}/compression/pako`) as { default: new(shard: Shard) => Compression; }).default; + this._compressor = new PakoCompression(this); + } else { + throw new DependencyError("Cannot use zlib based compression without pako or zlib-sync."); + } + } else { + throw new TypeError(`Invalid compression type "${type as string}".`); } - this.client.emit("debug", "Initializing zlib-sync-based compression."); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - this._sharedZLib = new ZlibSync.Inflate({ chunkSize: 128 * 1024 }); + /* eslint-enable @typescript-eslint/no-var-requires, unicorn/prefer-module */ } if (!this.client.shards.options.override.gatewayURLIsResumeURL && this.sessionID) { if (this.resumeURL === null) { @@ -443,7 +450,7 @@ export default class Shard extends TypedEmitter { } /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-argument */ - private onWSMessage(data: Data): void { + private async onWSMessage(data: Data): Promise { if (typeof data === "string") { data = Buffer.from(data); } @@ -457,54 +464,28 @@ export default class Shard extends TypedEmitter { data = Buffer.concat(data); } - const is = (input: unknown): input is T => true; - assert(is(data)); + const buf = data as Buffer; if (this.client.shards.options.compress) { - if (data.length >= 4 && data.readUInt32BE(data.length - 4) === 0xFFFF) { - // store the current pointer for slicing buffers after pushing. - const currentPointer: number | undefined = this._sharedZLib.strm?.next_out; - this._sharedZLib.push(data, zlibConstants!.Z_SYNC_FLUSH); - if (this._sharedZLib.err) { - this.client.emit("error", new GatewayError(`zlib error ${this._sharedZLib.err}: ${this._sharedZLib.msg ?? ""}`, 0)); - return; - } - - if (currentPointer === undefined) { - // decompression support by zlib-sync - data = Buffer.from(this._sharedZLib.result ?? ""); - } else if (this._sharedZLib.chunks.length === 0) { - // decompression support by pako. The current buffer hasn't been flushed - data = Buffer.from(this._sharedZLib.strm!.output.slice(currentPointer)); - } else { - // decompression support by pako. Buffers have been flushed once or more times. - data = Buffer.concat([ - this._sharedZLib.chunks[0].slice(currentPointer), - ...this._sharedZLib.chunks.slice(1), - this._sharedZLib.strm.output - ]); - this._sharedZLib.chunks = []; - } - - assert(is(data)); + let result = await this._compressor!.decompress(buf); + if (result === null) { + return; + } - if (Erlpack) { - return this.onPacket(Erlpack.unpack(data as Buffer) as AnyReceivePacket); - } else { - // After the valid data, all the remaining octets are filled with zero, so remove them. - let last = data.length - 1; - if (data[last] === 0) { - while (data[last - 1] === 0 && last > 0) last--; - data = data.subarray(0, last); - } - return this.onPacket(JSON.parse(String(data)) as AnyReceivePacket); - } + if (Erlpack) { + return this.onPacket(Erlpack.unpack(result) as AnyReceivePacket); } else { - this._sharedZLib.push(data, false); + // After the valid data, all the remaining octets are filled with zero, so remove them. + let last = result.length - 1; + if (result[last] === 0) { + while (result[last - 1] === 0 && last > 0) last--; + result = result.subarray(0, last); + } + return this.onPacket(JSON.parse(String(result)) as AnyReceivePacket); } } else if (Erlpack) { - return this.onPacket(Erlpack.unpack(data) as AnyReceivePacket); + return this.onPacket(Erlpack.unpack(buf) as AnyReceivePacket); } else { - return this.onPacket(JSON.parse(data.toString()) as AnyReceivePacket); + return this.onPacket(JSON.parse(String(buf)) as AnyReceivePacket); } } catch (err) { this.client.emit("error", err as Error, this.id); @@ -776,7 +757,7 @@ export default class Shard extends TypedEmitter { const func = (): void => { if (++i >= waitFor && this.ws && this.ws.readyState === WebSocket.OPEN) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - const d: string = Erlpack ? Erlpack.pack({ op, d: data }) : JSON.stringify({ op, d: data }); + const d: string | Buffer = Erlpack ? Erlpack.pack({ op, d: data }) : JSON.stringify({ op, d: data }); this.ws.send(d); if (typeof data === "object" && data && "token" in data) { (data as { token: string; }).token = "[REMOVED]"; diff --git a/lib/gateway/ShardManager.ts b/lib/gateway/ShardManager.ts index e651c75f..13fcb8e5 100644 --- a/lib/gateway/ShardManager.ts +++ b/lib/gateway/ShardManager.ts @@ -22,6 +22,7 @@ try { /* eslint-enable @typescript-eslint/ban-ts-comment, @typescript-eslint/no-redundant-type-constituents, @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, unicorn/prefer-module */ +let __compressionTrueDeprecationWarning = 0; /** A manager for all the client's shards. */ export default class ShardManager extends Collection { private _buckets: Record; @@ -39,7 +40,7 @@ export default class ShardManager extends Collection { this._connectTimeout = null; this.options = { autoReconnect: options.autoReconnect ?? true, - compress: options.compress ?? false, + compress: options.compress === true ? (__compressionTrueDeprecationWarning++, "zlib-stream") : options.compress ?? false, connectionProperties: { browser: options.connectionProperties?.browser ?? "Oceanic", device: options.connectionProperties?.device ?? "Oceanic", @@ -77,6 +78,11 @@ export default class ShardManager extends Collection { shardIDs: options.shardIDs ?? [], ws: options.ws ?? {} }; + if (__compressionTrueDeprecationWarning === 1) { + process.emitWarning("Using `compress: true` is deprecated and will be removed in a future version. Please use `compress: \"zlib-stream\"` instead.", { + code: "OCEANIC_GATEWAY_COMPRESSION_TRUE_DEPRECATION" + }); + } this.options.override.appendQuery ??= (this.options.override.getBot === undefined && this.options.override.url === undefined); this.options.override.gatewayURLIsResumeURL ??= (this.options.override.getBot !== undefined || this.options.override.url !== undefined); this.options.override.timeBetweenShardConnects ??= 5000; @@ -214,7 +220,8 @@ export default class ShardManager extends Collection { if (url && this.options.override.appendQuery) { url += `?v=${GATEWAY_VERSION}&encoding=${Erlpack ? "etf" : "json"}`; if (this.options.compress) { - url += "&compress=zlib-stream"; + const type = this.options.compress === "zstd-stream" ? "zstd-stream" : "zlib-stream"; + url += `&compress=${type}`; } this._gatewayURL = url; } diff --git a/lib/gateway/compression/base.ts b/lib/gateway/compression/base.ts new file mode 100644 index 00000000..a20cc940 --- /dev/null +++ b/lib/gateway/compression/base.ts @@ -0,0 +1,14 @@ +import type Shard from "../Shard"; + +export default abstract class Compression { + shard!: Shard; + abstract decompress(data: Buffer): Promise; + constructor(shard: Shard) { + Object.defineProperty(this, "shard", { + value: shard, + configurable: false, + enumerable: false, + writable: false + }); + } +} diff --git a/lib/gateway/compression/pako.ts b/lib/gateway/compression/pako.ts new file mode 100644 index 00000000..f1f03dd8 --- /dev/null +++ b/lib/gateway/compression/pako.ts @@ -0,0 +1,50 @@ +import Compression from "./base"; +import type Shard from "../Shard"; +import GatewayError from "../../util/Errors"; +import { Inflate, constants } from "pako"; + +interface PakoExtra { + chunks: Array; + strm: { + next_out: number; + output: Buffer; + }; +} + +export default class PakoCompression extends Compression { + _sharedZLib: Inflate & PakoExtra; + constructor(shard: Shard) { + super(shard); + this._sharedZLib = new Inflate({ chunkSize: 128 * 1024 }) as Inflate & PakoExtra; + } + + async decompress(data: Buffer): Promise { + if (data.length >= 4 && data.readUInt32BE(data.length - 4) === 0xFFFF) { + // store the current pointer for slicing buffers after pushing. + const currentPointer: number | undefined = this._sharedZLib.strm?.next_out; + this._sharedZLib.push(data, constants.Z_SYNC_FLUSH); + if (this._sharedZLib.err) { + this.shard.client.emit("error", new GatewayError(`zlib error ${this._sharedZLib.err}: ${this._sharedZLib.msg ?? ""}`, 0)); + return null; + } + + if (this._sharedZLib.chunks.length === 0) { + // The current buffer hasn't been flushed + data = Buffer.from(this._sharedZLib.strm!.output.slice(currentPointer)); + } else { + // Buffers have been flushed one or more times + data = Buffer.concat([ + this._sharedZLib.chunks[0].slice(currentPointer), + ...this._sharedZLib.chunks.slice(1), + this._sharedZLib.strm.output + ]); + this._sharedZLib.chunks = []; + } + + return data; + } else { + this._sharedZLib.push(data, false); + return null; + } + } +} diff --git a/lib/gateway/compression/zlib-sync.ts b/lib/gateway/compression/zlib-sync.ts new file mode 100644 index 00000000..008b7f66 --- /dev/null +++ b/lib/gateway/compression/zlib-sync.ts @@ -0,0 +1,30 @@ +import Compression from "./base"; +import type Shard from "../Shard"; +import GatewayError from "../../util/Errors"; +import ZlibSync from "zlib-sync"; + +export default class ZlibSyncCompression extends Compression { + _sharedZLib: ZlibSync.Inflate; + constructor(shard: Shard) { + super(shard); + this._sharedZLib = new ZlibSync.Inflate({ chunkSize: 128 * 1024 }); + } + + async decompress(data: Buffer): Promise { + if (data.length >= 4 && data.readUInt32BE(data.length - 4) === 0xFFFF) { + // store the current pointer for slicing buffers after pushing. + this._sharedZLib.push(data, ZlibSync.Z_SYNC_FLUSH); + if (this._sharedZLib.err) { + this.shard.client.emit("error", new GatewayError(`zlib error ${this._sharedZLib.err}: ${this._sharedZLib.msg ?? ""}`, 0)); + return null; + } + + data = Buffer.from(this._sharedZLib.result ?? ""); + + return data; + } else { + this._sharedZLib.push(data, false); + return null; + } + } +} diff --git a/lib/gateway/compression/zstd.ts b/lib/gateway/compression/zstd.ts new file mode 100644 index 00000000..5e20360a --- /dev/null +++ b/lib/gateway/compression/zstd.ts @@ -0,0 +1,27 @@ +import Compression from "./base"; +import type Shard from "../Shard"; +import fzstd from "fzstd"; + +export default class ZstdCompression extends Compression { + _resolvePromise?: (data: Uint8Array) => void; + _resultPromise?: Promise; + stream: fzstd.Decompress; + constructor(shard: Shard) { + super(shard); + this.stream = new fzstd.Decompress(data => { + this._resolvePromise!(data); + }); + } + + async decompress(data: Buffer): Promise { + if (this._resultPromise) { + await this._resultPromise; + } + this._resultPromise = new Promise(resolve => { + this._resolvePromise = resolve; + }); + this.stream.push(data); + const result = await this._resultPromise; + return Buffer.from(result); + } +} diff --git a/lib/types/gateway.d.ts b/lib/types/gateway.d.ts index 84b4a34a..32226c80 100644 --- a/lib/types/gateway.d.ts +++ b/lib/types/gateway.d.ts @@ -26,9 +26,10 @@ interface GatewayOptions { autoReconnect?: boolean; /** * If packets to and from Discord should be compressed. + * @note `true` is the same as `zlib-stream`. This behavior is deprecated. * @defaultValue false */ - compress?: boolean; + compress?: boolean | "zlib-stream" | "zstd-stream"; /** * The concurrency for shard connections. If you don't know what this is, don't mess with it. Only bots in >150,000 servers can use any non-default value. * @defaultValue 1 @@ -131,6 +132,7 @@ interface GatewayOptions { */ seedVoiceConnections?: boolean; /** + * An array of shard IDs to run for this client. Mutually exclusive with `firstShardID` & `lastShardID`. * An array of shard IDs to run for this client. Mutually exclusive with `firstShardID` & `lastShardID`. * @defaultValue based on `firstShardID` & `lastShardID` */ @@ -163,7 +165,8 @@ export interface OverrideOptions { url?(shard: Shard, totalShards: number): Promise; } -export interface ShardManagerInstanceOptions extends Required> { +export interface ShardManagerInstanceOptions extends Required> { + compress: false | "zlib-stream" | "zstd-stream"; concurrency: number; connectionProperties: Required; dispatcher: DispatcherInstanceOptions; diff --git a/lib/util/Util.ts b/lib/util/Util.ts index 3765fcca..90618562 100644 --- a/lib/util/Util.ts +++ b/lib/util/Util.ts @@ -118,6 +118,17 @@ export default class Util { return (id === undefined ? undefined : opt[id]) ?? opt.default ?? Infinity; } + /** @hidden intended for internal use only */ + _isModuleInstalled(name: string): boolean { + try { + // eslint-disable-next-line unicorn/prefer-module + require(name); + return true; + } catch { + return false; + } + } + _setLimit(values?: Record | number, defaultValue = Infinity): Record | number { if (values === undefined) { return defaultValue; diff --git a/package.json b/package.json index bb145642..82c34e7b 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "@types/ws": "^8.5.10", "@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/parser": "^6.21.0", + "erlpack": "^0.1.4", "eslint": "^8.57.0", "eslint-plugin-import": "^2.29.1", "eslint-plugin-import-newlines": "^1.4.0", @@ -57,13 +58,16 @@ "eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-unicorn": "^53.0.0", "eslint-plugin-unused-imports": "^3.2.0", + "fzstd": "^0.1.1", + "pako": "^2.1.0", "rimraf": "^5.0.5", "typedoc": "0.25.13", "typedoc-plugin-extras": "3.0.0", "typedoc-plugin-mdn-links": "^3.1.19", "typedoc-plugin-merge-modules": "^5.1.0", "typescript": "^5.3.3", - "undici-types": "~6.9.0" + "undici-types": "~6.9.0", + "zlib-sync": "^0.1.9" }, "dependencies": { "tslib": "^2.6.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 239c34d7..729e60cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,9 @@ importers: '@typescript-eslint/parser': specifier: ^6.21.0 version: 6.21.0(eslint@8.57.0)(typescript@5.3.3) + erlpack: + specifier: ^0.1.4 + version: 0.1.4 eslint: specifier: ^8.57.0 version: 8.57.0 @@ -69,6 +72,12 @@ importers: eslint-plugin-unused-imports: specifier: ^3.2.0 version: 3.2.0(@typescript-eslint/eslint-plugin@7.0.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0)(typescript@5.3.3))(eslint@8.57.0) + fzstd: + specifier: ^0.1.1 + version: 0.1.1 + pako: + specifier: ^2.1.0 + version: 2.1.0 rimraf: specifier: ^5.0.5 version: 5.0.5 @@ -90,6 +99,9 @@ importers: undici-types: specifier: ~6.9.0 version: 6.9.0 + zlib-sync: + specifier: ^0.1.9 + version: 0.1.9 packages: @@ -399,6 +411,9 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -554,6 +569,9 @@ packages: encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + erlpack@0.1.4: + resolution: {integrity: sha512-CJYbkEvsB5FqCCu2tLxF1eYKi28PvemC12oqzJ9oO6mDFrFO9G9G7nNJUHhiAyyL9zfXTOJx/tOcrQk+ncD65w==} + err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} @@ -724,6 +742,9 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -771,6 +792,9 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + fzstd@0.1.1: + resolution: {integrity: sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA==} + get-intrinsic@1.2.2: resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} @@ -1154,6 +1178,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + nan@2.20.0: + resolution: {integrity: sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==} + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -1237,6 +1264,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -1689,6 +1719,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zlib-sync@0.1.9: + resolution: {integrity: sha512-DinB43xCjVwIBDpaIvQqHbmDsnYnSt6HJ/yiB2MZQGTqgPcwBSZqLkimXwK8BvdjQ/MaZysb5uEenImncqvCqQ==} + snapshots: '@aashutoshrathi/word-wrap@1.2.6': {} @@ -2077,6 +2110,10 @@ snapshots: balanced-match@1.0.2: {} + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -2235,6 +2272,11 @@ snapshots: iconv-lite: 0.6.3 optional: true + erlpack@0.1.4: + dependencies: + bindings: 1.5.0 + nan: 2.20.0 + err-code@2.0.3: {} error-ex@1.3.2: @@ -2506,6 +2548,8 @@ snapshots: dependencies: flat-cache: 3.2.0 + file-uri-to-path@1.0.0: {} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 @@ -2558,6 +2602,8 @@ snapshots: functions-have-names@1.2.3: {} + fzstd@0.1.1: {} + get-intrinsic@1.2.2: dependencies: function-bind: 1.1.2 @@ -2936,6 +2982,8 @@ snapshots: ms@2.1.3: {} + nan@2.20.0: {} + natural-compare@1.4.0: {} negotiator@0.6.3: {} @@ -3039,6 +3087,8 @@ snapshots: p-try@2.2.0: {} + pako@2.1.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -3485,3 +3535,7 @@ snapshots: yallist@4.0.0: {} yocto-queue@0.1.0: {} + + zlib-sync@0.1.9: + dependencies: + nan: 2.20.0