diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index dcfdce8..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "root": true, - "extends": ["@clytage/eslint-config/typescript", "prettier"], - "plugins": ["prettier"], - "parserOptions": { - "project": "./tsconfig.json" - }, - "rules": { - "@typescript-eslint/naming-convention": [ - "error", - { - "selector": "default", - "format": ["camelCase", "PascalCase", "snake_case", "UPPER_CASE"], - "leadingUnderscore": "allow", - "trailingUnderscore": "forbid" - }, - { - "selector": "variable", - "modifiers": ["destructured"], - "format": null - } - ], - "prettier/prettier": [ - "error", - { - "useTabs": true, - "endOfLine": "lf", - "trailingComma": "none", - "arrowParens": "avoid", - "printWidth": 120, - "quoteProps": "as-needed" - } - ] - }, - "ignorePatterns": ["dist"] -} diff --git a/.github/renovate.json b/.github/renovate.json index ff961bf..11a9ece 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,4 +1,4 @@ { - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["github>stegripe/renovate-config"] + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["github>stegripe/renovate-config"] } diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cb6b6f8..1c25787 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,5 +10,5 @@ on: jobs: test: - uses: stegripe/workflows/.github/workflows/pnpm-lint-and-test.yml@main + uses: stegripe/workflows/.github/workflows/pnpm-lint-and-test.yaml@main secrets: inherit diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 7c933f1..0000000 --- a/.prettierignore +++ /dev/null @@ -1,13 +0,0 @@ -# Packages -node_modules/ - -# Auto Generated -pnpm-lock.yaml -dist -CHANGELOG.md - -# Cache -.cache/ -.eslintcache -.prettiercache -.tsbuildinfo diff --git a/.prettierrc.json b/.prettierrc.json deleted file mode 100644 index 307966e..0000000 --- a/.prettierrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/prettierrc.json", - "useTabs": true, - "endOfLine": "lf", - "trailingComma": "none", - "arrowParens": "avoid", - "printWidth": 120, - "quoteProps": "as-needed" -} diff --git a/.vscode/settings.json b/.vscode/settings.json index fd03f55..8bce75b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,8 @@ { - "files.eol": "\n", - "typescript.tsdk": "node_modules/typescript/lib", - "editor.formatOnSave": true, - "editor.defaultFormatter": "esbenp.prettier-vscode" + "files.eol": "\n", + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": false, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "always" + } } diff --git a/README.md b/README.md index c5f7dae..9cb40ad 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# Icelink +# Esbatu -> Icelink is an innovative project that surpasses Lavalink, offering a superior audio streaming experience. Built as a refined alternative, Icelink boasts enhanced stability, frequent updates, and a robust foundation that supports extendable structures. It introduces new handling mechanisms, ensures compatibility with ESM (ECMAScript Modules) and CommonJS, and integrates Redis caching for optimized performance. Icelink represents a cutting-edge solution for streaming music, elevating the user experience with its advanced features and forward-looking approach. +> Esbatu surpasses Lavalink with enhanced stability, frequent updates, and support for ESM and CommonJS, offering a superior audio streaming experience. It features new handling mechanisms and uses Redis to manage current song/session resources, preventing replay issues.
- NPM version - NPM downloads - Tests status + NPM version + NPM downloads + Tests status
## Installation @@ -13,20 +13,20 @@ **Node.js 18 or newer is required.** ```sh -npm install icelink -yarn add icelink -pnpm add icelink -bun add icelink +npm install esbatu +yarn add esbatu +pnpm add esbatu +bun add esbatu ``` ## Example usage -Create class extends Icelink for depending on your library implementation (like discord.js): +Create class extends Esbatu for depending on your library implementation (like discord.js): ```js -import { Icelink } from "icelink"; +import { Esbatu } from "esbatu"; -export class extends Icelink { +export class extends Esbatu { constructor(client, options) { super(options); @@ -43,7 +43,7 @@ Afterwards we can create a quite simple example: ```js import { Client } from "discord.js"; -import { Icelink } from "./Icelink.js"; +import { Esbatu } from "./Esbatu.js"; const client = new Client({ intents: [ @@ -54,7 +54,7 @@ const client = new Client({ ] }); -client.icelink = new Icelink(client, { +client.esbatu = new Esbatu(client, { nodes: [ { name: "default", @@ -64,15 +64,15 @@ client.icelink = new Icelink(client, { ] }); -client.icelink.on("error", (_, error) => console.error(error)); -client.on("raw", packet => client.icelink.updateInstance(packet)); +client.esbatu.on("error", (_, error) => console.error(error)); +client.on("raw", packet => client.esbatu.updateInstance(packet)); client.on("ready" async () => { - client.icelink.id = client.user.id; + client.esbatu.id = client.user.id; - for (const node of client.icelink.options.nodes) - client.icelink.addNode(node).catch(error => client.icelink.emit("error", node.name, error)); + for (const node of client.esbatu.options.nodes) + client.esbatu.addNode(node).catch(error => client.esbatu.emit("error", node.name, error)); - const node = client.icelink.idealNode; + const node = client.esbatu.idealNode; const player = await node.joinVoiceChannel({ guildId: "836189103103811192", channelId: "721217201021217261", @@ -84,7 +84,7 @@ client.on("ready" async () => { await player.playTrack({ track: resultTrack.data.encoded }); setTimeout(async () => { - await client.icelink.leaveVoiceChannel(player.guildId); + await client.esbatu.leaveVoiceChannel(player.guildId); }, 60_000); }); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..a4ab0aa --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,27 @@ +import { common, modules, node, stylistic, typescript, extend } from "@stegripe/eslint-config"; + +export default [ + ...common, + ...modules, + ...node, + ...stylistic, + ...extend(typescript, [ + { + rule: "typescript/naming-convention", + option: [ + "error", + { + selector: "default", + format: ["camelCase", "PascalCase", "snake_case", "UPPER_CASE"], + leadingUnderscore: "allow", + trailingUnderscore: "forbid" + }, + { + selector: "variable", + modifiers: ["destructured"], + format: null + } + ] + } + ]) +]; diff --git a/package.json b/package.json index 9ba9f6d..6981e04 100644 --- a/package.json +++ b/package.json @@ -1,68 +1,65 @@ { - "name": "icelink", - "version": "1.0.0-dev", - "description": "Icelink outshines Lavalink with its superior stability, frequent updates, and extended capabilities. Featuring new handling mechanisms, support for ESM and CommonJS, and efficient Redis caching, Icelink offers an enhanced and reliable music streaming experience.", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "scripts": { - "build": "tsc --noEmit && tsup --config tsup-config.json", - "build:docs": "typedoc --theme default --readme README.md --out docs/ --entryPointStrategy expand src/.", - "format": "prettier --write . && cross-env TIMING=1 eslint --fix --format=pretty src", - "lint": "prettier --check . && cross-env TIMING=1 eslint --format=pretty src", - "prepack": "pnpm lint && pnpm build" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/stegripe/icelink.git" - }, - "author": "Fab1o0107 ", - "license": "AGPL-3.0", - "bugs": { - "url": "https://github.com/stegripe/icelink/issues" - }, - "homepage": "https://github.com/stegripe/icelink#readme", - "engines": { - "node": ">=18.x" - }, - "devDependencies": { - "@clytage/eslint-config": "^3.0.1", - "@types/node": "^20.14.10", - "@types/ws": "^8.5.10", - "@typescript-eslint/eslint-plugin": "^7.16.1", - "@typescript-eslint/parser": "^7.16.1", - "cross-env": "^7.0.3", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-formatter-pretty": "^5.0.0", - "eslint-plugin-prettier": "^5.2.1", - "prettier": "^3.3.2", - "tsup": "^8.1.0", - "typedoc": "^0.26.3", - "typescript": "^5.5.3" - }, - "dependencies": { - "undici": "^6.19.2", - "ws": "^8.18.0" - }, - "peerDependencies": { - "ioredis": ">=5.4.1" - }, - "peerDependenciesMeta": { - "ioredis": { - "optional": true - } - }, - "exports": { - ".": { - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - } - } - } + "name": "esbatu", + "version": "1.0.0-dev", + "description": "Esbatu surpasses Lavalink with superior stability, frequent updates, extended capabilities, and efficient Redis caching, offering a reliable music streaming experience.", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "scripts": { + "build": "tsc --noEmit && tsup --config tsup-config.json", + "build:docs": "typedoc --theme default --readme README.md --out docs/ --entryPointStrategy expand src/.", + "format": "cross-env TIMING=1 eslint --fix src", + "lint": "cross-env TIMING=1 eslint src", + "prepack": "pnpm lint && pnpm build" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/stegripe/icelink.git" + }, + "author": "Fab1o0107 ", + "license": "AGPL-3.0", + "bugs": { + "url": "https://github.com/stegripe/icelink/issues" + }, + "homepage": "https://github.com/stegripe/icelink#readme", + "engines": { + "node": ">=18.x" + }, + "devDependencies": { + "@stegripe/eslint-config": "^1.0.0", + "@types/node": "^20.14.11", + "@types/ws": "^8.5.11", + "cross-env": "^7.0.3", + "eslint": "^9.7.0", + "tsup": "^8.1.2", + "typedoc": "^0.26.4", + "typescript": "^5.5.3" + }, + "dependencies": { + "undici": "^6.19.2", + "ws": "^8.18.0" + }, + "peerDependencies": { + "ioredis": ">=5.4.1" + }, + "peerDependenciesMeta": { + "ioredis": { + "optional": true + } + }, + "exports": { + ".": { + "require": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/index.mjs" + } + } + }, + "files": [ + "dist" + ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4ad9cf1..4f60fe2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,45 +18,27 @@ importers: specifier: ^8.18.0 version: 8.18.0 devDependencies: - '@clytage/eslint-config': - specifier: ^3.0.1 - version: 3.0.1(@eslint/js@8.57.0)(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) + '@stegripe/eslint-config': + specifier: ^1.0.0 + version: 1.0.0(@stylistic/eslint-plugin@2.3.0(eslint@9.7.0)(typescript@5.5.3))(eslint-config-prettier@9.1.0(eslint@9.7.0))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0))(eslint-plugin-import-x@3.0.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-jsdoc@48.7.0(eslint@9.7.0))(eslint-plugin-n@17.9.0(eslint@9.7.0))(eslint-plugin-promise@6.4.0(eslint@9.7.0))(eslint-plugin-tsdoc@0.3.0)(eslint-plugin-unicorn@54.0.0(eslint@9.7.0))(eslint@9.7.0)(globals@15.8.0)(typescript-eslint@7.16.1(eslint@9.7.0)(typescript@5.5.3))(typescript@5.5.3) '@types/node': - specifier: ^20.14.10 - version: 20.14.10 + specifier: ^20.14.11 + version: 20.14.11 '@types/ws': - specifier: ^8.5.10 - version: 8.5.10 - '@typescript-eslint/eslint-plugin': - specifier: ^7.16.1 - version: 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) - '@typescript-eslint/parser': - specifier: ^7.16.1 - version: 7.16.1(eslint@8.57.0)(typescript@5.5.3) + specifier: ^8.5.11 + version: 8.5.11 cross-env: specifier: ^7.0.3 version: 7.0.3 eslint: - specifier: ^8.57.0 - version: 8.57.0 - eslint-config-prettier: - specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.0) - eslint-formatter-pretty: - specifier: ^5.0.0 - version: 5.0.0 - eslint-plugin-prettier: - specifier: ^5.2.1 - version: 5.2.1(@types/eslint@8.56.0)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.2) - prettier: - specifier: ^3.3.2 - version: 3.3.2 + specifier: ^9.7.0 + version: 9.7.0 tsup: - specifier: ^8.1.0 - version: 8.1.0(typescript@5.5.3) + specifier: ^8.1.2 + version: 8.1.2(typescript@5.5.3)(yaml@2.4.5) typedoc: - specifier: ^0.26.3 - version: 0.26.3(typescript@5.5.3) + specifier: ^0.26.4 + version: 0.26.4(typescript@5.5.3) typescript: specifier: ^5.5.3 version: 5.5.3 @@ -67,157 +49,163 @@ packages: resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} engines: {node: '>=0.10.0'} - '@clytage/eslint-config@3.0.1': - resolution: {integrity: sha512-vSxaKElSjPs7jLu7qTP4K14P73UNKU3TPme2jZpr8iJ/UE20WNq2Xdv9sruCWNRc1sKd6xWEiABUtTG9nD/Tbw==} - peerDependencies: - '@eslint/js': ^8.44.0 - '@typescript-eslint/eslint-plugin': '>=6.0.0' - '@typescript-eslint/parser': '>=6.0.0' - eslint: '>=8.44.0' - typescript: '>=3.3.1 <6.0.0' - peerDependenciesMeta: - '@typescript-eslint/eslint-plugin': - optional: true - '@typescript-eslint/parser': - optional: true - typescript: - optional: true + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} - '@esbuild/aix-ppc64@0.21.4': - resolution: {integrity: sha512-Zrm+B33R4LWPLjDEVnEqt2+SLTATlru1q/xYKVn8oVTbiRBGmK2VIMoIYGJDGyftnGaC788IuzGFAlb7IQ0Y8A==} - engines: {node: '>=12'} + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + + '@es-joy/jsdoccomment@0.46.0': + resolution: {integrity: sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==} + engines: {node: '>=16'} + + '@esbuild/aix-ppc64@0.23.0': + resolution: {integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.21.4': - resolution: {integrity: sha512-fYFnz+ObClJ3dNiITySBUx+oNalYUT18/AryMxfovLkYWbutXsct3Wz2ZWAcGGppp+RVVX5FiXeLYGi97umisA==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.23.0': + resolution: {integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.21.4': - resolution: {integrity: sha512-E7H/yTd8kGQfY4z9t3nRPk/hrhaCajfA3YSQSBrst8B+3uTcgsi8N+ZWYCaeIDsiVs6m65JPCaQN/DxBRclF3A==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.23.0': + resolution: {integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==} + engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.21.4': - resolution: {integrity: sha512-mDqmlge3hFbEPbCWxp4fM6hqq7aZfLEHZAKGP9viq9wMUBVQx202aDIfc3l+d2cKhUJM741VrCXEzRFhPDKH3Q==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.23.0': + resolution: {integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==} + engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.21.4': - resolution: {integrity: sha512-72eaIrDZDSiWqpmCzVaBD58c8ea8cw/U0fq/PPOTqE3c53D0xVMRt2ooIABZ6/wj99Y+h4ksT/+I+srCDLU9TA==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.23.0': + resolution: {integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.21.4': - resolution: {integrity: sha512-uBsuwRMehGmw1JC7Vecu/upOjTsMhgahmDkWhGLWxIgUn2x/Y4tIwUZngsmVb6XyPSTXJYS4YiASKPcm9Zitag==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.23.0': + resolution: {integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.21.4': - resolution: {integrity: sha512-8JfuSC6YMSAEIZIWNL3GtdUT5NhUA/CMUCpZdDRolUXNAXEE/Vbpe6qlGLpfThtY5NwXq8Hi4nJy4YfPh+TwAg==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.23.0': + resolution: {integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.21.4': - resolution: {integrity: sha512-8d9y9eQhxv4ef7JmXny7591P/PYsDFc4+STaxC1GBv0tMyCdyWfXu2jBuqRsyhY8uL2HU8uPyscgE2KxCY9imQ==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.23.0': + resolution: {integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.21.4': - resolution: {integrity: sha512-/GLD2orjNU50v9PcxNpYZi+y8dJ7e7/LhQukN3S4jNDXCKkyyiyAz9zDw3siZ7Eh1tRcnCHAo/WcqKMzmi4eMQ==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.23.0': + resolution: {integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.21.4': - resolution: {integrity: sha512-2rqFFefpYmpMs+FWjkzSgXg5vViocqpq5a1PSRgT0AvSgxoXmGF17qfGAzKedg6wAwyM7UltrKVo9kxaJLMF/g==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.23.0': + resolution: {integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.21.4': - resolution: {integrity: sha512-pNftBl7m/tFG3t2m/tSjuYeWIffzwAZT9m08+9DPLizxVOsUl8DdFzn9HvJrTQwe3wvJnwTdl92AonY36w/25g==} - engines: {node: '>=12'} + '@esbuild/linux-ia32@0.23.0': + resolution: {integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.21.4': - resolution: {integrity: sha512-cSD2gzCK5LuVX+hszzXQzlWya6c7hilO71L9h4KHwqI4qeqZ57bAtkgcC2YioXjsbfAv4lPn3qe3b00Zt+jIfQ==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.23.0': + resolution: {integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.21.4': - resolution: {integrity: sha512-qtzAd3BJh7UdbiXCrg6npWLYU0YpufsV9XlufKhMhYMJGJCdfX/G6+PNd0+v877X1JG5VmjBLUiFB0o8EUSicA==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.23.0': + resolution: {integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.21.4': - resolution: {integrity: sha512-yB8AYzOTaL0D5+2a4xEy7OVvbcypvDR05MsB/VVPVA7nL4hc5w5Dyd/ddnayStDgJE59fAgNEOdLhBxjfx5+dg==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.23.0': + resolution: {integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.21.4': - resolution: {integrity: sha512-Y5AgOuVzPjQdgU59ramLoqSSiXddu7F3F+LI5hYy/d1UHN7K5oLzYBDZe23QmQJ9PIVUXwOdKJ/jZahPdxzm9w==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.23.0': + resolution: {integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.21.4': - resolution: {integrity: sha512-Iqc/l/FFwtt8FoTK9riYv9zQNms7B8u+vAI/rxKuN10HgQIXaPzKZc479lZ0x6+vKVQbu55GdpYpeNWzjOhgbA==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.23.0': + resolution: {integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.21.4': - resolution: {integrity: sha512-Td9jv782UMAFsuLZINfUpoF5mZIbAj+jv1YVtE58rFtfvoKRiKSkRGQfHTgKamLVT/fO7203bHa3wU122V/Bdg==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.23.0': + resolution: {integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-x64@0.21.4': - resolution: {integrity: sha512-Awn38oSXxsPMQxaV0Ipb7W/gxZtk5Tx3+W+rAPdZkyEhQ6968r9NvtkjhnhbEgWXYbgV+JEONJ6PcdBS+nlcpA==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.23.0': + resolution: {integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==} + engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-x64@0.21.4': - resolution: {integrity: sha512-IsUmQeCY0aU374R82fxIPu6vkOybWIMc3hVGZ3ChRwL9hA1TwY+tS0lgFWV5+F1+1ssuvvXt3HFqe8roCip8Hg==} - engines: {node: '>=12'} + '@esbuild/openbsd-arm64@0.23.0': + resolution: {integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.0': + resolution: {integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==} + engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.21.4': - resolution: {integrity: sha512-hsKhgZ4teLUaDA6FG/QIu2q0rI6I36tZVfM4DBZv3BG0mkMIdEnMbhc4xwLvLJSS22uWmaVkFkqWgIS0gPIm+A==} - engines: {node: '>=12'} + '@esbuild/sunos-x64@0.23.0': + resolution: {integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==} + engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.21.4': - resolution: {integrity: sha512-UUfMgMoXPoA/bvGUNfUBFLCh0gt9dxZYIx9W4rfJr7+hKe5jxxHmfOK8YSH4qsHLLN4Ck8JZ+v7Q5fIm1huErg==} - engines: {node: '>=12'} + '@esbuild/win32-arm64@0.23.0': + resolution: {integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==} + engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.21.4': - resolution: {integrity: sha512-yIxbspZb5kGCAHWm8dexALQ9en1IYDfErzjSEq1KzXFniHv019VT3mNtTK7t8qdy4TwT6QYHI9sEZabONHg+aw==} - engines: {node: '>=12'} + '@esbuild/win32-ia32@0.23.0': + resolution: {integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==} + engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.21.4': - resolution: {integrity: sha512-sywLRD3UK/qRJt0oBwdpYLBibk7KiRfbswmWRDabuncQYSlf8aLEEUor/oP6KRz8KEG+HoiVLBhPRD5JWjS8Sg==} - engines: {node: '>=12'} + '@esbuild/win32-x64@0.23.0': + resolution: {integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==} + engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -227,30 +215,33 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.10.0': - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} + '@eslint-community/regexpp@4.11.0': + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/config-array@0.17.0': + resolution: {integrity: sha512-A68TBu6/1mHHuc5YJL0U0VVeGNiklLAL6rRmhTCP2B5XjWLMnrX+HkO+IAXyHvks5cyyY1jjK5ITPQ1HGS2EVA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@8.57.0': - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@3.1.0': + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@humanwhocodes/config-array@0.11.14': - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@eslint/js@9.7.0': + resolution: {integrity: sha512-ChuWDQenef8OSFnvuxv0TCVxEwmu3+hPNKvM9B34qpM0rDRbjL8t5QkQeHHeAfsKQjuH9wS82WeCi1J/owatng==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.4': + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/object-schema@2.0.2': - resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} - deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.3.0': + resolution: {integrity: sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==} + engines: {node: '>=18.18'} '@ioredis/commands@1.2.0': resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==} @@ -277,6 +268,12 @@ packages: '@jridgewell/trace-mapping@0.3.20': resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} + '@microsoft/tsdoc-config@0.17.0': + resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} + + '@microsoft/tsdoc@0.15.0': + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -297,76 +294,140 @@ packages: resolution: {integrity: sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@rollup/rollup-android-arm-eabi@4.9.1': - resolution: {integrity: sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==} + '@rollup/rollup-android-arm-eabi@4.18.1': + resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.9.1': - resolution: {integrity: sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==} + '@rollup/rollup-android-arm64@4.18.1': + resolution: {integrity: sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.9.1': - resolution: {integrity: sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==} + '@rollup/rollup-darwin-arm64@4.18.1': + resolution: {integrity: sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.9.1': - resolution: {integrity: sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==} + '@rollup/rollup-darwin-x64@4.18.1': + resolution: {integrity: sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==} cpu: [x64] os: [darwin] - '@rollup/rollup-linux-arm-gnueabihf@4.9.1': - resolution: {integrity: sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==} + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': + resolution: {integrity: sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.18.1': + resolution: {integrity: sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.9.1': - resolution: {integrity: sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==} + '@rollup/rollup-linux-arm64-gnu@4.18.1': + resolution: {integrity: sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.9.1': - resolution: {integrity: sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==} + '@rollup/rollup-linux-arm64-musl@4.18.1': + resolution: {integrity: sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.9.1': - resolution: {integrity: sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==} + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': + resolution: {integrity: sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.18.1': + resolution: {integrity: sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.9.1': - resolution: {integrity: sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==} + '@rollup/rollup-linux-s390x-gnu@4.18.1': + resolution: {integrity: sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.18.1': + resolution: {integrity: sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.9.1': - resolution: {integrity: sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==} + '@rollup/rollup-linux-x64-musl@4.18.1': + resolution: {integrity: sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==} cpu: [x64] os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.9.1': - resolution: {integrity: sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==} + '@rollup/rollup-win32-arm64-msvc@4.18.1': + resolution: {integrity: sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.9.1': - resolution: {integrity: sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==} + '@rollup/rollup-win32-ia32-msvc@4.18.1': + resolution: {integrity: sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.9.1': - resolution: {integrity: sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==} + '@rollup/rollup-win32-x64-msvc@4.18.1': + resolution: {integrity: sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==} cpu: [x64] os: [win32] + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@shikijs/core@1.10.1': resolution: {integrity: sha512-qdiJS5a/QGCff7VUFIqd0hDdWly9rDp8lhVmXVrS11aazX8LOTRLHAXkkEeONNsS43EcCd7gax9LLoOz4vlFQA==} - '@types/eslint@8.56.0': - resolution: {integrity: sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==} + '@stegripe/eslint-config@1.0.0': + resolution: {integrity: sha512-W3ZE6VSaS9f03iNYqHK8TmYs7x0ll/jvzbAIRnyMMkzhDjGTJa5NbzCEGZZdC79iM3ksVlOWDuD6SUrmlYb0Ww==} + peerDependencies: + '@stylistic/eslint-plugin': ^2.3.0 + eslint: '>=9.6.0' + eslint-config-prettier: ^9.1.0 + eslint-import-resolver-typescript: ^3.6.1 + eslint-plugin-import-x: ^3.0.1 + eslint-plugin-jsdoc: ^48.7.0 + eslint-plugin-n: ^17.9.0 + eslint-plugin-promise: ^6.4.0 + eslint-plugin-tsdoc: ^0.3.0 + eslint-plugin-unicorn: ^54.0.0 + globals: ^15.8.0 + typescript: '>=4.7.4' + typescript-eslint: ^7.16.0 + + '@stylistic/eslint-plugin-js@2.3.0': + resolution: {integrity: sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.40.0' + + '@stylistic/eslint-plugin-jsx@2.3.0': + resolution: {integrity: sha512-tsQ0IEKB195H6X9A4iUSgLLLKBc8gUBWkBIU8tp1/3g2l8stu+PtMQVV/VmK1+3bem5FJCyvfcZIQ/WF1fsizA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.40.0' + + '@stylistic/eslint-plugin-plus@2.3.0': + resolution: {integrity: sha512-xboPWGUU5yaPlR+WR57GwXEuY4PSlPqA0C3IdNA/+1o2MuBi95XgDJcZiJ9N+aXsqBXAPIpFFb+WQ7QEHo4f7g==} + peerDependencies: + eslint: '*' + + '@stylistic/eslint-plugin-ts@2.3.0': + resolution: {integrity: sha512-wqOR38/uz/0XPnHX68ftp8sNMSAqnYGjovOTN7w00xnjS6Lxr3Sk7q6AaxWWqbMvOj7V2fQiMC5HWAbTruJsCg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.40.0' + + '@stylistic/eslint-plugin@2.3.0': + resolution: {integrity: sha512-rtiz6u5gRyyEZp36FcF1/gHJbsbT3qAgXZ1qkad6Nr/xJ9wrSJkiSFFQhpYVTIZ7FJNRJurEcumZDCwN9dEI4g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.40.0' + + '@types/eslint@8.56.10': + resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} '@types/estree@1.0.5': resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} @@ -374,11 +435,17 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@20.14.10': - resolution: {integrity: sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==} + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/ws@8.5.10': - resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + '@types/node@20.14.11': + resolution: {integrity: sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + + '@types/ws@8.5.11': + resolution: {integrity: sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==} '@typescript-eslint/eslint-plugin@7.16.1': resolution: {integrity: sha512-SxdPak/5bO0EnGktV05+Hq8oatjAYVY3Zh2bye9pGZy6+jwyR3LG3YKkV4YatlsgqXP28BTeVm9pqwJM96vf2A==} @@ -438,25 +505,21 @@ packages: resolution: {integrity: sha512-Qlzzx4sE4u3FsHTPQAAQFJFNOuqtuY0LFrZHwQ8IHK705XxBiWOFkfKRWu6niB7hwfgnwIpO4jTC75ozW1PHWg==} engines: {node: ^18.18.0 || >=20.0.0} - '@ungap/structured-clone@1.2.0': - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn@8.11.2: - resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -466,6 +529,10 @@ packages: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -481,13 +548,45 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -505,36 +604,70 @@ packages: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} - bundle-require@4.0.2: - resolution: {integrity: sha512-jwzPOChofl67PSTW2SGubV9HBQAhhR2i6nskiOThauo9dzwDUgOWQScFVaJkjEfYX+UXiD+LEx8EblQMc2wIag==} + browserslist@4.23.2: + resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + builtin-modules@3.3.0: + resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} + engines: {node: '>=6'} + + bundle-require@5.0.0: + resolution: {integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: - esbuild: '>=0.17' + esbuild: '>=0.18' cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + caniuse-lite@1.0.30001642: + resolution: {integrity: sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + ci-info@4.0.0: + resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} + engines: {node: '>=8'} + + clean-regexp@1.0.0: + resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} + engines: {node: '>=4'} + cluster-key-slot@1.1.2: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -542,9 +675,20 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} + comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + + core-js-compat@3.37.1: + resolution: {integrity: sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==} + cross-env@7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -554,6 +698,26 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -563,9 +727,26 @@ packages: supports-color: optional: true + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + denque@2.1.0: resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} engines: {node: '>=0.10'} @@ -574,6 +755,10 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -581,73 +766,194 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + electron-to-chromium@1.4.829: + resolution: {integrity: sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + enhanced-resolve@5.17.0: + resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==} + engines: {node: '>=10.13.0'} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - esbuild@0.21.4: - resolution: {integrity: sha512-sFMcNNrj+Q0ZDolrp5pDhH0nRPN9hLIM3fRPwgbLYJeSHHgnXSnbV3xYgSVuOeLWH9c73VwmEverVzupIv5xuA==} - engines: {node: '>=12'} + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.5.4: + resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} + + es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + esbuild@0.23.0: + resolution: {integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==} + engines: {node: '>=18'} hasBin: true + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-compat-utils@0.5.1: + resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==} + engines: {node: '>=12'} + peerDependencies: + eslint: '>=6.0.0' + eslint-config-prettier@9.1.0: resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' - eslint-formatter-pretty@5.0.0: - resolution: {integrity: sha512-Uick451FoL22/wXqyScX3inW8ZlD/GQO7eFXj3bqb6N/ZtuuF00/CwSNIKLbFCJPrX5V4EdQBSgJ/UVnmLRnug==} - engines: {node: '>=14.16'} + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - eslint-plugin-prettier@5.2.1: - resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} + eslint-import-resolver-typescript@3.6.1: + resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '*' - prettier: '>=3.0.0' + eslint: '*' + eslint-plugin-import: '*' + + eslint-module-utils@2.8.1: + resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' peerDependenciesMeta: - '@types/eslint': + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: optional: true - eslint-config-prettier: + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-es-x@7.8.0: + resolution: {integrity: sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '>=8' + + eslint-plugin-import-x@3.0.1: + resolution: {integrity: sha512-jzQgJuE4ssxwNi0aMBkOL8whd4eHb0Z/uFWsk8uEoYB7xwTkAptSKojLzRswxgf/1bhH6QgcLjgabUBQqluBIg==} + engines: {node: '>=16'} + peerDependencies: + eslint: ^8.56.0 || ^9.0.0-0 + + eslint-plugin-import@2.29.1: + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': optional: true - eslint-rule-docs@1.1.235: - resolution: {integrity: sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==} + eslint-plugin-jsdoc@48.7.0: + resolution: {integrity: sha512-5oiVf7Y+ZxGYQTlLq81X72n+S+hjvS/u0upAdbpPEeaIZILK3MKN8lm/6QqKioBjm/qZ0B5XpMQUtc2fUkqXAg==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-n@17.9.0: + resolution: {integrity: sha512-CPSaXDXdrT4nsrOrO4mT4VB6FMUkoySRkHWuuJJHVqsIEjIeZgMY1H7AzSwPbDScikBmLN82KeM1u7ixV7PzGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: '>=8.23.0' - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + eslint-plugin-promise@6.4.0: + resolution: {integrity: sha512-/KWWRaD3fGkVCZsdR0RU53PSthFmoHVhZl+y9+6DqeDLSikLdlUVpVEAmI6iCRR5QyOjBYBqHZV/bdv4DJ4Gtw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-tsdoc@0.3.0: + resolution: {integrity: sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==} + + eslint-plugin-unicorn@54.0.0: + resolution: {integrity: sha512-XxYLRiYtAWiAjPv6z4JREby1TAE2byBC7wlh0V4vWDCpccOSU1KovWV//jqPXF6bq3WKxqX9rdjoRQ1EhdmNdQ==} + engines: {node: '>=18.18'} + peerDependencies: + eslint: '>=8.56.0' + + eslint-scope@8.0.2: + resolution: {integrity: sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-visitor-keys@4.0.0: + resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.7.0: + resolution: {integrity: sha512-FzJ9D/0nGiCGBf8UXO/IGLTgLVzIxze1zpfA8Ton2mjLovXdAPlYDv+MQDcqj3TmrhAGYfOpz9RfR+ent0AgAw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@10.1.0: + resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -667,9 +973,6 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -683,41 +986,66 @@ packages: fastq@1.16.0: resolution: {integrity: sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} flatted@3.2.9: resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + foreground-child@3.1.1: resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} engines: {node: '>=14'} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + + get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -731,33 +1059,68 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@15.8.0: + resolution: {integrity: sha512-VZAJ4cewHTExBWDHR6yptdIBlx9YSSZuwojj9Nt5mBRXQzrKakDsVKQ1J63sklLvzAJm0X5+RpO4i3Y2hcOnFw==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - ignore@5.3.0: - resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==} - engines: {node: '>= 4'} - ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} @@ -770,25 +1133,56 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} ioredis@5.4.1: resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} engines: {node: '>=12.22.0'} - irregular-plurals@3.5.0: - resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} - engines: {node: '>=8'} + is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-builtin-module@3.2.1: + resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} + engines: {node: '>=6'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.15.0: + resolution: {integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -801,6 +1195,14 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -809,13 +1211,35 @@ packages: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -824,23 +1248,52 @@ packages: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsdoc-type-pratt-parser@4.0.0: + resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} + engines: {node: '>=12.0.0'} + + jsesc@0.5.0: + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} + hasBin: true + + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -848,8 +1301,8 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lilconfig@3.0.0: - resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} + lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} lines-and-columns@1.2.4: @@ -862,7 +1315,11 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - locate-path@6.0.0: + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -878,18 +1335,10 @@ packages: lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - lru-cache@10.1.0: resolution: {integrity: sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag==} engines: {node: 14 || >=16.14} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - lunr@2.3.9: resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} @@ -915,17 +1364,20 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@9.0.4: - resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@7.0.4: resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==} engines: {node: '>=16 || 14 >=14.17'} @@ -939,6 +1391,12 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-releases@2.0.17: + resolution: {integrity: sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==} + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -951,8 +1409,29 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} @@ -962,30 +1441,49 @@ packages: resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} engines: {node: '>= 0.8.0'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-imports@2.1.1: + resolution: {integrity: sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==} + engines: {node: '>= 18'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.10.1: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} engines: {node: '>=16 || 14 >=14.17'} @@ -994,43 +1492,51 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - plur@4.0.0: - resolution: {integrity: sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==} - engines: {node: '>=10'} + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} peerDependencies: + jiti: '>=1.21.0' postcss: '>=8.0.9' - ts-node: '>=9.0.0' + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: + jiti: + optional: true postcss: optional: true - ts-node: + tsx: + optional: true + yaml: optional: true prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} - - prettier@3.3.2: - resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} - engines: {node: '>=14'} - hasBin: true - punycode.js@2.3.1: resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} engines: {node: '>=6'} @@ -1042,6 +1548,14 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + + read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -1054,6 +1568,22 @@ packages: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} + regexp-tree@0.1.27: + resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==} + hasBin: true + + regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + + regjsparser@0.10.0: + resolution: {integrity: sha512-qx+xQGZVsy55CH0a1hiVwHmqjLryfh7wQyF5HO07XJ9f7dQMY/gPQHhlyDkIzJKC+x2fUCpCcUODUUUFrm7SHA==} + hasBin: true + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1062,28 +1592,54 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - rollup@4.9.1: - resolution: {integrity: sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==} + rollup@4.18.1: + resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + + safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} hasBin: true + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1095,6 +1651,10 @@ packages: shiki@1.10.1: resolution: {integrity: sha512-uafV7WCgN4YYrccH6yxpnps6k38sSTlFRrwc4jycWmhWxJIm9dPrk+XkY1hZ2t0I7jmacMNb15Lf2fspa/Y3lg==} + side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -1106,10 +1666,31 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slashes@3.0.12: + resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==} + source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.18: + resolution: {integrity: sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==} + + stable-hash@0.0.4: + resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + standard-as-callback@2.1.0: resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==} @@ -1121,6 +1702,17 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1129,10 +1721,18 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -1142,18 +1742,26 @@ packages: engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - supports-hyperlinks@2.3.0: - resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} - engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} synckit@0.9.1: resolution: {integrity: sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==} engines: {node: ^14.18.0 || >=16.0.0} + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -1184,11 +1792,14 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tsup@8.1.0: - resolution: {integrity: sha512-UFdfCAXukax+U6KzeTNO2kAARHcWxmKsnvSPXUcfA1D+kU05XDccCrkffCQpFaWDsZfV0jMyTsxU39VfCp6EOg==} + tsup@8.1.2: + resolution: {integrity: sha512-Gzw/PXSX/z0aYMNmkcI54bKKFVFJQbLne+EqTJZeQ3lNT3QpumjtMU4rl+ZwTTp8oRF3ahMbEAxT2sZPJLFSrg==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -1210,21 +1821,47 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} + type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + + typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} - typedoc@0.26.3: - resolution: {integrity: sha512-6d2Sw9disvvpdk4K7VNjKr5/3hzijtfQVHRthhDqJgnhMHy1wQz4yPMJVKXElvnZhFr0nkzo+GzjXDTRV5yLpg==} + typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + + typedoc@0.26.4: + resolution: {integrity: sha512-FlW6HpvULDKgc3rK04V+nbFyXogPV88hurarDPOjuuB5HAwuAlrCMQ5NeH7Zt68a/ikOKu6Z/0hFXAeC9xPccQ==} engines: {node: '>= 18'} hasBin: true peerDependencies: typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x + typescript-eslint@7.16.1: + resolution: {integrity: sha512-889oE5qELj65q/tGeOSvlreNKhimitFwZqQ0o7PcWC7/lgRkAMknznsCsV8J8mZGTP/Z+cIbX8accf2DE33hrA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + typescript@5.5.3: resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==} engines: {node: '>=14.17'} @@ -1233,6 +1870,9 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -1240,15 +1880,31 @@ packages: resolution: {integrity: sha512-JfjKqIauur3Q6biAtHJ564e3bWa8VvT+7cSiOJHFbX4Erv6CLGDpg8z+Fmg/1OI/47RA+GI2QZaF48SSaLvyBA==} engines: {node: '>=18.17'} + update-browserslist-db@1.1.0: + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + webidl-conversions@4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1262,9 +1918,6 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.0: resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} @@ -1277,13 +1930,6 @@ packages: utf-8-validate: optional: true - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yaml@2.3.4: - resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} - engines: {node: '>= 14'} - yaml@2.4.5: resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} engines: {node: '>= 14'} @@ -1297,97 +1943,119 @@ snapshots: '@aashutoshrathi/word-wrap@1.2.6': {} - '@clytage/eslint-config@3.0.1(@eslint/js@8.57.0)(@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3))(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)': + '@babel/code-frame@7.24.7': dependencies: - '@eslint/js': 8.57.0 - eslint: 8.57.0 - optionalDependencies: - '@typescript-eslint/eslint-plugin': 7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3) - '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.5.3) - typescript: 5.5.3 + '@babel/highlight': 7.24.7 + picocolors: 1.0.1 + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@es-joy/jsdoccomment@0.46.0': + dependencies: + comment-parser: 1.4.1 + esquery: 1.6.0 + jsdoc-type-pratt-parser: 4.0.0 + + '@esbuild/aix-ppc64@0.23.0': + optional: true - '@esbuild/aix-ppc64@0.21.4': + '@esbuild/android-arm64@0.23.0': optional: true - '@esbuild/android-arm64@0.21.4': + '@esbuild/android-arm@0.23.0': optional: true - '@esbuild/android-arm@0.21.4': + '@esbuild/android-x64@0.23.0': optional: true - '@esbuild/android-x64@0.21.4': + '@esbuild/darwin-arm64@0.23.0': optional: true - '@esbuild/darwin-arm64@0.21.4': + '@esbuild/darwin-x64@0.23.0': optional: true - '@esbuild/darwin-x64@0.21.4': + '@esbuild/freebsd-arm64@0.23.0': optional: true - '@esbuild/freebsd-arm64@0.21.4': + '@esbuild/freebsd-x64@0.23.0': optional: true - '@esbuild/freebsd-x64@0.21.4': + '@esbuild/linux-arm64@0.23.0': optional: true - '@esbuild/linux-arm64@0.21.4': + '@esbuild/linux-arm@0.23.0': optional: true - '@esbuild/linux-arm@0.21.4': + '@esbuild/linux-ia32@0.23.0': optional: true - '@esbuild/linux-ia32@0.21.4': + '@esbuild/linux-loong64@0.23.0': optional: true - '@esbuild/linux-loong64@0.21.4': + '@esbuild/linux-mips64el@0.23.0': optional: true - '@esbuild/linux-mips64el@0.21.4': + '@esbuild/linux-ppc64@0.23.0': optional: true - '@esbuild/linux-ppc64@0.21.4': + '@esbuild/linux-riscv64@0.23.0': optional: true - '@esbuild/linux-riscv64@0.21.4': + '@esbuild/linux-s390x@0.23.0': optional: true - '@esbuild/linux-s390x@0.21.4': + '@esbuild/linux-x64@0.23.0': optional: true - '@esbuild/linux-x64@0.21.4': + '@esbuild/netbsd-x64@0.23.0': optional: true - '@esbuild/netbsd-x64@0.21.4': + '@esbuild/openbsd-arm64@0.23.0': optional: true - '@esbuild/openbsd-x64@0.21.4': + '@esbuild/openbsd-x64@0.23.0': optional: true - '@esbuild/sunos-x64@0.21.4': + '@esbuild/sunos-x64@0.23.0': optional: true - '@esbuild/win32-arm64@0.21.4': + '@esbuild/win32-arm64@0.23.0': optional: true - '@esbuild/win32-ia32@0.21.4': + '@esbuild/win32-ia32@0.23.0': optional: true - '@esbuild/win32-x64@0.21.4': + '@esbuild/win32-x64@0.23.0': optional: true - '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': + '@eslint-community/eslint-utils@4.4.0(eslint@9.7.0)': dependencies: - eslint: 8.57.0 + eslint: 9.7.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.10.0': {} + '@eslint-community/regexpp@4.11.0': {} + + '@eslint/config-array@0.17.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.4 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color - '@eslint/eslintrc@2.1.4': + '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 debug: 4.3.4 - espree: 9.6.1 - globals: 13.24.0 + espree: 10.1.0 + globals: 14.0.0 ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -1396,19 +2064,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.0': {} + '@eslint/js@9.7.0': {} - '@humanwhocodes/config-array@0.11.14': - dependencies: - '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@eslint/object-schema@2.1.4': {} '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.2': {} + '@humanwhocodes/retry@0.3.0': {} '@ioredis/commands@1.2.0': {} @@ -1438,6 +2100,15 @@ snapshots: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + '@microsoft/tsdoc-config@0.17.0': + dependencies: + '@microsoft/tsdoc': 0.15.0 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.8 + + '@microsoft/tsdoc@0.15.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -1455,48 +2126,122 @@ snapshots: '@pkgr/core@0.1.0': {} - '@rollup/rollup-android-arm-eabi@4.9.1': + '@rollup/rollup-android-arm-eabi@4.18.1': + optional: true + + '@rollup/rollup-android-arm64@4.18.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.18.1': optional: true - '@rollup/rollup-android-arm64@4.9.1': + '@rollup/rollup-darwin-x64@4.18.1': optional: true - '@rollup/rollup-darwin-arm64@4.9.1': + '@rollup/rollup-linux-arm-gnueabihf@4.18.1': optional: true - '@rollup/rollup-darwin-x64@4.9.1': + '@rollup/rollup-linux-arm-musleabihf@4.18.1': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.9.1': + '@rollup/rollup-linux-arm64-gnu@4.18.1': optional: true - '@rollup/rollup-linux-arm64-gnu@4.9.1': + '@rollup/rollup-linux-arm64-musl@4.18.1': optional: true - '@rollup/rollup-linux-arm64-musl@4.9.1': + '@rollup/rollup-linux-powerpc64le-gnu@4.18.1': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.9.1': + '@rollup/rollup-linux-riscv64-gnu@4.18.1': optional: true - '@rollup/rollup-linux-x64-gnu@4.9.1': + '@rollup/rollup-linux-s390x-gnu@4.18.1': optional: true - '@rollup/rollup-linux-x64-musl@4.9.1': + '@rollup/rollup-linux-x64-gnu@4.18.1': optional: true - '@rollup/rollup-win32-arm64-msvc@4.9.1': + '@rollup/rollup-linux-x64-musl@4.18.1': optional: true - '@rollup/rollup-win32-ia32-msvc@4.9.1': + '@rollup/rollup-win32-arm64-msvc@4.18.1': optional: true - '@rollup/rollup-win32-x64-msvc@4.9.1': + '@rollup/rollup-win32-ia32-msvc@4.18.1': optional: true + '@rollup/rollup-win32-x64-msvc@4.18.1': + optional: true + + '@rtsao/scc@1.1.0': {} + '@shikijs/core@1.10.1': {} - '@types/eslint@8.56.0': + '@stegripe/eslint-config@1.0.0(@stylistic/eslint-plugin@2.3.0(eslint@9.7.0)(typescript@5.5.3))(eslint-config-prettier@9.1.0(eslint@9.7.0))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0))(eslint-plugin-import-x@3.0.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-jsdoc@48.7.0(eslint@9.7.0))(eslint-plugin-n@17.9.0(eslint@9.7.0))(eslint-plugin-promise@6.4.0(eslint@9.7.0))(eslint-plugin-tsdoc@0.3.0)(eslint-plugin-unicorn@54.0.0(eslint@9.7.0))(eslint@9.7.0)(globals@15.8.0)(typescript-eslint@7.16.1(eslint@9.7.0)(typescript@5.5.3))(typescript@5.5.3)': + dependencies: + '@stylistic/eslint-plugin': 2.3.0(eslint@9.7.0)(typescript@5.5.3) + eslint: 9.7.0 + eslint-config-prettier: 9.1.0(eslint@9.7.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0) + eslint-plugin-import-x: 3.0.1(eslint@9.7.0)(typescript@5.5.3) + eslint-plugin-jsdoc: 48.7.0(eslint@9.7.0) + eslint-plugin-n: 17.9.0(eslint@9.7.0) + eslint-plugin-promise: 6.4.0(eslint@9.7.0) + eslint-plugin-tsdoc: 0.3.0 + eslint-plugin-unicorn: 54.0.0(eslint@9.7.0) + globals: 15.8.0 + typescript: 5.5.3 + typescript-eslint: 7.16.1(eslint@9.7.0)(typescript@5.5.3) + + '@stylistic/eslint-plugin-js@2.3.0(eslint@9.7.0)': + dependencies: + '@types/eslint': 8.56.10 + acorn: 8.12.1 + eslint: 9.7.0 + eslint-visitor-keys: 4.0.0 + espree: 10.1.0 + + '@stylistic/eslint-plugin-jsx@2.3.0(eslint@9.7.0)': + dependencies: + '@stylistic/eslint-plugin-js': 2.3.0(eslint@9.7.0) + '@types/eslint': 8.56.10 + eslint: 9.7.0 + estraverse: 5.3.0 + picomatch: 4.0.2 + + '@stylistic/eslint-plugin-plus@2.3.0(eslint@9.7.0)(typescript@5.5.3)': + dependencies: + '@types/eslint': 8.56.10 + '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + eslint: 9.7.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@stylistic/eslint-plugin-ts@2.3.0(eslint@9.7.0)(typescript@5.5.3)': + dependencies: + '@stylistic/eslint-plugin-js': 2.3.0(eslint@9.7.0) + '@types/eslint': 8.56.10 + '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + eslint: 9.7.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@stylistic/eslint-plugin@2.3.0(eslint@9.7.0)(typescript@5.5.3)': + dependencies: + '@stylistic/eslint-plugin-js': 2.3.0(eslint@9.7.0) + '@stylistic/eslint-plugin-jsx': 2.3.0(eslint@9.7.0) + '@stylistic/eslint-plugin-plus': 2.3.0(eslint@9.7.0)(typescript@5.5.3) + '@stylistic/eslint-plugin-ts': 2.3.0(eslint@9.7.0)(typescript@5.5.3) + '@types/eslint': 8.56.10 + eslint: 9.7.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@types/eslint@8.56.10': dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 @@ -1505,23 +2250,27 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/node@20.14.10': + '@types/json5@0.0.29': {} + + '@types/node@20.14.11': dependencies: undici-types: 5.26.5 - '@types/ws@8.5.10': + '@types/normalize-package-data@2.4.4': {} + + '@types/ws@8.5.11': dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.11 - '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)': + '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3)': dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.5.3) + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 7.16.1(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/scope-manager': 7.16.1 - '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.5.3) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.5.3) + '@typescript-eslint/type-utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3) '@typescript-eslint/visitor-keys': 7.16.1 - eslint: 8.57.0 + eslint: 9.7.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 @@ -1531,14 +2280,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.5.3)': + '@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3)': dependencies: '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3) '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.4 - eslint: 8.57.0 + debug: 4.3.5 + eslint: 9.7.0 optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: @@ -1549,12 +2298,12 @@ snapshots: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 - '@typescript-eslint/type-utils@7.16.1(eslint@8.57.0)(typescript@5.5.3)': + '@typescript-eslint/type-utils@7.16.1(eslint@9.7.0)(typescript@5.5.3)': dependencies: '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3) - '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.5.3) - debug: 4.3.4 - eslint: 8.57.0 + '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + debug: 4.3.5 + eslint: 9.7.0 ts-api-utils: 1.3.0(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 @@ -1567,24 +2316,24 @@ snapshots: dependencies: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.4 + debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.0 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.5.3) optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.16.1(eslint@8.57.0)(typescript@5.5.3)': + '@typescript-eslint/utils@7.16.1(eslint@9.7.0)(typescript@5.5.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/types': 7.16.1 '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.5.3) - eslint: 8.57.0 + eslint: 9.7.0 transitivePeerDependencies: - supports-color - typescript @@ -1594,13 +2343,11 @@ snapshots: '@typescript-eslint/types': 7.16.1 eslint-visitor-keys: 3.4.3 - '@ungap/structured-clone@1.2.0': {} - - acorn-jsx@5.3.2(acorn@8.11.2): + acorn-jsx@5.3.2(acorn@8.12.1): dependencies: - acorn: 8.11.2 + acorn: 8.12.1 - acorn@8.11.2: {} + acorn@8.12.1: {} ajv@6.12.6: dependencies: @@ -1609,14 +2356,21 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ansi-escapes@4.3.2: + ajv@8.12.0: dependencies: - type-fest: 0.21.3 + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 ansi-regex@5.0.1: {} ansi-regex@6.0.1: {} + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -1630,10 +2384,64 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + are-docs-informative@0.0.2: {} + argparse@2.0.1: {} + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + array-union@2.1.0: {} + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + balanced-match@1.0.2: {} binary-extensions@2.2.0: {} @@ -1651,21 +2459,46 @@ snapshots: dependencies: fill-range: 7.0.1 - bundle-require@4.0.2(esbuild@0.21.4): + browserslist@4.23.2: + dependencies: + caniuse-lite: 1.0.30001642 + electron-to-chromium: 1.4.829 + node-releases: 2.0.17 + update-browserslist-db: 1.1.0(browserslist@4.23.2) + + builtin-modules@3.3.0: {} + + bundle-require@5.0.0(esbuild@0.23.0): dependencies: - esbuild: 0.21.4 + esbuild: 0.23.0 load-tsconfig: 0.2.5 cac@6.7.14: {} + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + callsites@3.1.0: {} + caniuse-lite@1.0.30001642: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - chokidar@3.5.3: + chokidar@3.6.0: dependencies: anymatch: 3.1.3 braces: 3.0.2 @@ -1677,18 +2510,38 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + ci-info@4.0.0: {} + + clean-regexp@1.0.0: + dependencies: + escape-string-regexp: 1.0.5 + cluster-key-slot@1.1.2: {} + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} commander@4.1.1: {} + comment-parser@1.4.1: {} + concat-map@0.0.1: {} + consola@3.2.3: {} + + core-js-compat@3.37.1: + dependencies: + browserslist: 4.23.2 + cross-env@7.0.3: dependencies: cross-spawn: 7.0.3 @@ -1699,124 +2552,386 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + debug@3.2.7: + dependencies: + ms: 2.1.2 + debug@4.3.4: dependencies: ms: 2.1.2 + debug@4.3.5: + dependencies: + ms: 2.1.2 + deep-is@0.1.4: {} + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + denque@2.1.0: {} dir-glob@3.0.1: dependencies: path-type: 4.0.0 + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + doctrine@3.0.0: dependencies: esutils: 2.0.3 eastasianwidth@0.2.0: {} + electron-to-chromium@1.4.829: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} + enhanced-resolve@5.17.0: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + entities@4.5.0: {} - esbuild@0.21.4: + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.23.3: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.2 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 + + es-errors@1.3.0: {} + + es-module-lexer@1.5.4: {} + + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + esbuild@0.23.0: optionalDependencies: - '@esbuild/aix-ppc64': 0.21.4 - '@esbuild/android-arm': 0.21.4 - '@esbuild/android-arm64': 0.21.4 - '@esbuild/android-x64': 0.21.4 - '@esbuild/darwin-arm64': 0.21.4 - '@esbuild/darwin-x64': 0.21.4 - '@esbuild/freebsd-arm64': 0.21.4 - '@esbuild/freebsd-x64': 0.21.4 - '@esbuild/linux-arm': 0.21.4 - '@esbuild/linux-arm64': 0.21.4 - '@esbuild/linux-ia32': 0.21.4 - '@esbuild/linux-loong64': 0.21.4 - '@esbuild/linux-mips64el': 0.21.4 - '@esbuild/linux-ppc64': 0.21.4 - '@esbuild/linux-riscv64': 0.21.4 - '@esbuild/linux-s390x': 0.21.4 - '@esbuild/linux-x64': 0.21.4 - '@esbuild/netbsd-x64': 0.21.4 - '@esbuild/openbsd-x64': 0.21.4 - '@esbuild/sunos-x64': 0.21.4 - '@esbuild/win32-arm64': 0.21.4 - '@esbuild/win32-ia32': 0.21.4 - '@esbuild/win32-x64': 0.21.4 + '@esbuild/aix-ppc64': 0.23.0 + '@esbuild/android-arm': 0.23.0 + '@esbuild/android-arm64': 0.23.0 + '@esbuild/android-x64': 0.23.0 + '@esbuild/darwin-arm64': 0.23.0 + '@esbuild/darwin-x64': 0.23.0 + '@esbuild/freebsd-arm64': 0.23.0 + '@esbuild/freebsd-x64': 0.23.0 + '@esbuild/linux-arm': 0.23.0 + '@esbuild/linux-arm64': 0.23.0 + '@esbuild/linux-ia32': 0.23.0 + '@esbuild/linux-loong64': 0.23.0 + '@esbuild/linux-mips64el': 0.23.0 + '@esbuild/linux-ppc64': 0.23.0 + '@esbuild/linux-riscv64': 0.23.0 + '@esbuild/linux-s390x': 0.23.0 + '@esbuild/linux-x64': 0.23.0 + '@esbuild/netbsd-x64': 0.23.0 + '@esbuild/openbsd-arm64': 0.23.0 + '@esbuild/openbsd-x64': 0.23.0 + '@esbuild/sunos-x64': 0.23.0 + '@esbuild/win32-arm64': 0.23.0 + '@esbuild/win32-ia32': 0.23.0 + '@esbuild/win32-x64': 0.23.0 + + escalade@3.1.2: {} + + escape-string-regexp@1.0.5: {} escape-string-regexp@4.0.0: {} - eslint-config-prettier@9.1.0(eslint@8.57.0): + eslint-compat-utils@0.5.1(eslint@9.7.0): dependencies: - eslint: 8.57.0 + eslint: 9.7.0 + semver: 7.6.3 - eslint-formatter-pretty@5.0.0: + eslint-config-prettier@9.1.0(eslint@9.7.0): dependencies: - '@types/eslint': 8.56.0 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - eslint-rule-docs: 1.1.235 - log-symbols: 4.1.0 - plur: 4.0.0 - string-width: 4.2.3 - supports-hyperlinks: 2.3.0 + eslint: 9.7.0 - eslint-plugin-prettier@5.2.1(@types/eslint@8.56.0)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.2): + eslint-import-resolver-node@0.3.9: dependencies: - eslint: 8.57.0 - prettier: 3.3.2 - prettier-linter-helpers: 1.0.0 - synckit: 0.9.1 + debug: 3.2.7 + is-core-module: 2.15.0 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0): + dependencies: + debug: 4.3.5 + enhanced-resolve: 5.17.0 + eslint: 9.7.0 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0))(eslint@9.7.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1)(eslint@9.7.0) + fast-glob: 3.3.2 + get-tsconfig: 4.7.5 + is-core-module: 2.15.0 + is-glob: 4.0.3 + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0))(eslint@9.7.0): + dependencies: + debug: 3.2.7 optionalDependencies: - '@types/eslint': 8.56.0 - eslint-config-prettier: 9.1.0(eslint@8.57.0) + '@typescript-eslint/parser': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + eslint: 9.7.0 + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0) + transitivePeerDependencies: + - supports-color + + eslint-plugin-es-x@7.8.0(eslint@9.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) + '@eslint-community/regexpp': 4.11.0 + eslint: 9.7.0 + eslint-compat-utils: 0.5.1(eslint@9.7.0) + + eslint-plugin-import-x@3.0.1(eslint@9.7.0)(typescript@5.5.3): + dependencies: + '@rtsao/scc': 1.1.0 + '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + debug: 4.3.5 + doctrine: 3.0.0 + eslint: 9.7.0 + eslint-import-resolver-node: 0.3.9 + get-tsconfig: 4.7.5 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + stable-hash: 0.0.4 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + - typescript - eslint-rule-docs@1.1.235: {} + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-import-resolver-typescript@3.6.1)(eslint@9.7.0): + dependencies: + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.7.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint-plugin-import@2.29.1)(eslint@9.7.0))(eslint@9.7.0) + hasown: 2.0.2 + is-core-module: 2.15.0 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsdoc@48.7.0(eslint@9.7.0): + dependencies: + '@es-joy/jsdoccomment': 0.46.0 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.3.5 + escape-string-regexp: 4.0.0 + eslint: 9.7.0 + esquery: 1.6.0 + parse-imports: 2.1.1 + semver: 7.6.3 + spdx-expression-parse: 4.0.0 + synckit: 0.9.1 + transitivePeerDependencies: + - supports-color + + eslint-plugin-n@17.9.0(eslint@9.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) + enhanced-resolve: 5.17.0 + eslint: 9.7.0 + eslint-plugin-es-x: 7.8.0(eslint@9.7.0) + get-tsconfig: 4.7.5 + globals: 15.8.0 + ignore: 5.3.1 + minimatch: 9.0.5 + semver: 7.6.3 + + eslint-plugin-promise@6.4.0(eslint@9.7.0): + dependencies: + eslint: 9.7.0 + + eslint-plugin-tsdoc@0.3.0: + dependencies: + '@microsoft/tsdoc': 0.15.0 + '@microsoft/tsdoc-config': 0.17.0 + + eslint-plugin-unicorn@54.0.0(eslint@9.7.0): + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) + '@eslint/eslintrc': 3.1.0 + ci-info: 4.0.0 + clean-regexp: 1.0.0 + core-js-compat: 3.37.1 + eslint: 9.7.0 + esquery: 1.6.0 + indent-string: 4.0.0 + is-builtin-module: 3.2.1 + jsesc: 3.0.2 + pluralize: 8.0.0 + read-pkg-up: 7.0.1 + regexp-tree: 0.1.27 + regjsparser: 0.10.0 + semver: 7.6.3 + strip-indent: 3.0.0 + transitivePeerDependencies: + - supports-color - eslint-scope@7.2.2: + eslint-scope@8.0.2: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint@8.57.0: + eslint-visitor-keys@4.0.0: {} + + eslint@9.7.0: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.7.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/config-array': 0.17.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.7.0 '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.3.0 '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.4 - doctrine: 3.0.0 escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 + eslint-scope: 8.0.2 + eslint-visitor-keys: 4.0.0 + espree: 10.1.0 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.0 + ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 - js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 @@ -1828,16 +2943,20 @@ snapshots: transitivePeerDependencies: - supports-color - espree@9.6.1: + espree@10.1.0: dependencies: - acorn: 8.11.2 - acorn-jsx: 5.3.2(acorn@8.11.2) - eslint-visitor-keys: 3.4.3 + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) + eslint-visitor-keys: 4.0.0 esquery@1.5.0: dependencies: estraverse: 5.3.0 + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -1860,8 +2979,6 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-diff@1.3.0: {} - fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -1878,39 +2995,74 @@ snapshots: dependencies: reusify: 1.0.4 - file-entry-cache@6.0.1: + file-entry-cache@8.0.0: dependencies: - flat-cache: 3.2.0 + flat-cache: 4.0.1 fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - flat-cache@3.2.0: + flat-cache@4.0.1: dependencies: flatted: 3.2.9 keyv: 4.5.4 - rimraf: 3.0.2 flatted@3.2.9: {} + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + foreground-child@3.1.1: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functions-have-names@1.2.3: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + get-stream@6.0.1: {} + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + get-tsconfig@4.7.5: + dependencies: + resolve-pkg-maps: 1.0.0 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -1923,22 +3075,18 @@ snapshots: dependencies: foreground-child: 3.1.1 jackspeak: 2.3.6 - minimatch: 9.0.4 + minimatch: 9.0.5 minipass: 7.0.4 path-scurry: 1.10.1 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + globals@14.0.0: {} + + globals@15.8.0: {} - globals@13.24.0: + globalthis@1.0.4: dependencies: - type-fest: 0.20.2 + define-properties: 1.2.1 + gopd: 1.0.1 globby@11.1.0: dependencies: @@ -1949,13 +3097,39 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 + + graceful-fs@4.2.11: {} + graphemer@1.4.0: {} + has-bigints@1.0.2: {} + + has-flag@3.0.0: {} + has-flag@4.0.0: {} - human-signals@2.1.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 - ignore@5.3.0: {} + hosted-git-info@2.8.9: {} + + human-signals@2.1.0: {} ignore@5.3.1: {} @@ -1966,12 +3140,13 @@ snapshots: imurmurhash@0.1.4: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 + indent-string@4.0.0: {} - inherits@2.0.4: {} + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 ioredis@5.4.1: dependencies: @@ -1987,12 +3162,44 @@ snapshots: transitivePeerDependencies: - supports-color - irregular-plurals@3.5.0: {} + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-arrayish@0.2.1: {} + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 is-binary-path@2.1.0: dependencies: binary-extensions: 2.2.0 + is-boolean-object@1.1.2: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-builtin-module@3.2.1: + dependencies: + builtin-modules: 3.3.0 + + is-callable@1.2.7: {} + + is-core-module@2.15.0: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 + is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} @@ -2001,13 +3208,44 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + is-number@7.0.0: {} is-path-inside@3.0.3: {} + is-regex@1.1.4: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + is-stream@2.0.1: {} - is-unicode-supported@0.1.0: {} + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + isarray@2.0.5: {} isexe@2.0.0: {} @@ -2017,18 +3255,36 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jju@1.4.0: {} + joycon@3.1.1: {} + js-tokens@4.0.0: {} + js-yaml@4.1.0: dependencies: argparse: 2.0.1 + jsdoc-type-pratt-parser@4.0.0: {} + + jsesc@0.5.0: {} + + jsesc@3.0.2: {} + json-buffer@3.0.1: {} + json-parse-even-better-errors@2.3.1: {} + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} + json5@1.0.2: + dependencies: + minimist: 1.2.8 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -2038,7 +3294,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lilconfig@3.0.0: {} + lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} @@ -2048,6 +3304,10 @@ snapshots: load-tsconfig@0.2.5: {} + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -2060,17 +3320,8 @@ snapshots: lodash.sortby@4.7.0: {} - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - lru-cache@10.1.0: {} - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - lunr@2.3.9: {} markdown-it@14.1.0: @@ -2095,18 +3346,18 @@ snapshots: mimic-fn@2.1.0: {} + min-indent@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - minimatch@9.0.4: - dependencies: - brace-expansion: 2.0.1 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + minipass@7.0.4: {} ms@2.1.2: {} @@ -2119,6 +3370,15 @@ snapshots: natural-compare@1.4.0: {} + node-releases@2.0.17: {} + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.8 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} npm-run-path@4.0.1: @@ -2127,9 +3387,35 @@ snapshots: object-assign@4.1.1: {} - once@1.4.0: + object-inspect@1.13.2: {} + + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.fromentries@2.0.8: dependencies: - wrappy: 1.0.2 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 onetime@5.1.2: dependencies: @@ -2144,24 +3430,46 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-try@2.2.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - path-exists@4.0.0: {} + parse-imports@2.1.1: + dependencies: + es-module-lexer: 1.5.4 + slashes: 3.0.12 - path-is-absolute@1.0.1: {} + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.24.7 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} path-key@3.1.1: {} + path-parse@1.0.7: {} + path-scurry@1.10.1: dependencies: lru-cache: 10.1.0 @@ -2169,26 +3477,25 @@ snapshots: path-type@4.0.0: {} + picocolors@1.0.1: {} + picomatch@2.3.1: {} - pirates@4.0.6: {} + picomatch@4.0.2: {} - plur@4.0.0: - dependencies: - irregular-plurals: 3.5.0 + pirates@4.0.6: {} - postcss-load-config@4.0.2: - dependencies: - lilconfig: 3.0.0 - yaml: 2.3.4 + pluralize@8.0.0: {} - prelude-ls@1.2.1: {} + possible-typed-array-names@1.0.0: {} - prettier-linter-helpers@1.0.0: + postcss-load-config@6.0.1(yaml@2.4.5): dependencies: - fast-diff: 1.3.0 + lilconfig: 3.1.2 + optionalDependencies: + yaml: 2.4.5 - prettier@3.3.2: {} + prelude-ls@1.2.1: {} punycode.js@2.3.1: {} @@ -2196,6 +3503,19 @@ snapshots: queue-microtask@1.2.3: {} + read-pkg-up@7.0.1: + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + + read-pkg@5.2.0: + dependencies: + '@types/normalize-package-data': 2.4.4 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -2206,40 +3526,95 @@ snapshots: dependencies: redis-errors: 1.2.0 + regexp-tree@0.1.27: {} + + regexp.prototype.flags@1.5.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + regjsparser@0.10.0: + dependencies: + jsesc: 0.5.0 + + require-from-string@2.0.2: {} + resolve-from@4.0.0: {} resolve-from@5.0.0: {} - reusify@1.0.4: {} + resolve-pkg-maps@1.0.0: {} - rimraf@3.0.2: + resolve@1.22.8: dependencies: - glob: 7.2.3 + is-core-module: 2.15.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.0.4: {} - rollup@4.9.1: + rollup@4.18.1: + dependencies: + '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.9.1 - '@rollup/rollup-android-arm64': 4.9.1 - '@rollup/rollup-darwin-arm64': 4.9.1 - '@rollup/rollup-darwin-x64': 4.9.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.9.1 - '@rollup/rollup-linux-arm64-gnu': 4.9.1 - '@rollup/rollup-linux-arm64-musl': 4.9.1 - '@rollup/rollup-linux-riscv64-gnu': 4.9.1 - '@rollup/rollup-linux-x64-gnu': 4.9.1 - '@rollup/rollup-linux-x64-musl': 4.9.1 - '@rollup/rollup-win32-arm64-msvc': 4.9.1 - '@rollup/rollup-win32-ia32-msvc': 4.9.1 - '@rollup/rollup-win32-x64-msvc': 4.9.1 + '@rollup/rollup-android-arm-eabi': 4.18.1 + '@rollup/rollup-android-arm64': 4.18.1 + '@rollup/rollup-darwin-arm64': 4.18.1 + '@rollup/rollup-darwin-x64': 4.18.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.18.1 + '@rollup/rollup-linux-arm-musleabihf': 4.18.1 + '@rollup/rollup-linux-arm64-gnu': 4.18.1 + '@rollup/rollup-linux-arm64-musl': 4.18.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.18.1 + '@rollup/rollup-linux-riscv64-gnu': 4.18.1 + '@rollup/rollup-linux-s390x-gnu': 4.18.1 + '@rollup/rollup-linux-x64-gnu': 4.18.1 + '@rollup/rollup-linux-x64-musl': 4.18.1 + '@rollup/rollup-win32-arm64-msvc': 4.18.1 + '@rollup/rollup-win32-ia32-msvc': 4.18.1 + '@rollup/rollup-win32-x64-msvc': 4.18.1 fsevents: 2.3.3 run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - semver@7.6.0: + safe-array-concat@1.1.2: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + + safe-regex-test@1.0.3: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.6.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: dependencies: - lru-cache: 6.0.0 + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 shebang-command@2.0.0: dependencies: @@ -2251,16 +3626,46 @@ snapshots: dependencies: '@shikijs/core': 1.10.1 + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + signal-exit@3.0.7: {} signal-exit@4.1.0: {} slash@3.0.0: {} + slashes@3.0.12: {} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.18 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.18 + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.18 + + spdx-license-ids@3.0.18: {} + + stable-hash@0.0.4: {} + standard-as-callback@2.1.0: {} string-width@4.2.3: @@ -2275,6 +3680,25 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -2283,8 +3707,14 @@ snapshots: dependencies: ansi-regex: 6.0.1 + strip-bom@3.0.0: {} + strip-final-newline@2.0.0: {} + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + strip-json-comments@3.1.1: {} sucrase@3.35.0: @@ -2297,20 +3727,23 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 - supports-color@7.2.0: + supports-color@5.5.0: dependencies: - has-flag: 4.0.0 + has-flag: 3.0.0 - supports-hyperlinks@2.3.0: + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - supports-color: 7.2.0 + + supports-preserve-symlinks-flag@1.0.0: {} synckit@0.9.1: dependencies: '@pkgr/core': 0.1.0 tslib: 2.6.2 + tapable@2.2.1: {} + text-table@0.2.0: {} thenify-all@1.6.0: @@ -2337,39 +3770,81 @@ snapshots: ts-interface-checker@0.1.13: {} + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + tslib@2.6.2: {} - tsup@8.1.0(typescript@5.5.3): + tsup@8.1.2(typescript@5.5.3)(yaml@2.4.5): dependencies: - bundle-require: 4.0.2(esbuild@0.21.4) + bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4 - esbuild: 0.21.4 + chokidar: 3.6.0 + consola: 3.2.3 + debug: 4.3.5 + esbuild: 0.23.0 execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.2 + postcss-load-config: 6.0.1(yaml@2.4.5) resolve-from: 5.0.0 - rollup: 4.9.1 + rollup: 4.18.1 source-map: 0.8.0-beta.0 sucrase: 3.35.0 tree-kill: 1.2.2 optionalDependencies: typescript: 5.5.3 transitivePeerDependencies: + - jiti - supports-color - - ts-node + - tsx + - yaml type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - type-fest@0.20.2: {} + type-fest@0.6.0: {} + + type-fest@0.8.1: {} - type-fest@0.21.3: {} + typed-array-buffer@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 - typedoc@0.26.3(typescript@5.5.3): + typed-array-byte-offset@1.0.2: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-length@1.0.6: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + typedoc@0.26.4(typescript@5.5.3): dependencies: lunr: 2.3.9 markdown-it: 14.1.0 @@ -2378,18 +3853,47 @@ snapshots: typescript: 5.5.3 yaml: 2.4.5 + typescript-eslint@7.16.1(eslint@9.7.0)(typescript@5.5.3): + dependencies: + '@typescript-eslint/eslint-plugin': 7.16.1(@typescript-eslint/parser@7.16.1(eslint@9.7.0)(typescript@5.5.3))(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/parser': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + '@typescript-eslint/utils': 7.16.1(eslint@9.7.0)(typescript@5.5.3) + eslint: 9.7.0 + optionalDependencies: + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + typescript@5.5.3: {} uc.micro@2.1.0: {} + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + undici-types@5.26.5: {} undici@6.19.2: {} + update-browserslist-db@1.1.0(browserslist@4.23.2): + dependencies: + browserslist: 4.23.2 + escalade: 3.1.2 + picocolors: 1.0.1 + uri-js@4.4.1: dependencies: punycode: 2.3.1 + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + webidl-conversions@4.0.2: {} whatwg-url@7.1.0: @@ -2398,6 +3902,22 @@ snapshots: tr46: 1.0.1 webidl-conversions: 4.0.2 + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -2414,14 +3934,8 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 - wrappy@1.0.2: {} - ws@8.18.0: {} - yallist@4.0.0: {} - - yaml@2.3.4: {} - yaml@2.4.5: {} yocto-queue@0.1.0: {} diff --git a/src/Constants.ts b/src/Constants.ts index 72c0ce2..36f1871 100644 --- a/src/Constants.ts +++ b/src/Constants.ts @@ -1,27 +1,28 @@ +/* eslint-disable typescript/explicit-module-boundary-types */ export enum State { - Connecting = 0, - Nearly = 1, - Connected = 2, - Reconnecting = 3, - Disconnecting = 4, - Disconnected = 5 + Connecting = 0, + Nearly = 1, + Connected = 2, + Reconnecting = 3, + Disconnecting = 4, + Disconnected = 5 } export enum VoiceState { - SessionReady = 0, - SessionIdMissing = 1, - SessionEndpointMissing = 2, - SessionFailedUpdate = 3 + SessionReady = 0, + SessionIdMissing = 1, + SessionEndpointMissing = 2, + SessionFailedUpdate = 3 } export enum OpCodes { - PlayerUpdate = "playerUpdate", - Stats = "stats", - Event = "event", - Ready = "ready" + PlayerUpdate = "playerUpdate", + Stats = "stats", + Event = "event", + Ready = "ready" } export const RedisKey = { - NodeSession: (name: string) => `icelink:node:${name}:session`, - NodePlayers: (name: string) => `icelink:node:${name}:players` + NodeSession: (name: string) => `esbatu:node:${name}:session`, + NodePlayers: (name: string) => `esbatu:node:${name}:players` }; diff --git a/src/Esbatu.ts b/src/Esbatu.ts new file mode 100644 index 0000000..bc19d34 --- /dev/null +++ b/src/Esbatu.ts @@ -0,0 +1,326 @@ +/* eslint-disable typescript/no-unsafe-member-access, typescript/no-unsafe-argument, typescript/no-unsafe-assignment, tsdoc/syntax */ +import { EventEmitter } from "node:events"; +import type { Redis } from "ioredis"; +import { name as packageName, version as packageVersion } from "../package.json"; +import { State, VoiceState } from "./Constants"; +import type { Player } from "./guild/Player"; +import type { VoiceConnection } from "./guild/VoiceConnection"; +import type { Rest } from "./node/Rest"; +import { Node } from "./node/index"; + +export type VoiceChannelOptions = { + /** + * A id of Guild in which the {@link VoiceChannelOptions.channelId} of the voice channel is located. + */ + guildId: string; + /** + * A id of Shard to track where this should send on sharded websockets, put 0 if you are unsharded. + */ + shardId: number; + /** + * A id of the voice channel you want to connect to. + */ + channelId: string; + /** + * Whether to deafen or undeafen the current bot user. + */ + mute?: boolean; + /** + * Whether to mute or unmute the current bot user. + */ + deaf?: boolean; +}; + +export type NodeOption = { + /** + * Name of this node. + */ + name: string; + /** + * A credentials to access the Lavalink. + */ + authorization: string; + /** + * A URL of the Lavalink. + */ + url: string; + /** + * Whether to use secure protocols or not. + */ + secure?: boolean; +}; + +export type EsbatuOptions = { + /** + * Whether to move players to a different Lavalink node when a node disconnect. + */ + moveOnDisconnect?: boolean; + /** + * The {@link Node} options, for all the nodes. + */ + nodes: NodeOption[]; + /** + * Timeout before trying to reconnect. + */ + reconnectInterval?: number; + /** + * Number of times to try and reconnect to Lavalink before giving up. + */ + reconnectTries?: number; + /** + * Whether to use redis cache system to save the node session and channel id from players, or not. + */ + redis?: Redis; + /** + * Whether to resume a connection on disconnect from the Lavalink. (Server Side) + */ + resume?: boolean; + /** + * Whether to resume the players by doing it in the library side. (Client Side) + */ + resumeByLibrary?: boolean; + /** + * Time to wait before lavalink starts to destroy the players of the disconnected client. + */ + resumeTimeout?: number; + /** + * Time to wait for a response from the Lavalink REST API before giving up. + */ + restTimeout?: number; + /** + * Custom or extend the structures for Esbatu to use. + */ + structures?: Structures; + /** + * User Agent to use when making requests to Lavalink. + */ + userAgent?: string; + /** + * Timeout before abort the voice connection. + */ + voiceConnectionTimeout?: number; +}; + +type Constructor = new (...args: any[]) => T; + +export type Structures = { + /** + * A custom structure that extends the {@link Rest} class. + */ + rest?: Constructor; + /** + * A custom structure that extends the {@link Player} class. + */ + player?: Constructor; +}; + +/** + * Main Esbatu class. + */ +// @ts-expect-error ignore this ts(2300) +export abstract class Esbatu extends EventEmitter { + /** + * A Esbatu options. + * + * @readonly + */ + public readonly options: Required>; + /** + * Connected Lavalink nodes. + * + * @readonly + */ + public readonly nodes = new Map(); + /** + * Voice connections being handled. + * + * @readonly + */ + public readonly connections = new Map(); + /** + * Players being handled. + * + * @readonly + */ + public readonly players = new Map(); + /** + * redis cache being handle for save node session and players. + * + * @readonly + */ + public readonly redis: Redis | null = null; + /** + * Esbatu instance identifier. + */ + public id: string | null = null; + + /** + * Creates a new Esbatu. + * + * @param options An options to pass to create this Esbatu instance. + */ + public constructor(options: EsbatuOptions) { + super(); + + this.options = { + moveOnDisconnect: options.moveOnDisconnect ?? false, + nodes: options.nodes, + reconnectInterval: options.reconnectInterval ?? 5, + reconnectTries: options.reconnectTries ?? 3, + resume: options.resume ?? false, + resumeByLibrary: options.resumeByLibrary ?? false, + resumeTimeout: options.resumeTimeout ?? 30, + restTimeout: options.restTimeout ?? 60, + structures: options.structures ?? {}, + userAgent: options.userAgent ?? `${packageName}/${packageVersion}`, + voiceConnectionTimeout: options.voiceConnectionTimeout ?? 15 + }; + this.redis = options.redis ?? null; + + Object.defineProperties(this, { + options: { enumerable: false, writable: false }, + nodes: { enumerable: true, writable: false }, + connections: { enumerable: true, writable: false }, + players: { enumerable: true, writable: false }, + redis: { enumerable: false, writable: false }, + id: { enumerable: false, writable: true } + }); + } + + /** + * A ideal Lavalink node if available connected. + * + * @readonly + */ + public get idealNode(): Node | undefined { + return [...this.nodes.values()] + .filter(node => node.state === State.Connected) + .sort((a, b) => a.penalties - b.penalties) + .shift(); + } + + /** + * Add a Lavalink node to the pool of available nodes. + * + * @param options A node options for instance. + */ + public async addNode(options: NodeOption): Promise { + const node = new Node(this, options); + + await node.connect(); + + this.nodes.set(node.name, node); + } + + /** + * Remove a Lavalink node from the pool of available nodes. + * + * @param name Name of the node. + * @param reason Reason of removing the node. + */ + public removeNode(name: string, reason = "Remove node executed"): void { + const node = this.nodes.get(name); + + if (!node) throw new Error("The node name you specified doesn't exist"); + + node.disconnect(1_000, reason); + } + + /** + * update an instance for voice connection (voice state, and voice server). + * + * @param packet Packet instance from Discord Gateway. + */ + // eslint-disable-next-line consistent-return, typescript/explicit-module-boundary-types + public updateInstance(packet: any): void { + const guildId = packet.d.guild_id; + const connection = this.connections.get(guildId); + const AllowedPackets = ["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"]; + + if (!connection || !AllowedPackets.includes(packet.t)) return undefined; + + if (packet.t === "VOICE_SERVER_UPDATE") { + // eslint-disable-next-line typescript/strict-boolean-expressions + if (!packet.d.endpoint) { + connection.emit("connectionUpdate", VoiceState.SessionEndpointMissing); + + return undefined; + } + if (connection.sessionId === null) { + connection.emit("connectionUpdate", VoiceState.SessionIdMissing); + + return undefined; + } + + connection.lastRegion = connection.region?.repeat(1) ?? null; + // eslint-disable-next-line typescript/no-unsafe-call + connection.region = packet.d.endpoint.split(".").shift()?.replace(/\d/gu, "") ?? null; + connection.serverUpdate = packet.d; + + if (connection.region !== null && connection.lastRegion !== connection.region) { + this.emit( + "debug", + `[VOICE => DISCORD] Voice region changed, old region: ${connection.lastRegion}, new region: ${connection.region}, guild: ${guildId}.` + ); + } + + connection.emit("connectionUpdate", VoiceState.SessionReady); + this.emit("debug", `[VOICE => DISCORD] Server update received, guild: ${guildId}.`); + + return undefined; + } + + const userId = packet.d.user_id; + + if (userId !== this.id) return undefined; + + connection.lastChannelId = connection.channelId?.repeat(1) ?? null; + connection.channelId = packet.d.channel_id; + connection.deafened = packet.d.self_deaf; + connection.muted = packet.d.self_mute; + connection.sessionId = packet.d.session_id ?? null; + + if (connection.channelId !== null && connection.lastChannelId !== connection.channelId) { + this.emit( + "debug", + `[VOICE => DISCORD] Channel moved, old channel: ${connection.lastChannelId}, new channel: ${connection.channelId}, guild: ${guildId}.` + ); + } + + if (connection.channelId === null) { + connection.state = State.Disconnected; + + this.emit("debug", `[VOICE => DISCORD] Channel disconnected, guild: ${guildId}.`); + + return undefined; + } + + this.emit( + "debug", + `[VOICE => DISCORD] State update received, session: ${connection.sessionId}, guild: ${guildId}.` + ); + } + + /** + * sendPacket is where your library send packets to Discord Gateway. + * + * @abstract + */ + // eslint-disable-next-line typescript/explicit-module-boundary-types + public abstract sendPacket(shardId: number, payload: any, important: boolean): void; +} + +// @ts-expect-error ignore this ts(2300) +// eslint-disable-next-line typescript/no-redeclare +export type Esbatu = EventEmitter & { + on: (( + event: "reconnecting", + listener: (name: string, reconnectsLeft: number, reconnectInterval: number) => void + ) => Esbatu) & + ((event: "close", listener: (name: string, code: number, reason: string) => void) => Esbatu) & + ((event: "debug", listener: (debug: string) => void) => Esbatu) & + ((event: "disconnect", listener: (name: string, count: number) => void) => Esbatu) & + ((event: "error", listener: (name: string, error: Error) => void) => Esbatu) & + ((event: "raw", listener: (name: string, data: unknown) => void) => Esbatu) & + ((event: "ready", listener: (name: string, reconnected: boolean) => void) => Esbatu); +}; diff --git a/src/Icelink.ts b/src/Icelink.ts deleted file mode 100644 index d9fc552..0000000 --- a/src/Icelink.ts +++ /dev/null @@ -1,257 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-declaration-merging */ -import { EventEmitter } from "node:events"; -import { Redis } from "ioredis"; -import { Node } from "./node/index"; -import { Player } from "./guild/Player"; -import { VoiceConnection } from "./guild/VoiceConnection"; -import { State, VoiceState } from "./Constants"; -import { Rest } from "./node/Rest"; -import { name as packageName, version as packageVersion } from "../package.json"; - -export interface VoiceChannelOptions { - /** A id of Guild in which the {@link channelId} of the voice channel is located. */ - guildId: string; - /** A id of Shard to track where this should send on sharded websockets, put 0 if you are unsharded. */ - shardId: number; - /** A id of the voice channel you want to connect to. */ - channelId: string; - /** Whether to deafen or undeafen the current bot user. */ - mute?: boolean; - /** Whether to mute or unmute the current bot user. */ - deaf?: boolean; -} - -export interface NodeOption { - /** Name of this node. */ - name: string; - /** A credentials to access the Lavalink. */ - authorization: string; - /** A URL of the Lavalink. */ - url: string; - /** Whether to use secure protocols or not. */ - secure?: boolean; -} - -export interface IcelinkOptions { - /** Whether to move players to a different Lavalink node when a node disconnect. */ - moveOnDisconnect?: boolean; - /** The {@link Node} options, for all the nodes. */ - nodes: NodeOption[]; - /** Timeout before trying to reconnect. */ - reconnectInterval?: number; - /** Number of times to try and reconnect to Lavalink before giving up. */ - reconnectTries?: number; - /** Whether to use redis cache system to save the node session and channel id from players, or not. */ - redis?: Redis; - /** Whether to resume a connection on disconnect from the Lavalink. (Server Side) */ - resume?: boolean; - /** Whether to resume the players by doing it in the library side. (Client Side) */ - resumeByLibrary?: boolean; - /** Time to wait before lavalink starts to destroy the players of the disconnected client. */ - resumeTimeout?: number; - /** Time to wait for a response from the Lavalink REST API before giving up. */ - restTimeout?: number; - /** Custom or extend the structures for icelink to use. */ - structures?: Structures; - /** User Agent to use when making requests to Lavalink. */ - userAgent?: string; - /** Timeout before abort the voice connection. */ - voiceConnectionTimeout?: number; -} - -type Constructor = new (...args: any[]) => T; - -export interface Structures { - /** A custom structure that extends the {@link Rest} class. */ - rest?: Constructor; - /** A custom structure that extends the {@link Player} class. */ - player?: Constructor; -} - -export interface Icelink extends EventEmitter { - on: (( - event: "reconnecting", - listener: (name: string, reconnectsLeft: number, reconnectInterval: number) => void - ) => this) & - ((event: "close", listener: (name: string, code: number, reason: string) => void) => this) & - ((event: "debug", listener: (debug: string) => void) => this) & - ((event: "disconnect", listener: (name: string, count: number) => void) => this) & - ((event: "error", listener: (name: string, error: Error) => void) => this) & - ((event: "raw", listener: (name: string, data: unknown) => void) => this) & - ((event: "ready", listener: (name: string, reconnected: boolean) => void) => this); -} - -/** Main Icelink class. */ -export abstract class Icelink extends EventEmitter { - /** - * A Icelink options. - * @readonly - */ - public readonly options: Required>; - /** - * Connected Lavalink nodes. - * @readonly - */ - public readonly nodes = new Map(); - /** - * Voice connections being handled. - * @readonly - */ - public readonly connections = new Map(); - /** - * Players being handled. - * @readonly - */ - public readonly players = new Map(); - /** - * redis cache being handle for save node session and players. - * @readonly - */ - public readonly redis: Redis | null = null; - /** Icelink instance identifier. */ - public id: string | null = null; - - /** - * Creates a new Icelink. - * @param options An options to pass to create this Icelink instance. - */ - public constructor(options: IcelinkOptions) { - super(); - - this.options = { - moveOnDisconnect: options.moveOnDisconnect ?? false, - nodes: options.nodes, - reconnectInterval: options.reconnectInterval ?? 5, - reconnectTries: options.reconnectTries ?? 3, - resume: options.resume ?? false, - resumeByLibrary: options.resumeByLibrary ?? false, - resumeTimeout: options.resumeTimeout ?? 30, - restTimeout: options.restTimeout ?? 60, - structures: options.structures ?? {}, - userAgent: options.userAgent ?? `${packageName}/${packageVersion}`, - voiceConnectionTimeout: options.voiceConnectionTimeout ?? 15 - }; - this.redis = options.redis ?? null; - - Object.defineProperties(this, { - options: { enumerable: false, writable: false }, - nodes: { enumerable: true, writable: false }, - connections: { enumerable: true, writable: false }, - players: { enumerable: true, writable: false }, - redis: { enumerable: false, writable: false }, - id: { enumerable: false, writable: true } - }); - } - - /** - * A ideal Lavalink node if available connected. - * @readonly - */ - public get idealNode(): Node | undefined { - return [...this.nodes.values()] - .filter(node => node.state === State.Connected) - .sort((a, b) => a.penalties - b.penalties) - .shift(); - } - - /** - * Add a Lavalink node to the pool of available nodes. - * @param options A node options for instance. - */ - public async addNode(options: NodeOption): Promise { - const node = new Node(this, options); - - await node.connect(); - - this.nodes.set(node.name, node); - } - - /** - * Remove a Lavalink node from the pool of available nodes. - * @param name Name of the node. - * @param reason Reason of removing the node. - */ - public removeNode(name: string, reason = "Remove node executed"): void { - const node = this.nodes.get(name); - - if (!node) throw new Error("The node name you specified doesn't exist"); - - node.disconnect(1000, reason); - } - - /** - * update an instance for voice connection (voice state, and voice server). - * @param packet Packet instance from Discord Gateway. - */ - public updateInstance(packet: any): void { - const guildId = packet.d.guild_id; - const connection = this.connections.get(guildId); - const AllowedPackets = ["VOICE_STATE_UPDATE", "VOICE_SERVER_UPDATE"]; - - if (!connection || !AllowedPackets.includes(packet.t)) return undefined; - - if (packet.t === "VOICE_SERVER_UPDATE") { - if (!packet.d.endpoint) { - connection.emit("connectionUpdate", VoiceState.SessionEndpointMissing); - - return undefined; - } - if (!connection.sessionId) { - connection.emit("connectionUpdate", VoiceState.SessionIdMissing); - - return undefined; - } - - connection.lastRegion = connection.region?.repeat(1) ?? null; - // eslint-disable-next-line @typescript-eslint/no-unsafe-call - connection.region = packet.d.endpoint.split(".").shift()?.replace(/[0-9]/g, "") ?? null; - connection.serverUpdate = packet.d; - - if (connection.region && connection.lastRegion !== connection.region) - this.emit( - "debug", - `[VOICE => DISCORD] Voice region changed, old region: ${connection.lastRegion}, new region: ${connection.region}, guild: ${guildId}.` - ); - - connection.emit("connectionUpdate", VoiceState.SessionReady); - this.emit("debug", `[VOICE => DISCORD] Server update received, guild: ${guildId}.`); - - return undefined; - } - - const userId = packet.d.user_id; - - if (userId !== this.id) return undefined; - - connection.lastChannelId = connection.channelId?.repeat(1) ?? null; - connection.channelId = packet.d.channel_id; - connection.deafened = packet.d.self_deaf; - connection.muted = packet.d.self_mute; - connection.sessionId = packet.d.session_id ?? null; - - if (connection.channelId && connection.lastChannelId !== connection.channelId) - this.emit( - "debug", - `[VOICE => DISCORD] Channel moved, old channel: ${connection.lastChannelId}, new channel: ${connection.channelId}, guild: ${guildId}.` - ); - - if (!connection.channelId) { - connection.state = State.Disconnected; - - this.emit("debug", `[VOICE => DISCORD] Channel disconnected, guild: ${guildId}.`); - - return undefined; - } - - this.emit( - "debug", - `[VOICE => DISCORD] State update received, session: ${connection.sessionId}, guild: ${guildId}.` - ); - } - - /** - * sendPacket is where your library send packets to Discord Gateway. - * @abstract - */ - public abstract sendPacket(shardId: number, payload: any, important: boolean): void; -} diff --git a/src/guild/Player.ts b/src/guild/Player.ts index 1fd7431..1652598 100644 --- a/src/guild/Player.ts +++ b/src/guild/Player.ts @@ -1,588 +1,657 @@ -/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging, max-lines */ +/* eslint-disable jsdoc/check-param-names, stylistic/max-len, tsdoc/syntax */ import { EventEmitter } from "node:events"; -import { Node } from "../node/index"; -import { VoiceConnection } from "./VoiceConnection"; -import { OpCodes, RedisKey, State } from "../Constants"; -import { Exception, Track } from "../node/Rest"; -import { VoiceChannelOptions } from "../Icelink"; +import type { OpCodes } from "../Constants"; +import { RedisKey, State } from "../Constants"; +import type { VoiceChannelOptions } from "../Esbatu"; +import type { Exception, Track } from "../node/Rest"; +import type { Node } from "../node/index"; +import type { VoiceConnection } from "./VoiceConnection"; export type TrackEndReason = "cleanup" | "finished" | "loadFailed" | "replaced" | "stopped"; export type PlayerEventType = - | "TrackEndEvent" - | "TrackExceptionEvent" - | "TrackStartEvent" - | "TrackStuckEvent" - | "WebSocketClosedEvent"; - -export interface PlayOptions { - track: string; - options?: { - noReplace?: boolean; - pause?: boolean; - startTime?: number; - endTime?: number; - }; -} - -export interface Band { - band: number; - gain: number; -} - -export interface KaraokeSettings { - level?: number; - monoLevel?: number; - filterBand?: number; - filterWidth?: number; -} - -export interface TimescaleSettings { - speed?: number; - pitch?: number; - rate?: number; -} - -export interface FreqSettings { - frequency?: number; - depth?: number; -} - -export interface RotationSettings { - rotationHz?: number; -} - -export interface DistortionSettings { - sinOffset?: number; - sinScale?: number; - cosOffset?: number; - cosScale?: number; - tanOffset?: number; - tanScale?: number; - offset?: number; - scale?: number; -} - -export interface ChannelMixSettings { - leftToLeft?: number; - leftToRight?: number; - rightToLeft?: number; - rightToRight?: number; -} - -export interface LowPassSettings { - smoothing?: number; -} - -export interface PlayerEvent { - op: OpCodes.Event; - type: PlayerEventType; - guildId: string; -} - -export interface TrackStartEvent extends PlayerEvent { - type: "TrackStartEvent"; - track: Track; -} - -export interface TrackEndEvent extends PlayerEvent { - type: "TrackEndEvent"; - track: Track | null; - reason: TrackEndReason; -} - -export interface TrackStuckEvent extends PlayerEvent { - type: "TrackStuckEvent"; - track: Track; - thresholdMs: number; -} - -export interface TrackExceptionEvent extends PlayerEvent { - type: "TrackExceptionEvent"; - exception: Exception; -} - -export interface WebSocketClosedEvent extends PlayerEvent { - type: "WebSocketClosedEvent"; - code: number; - reason: string; - byRemote: boolean; -} - -export interface PlayerUpdate { - op: OpCodes.PlayerUpdate; - state: { - time: number; - position: number; - connected: boolean; - ping: number; - }; -} - -export interface FilterOptions { - volume?: number; - equalizer?: Band[]; - karaoke?: KaraokeSettings | null; - timescale?: TimescaleSettings | null; - tremolo?: FreqSettings | null; - vibrato?: FreqSettings | null; - rotation?: RotationSettings | null; - distortion?: DistortionSettings | null; - channelMix?: ChannelMixSettings | null; - lowPass?: LowPassSettings | null; -} - -export declare interface Player { - on: ((event: "closed", listener: (reason: WebSocketClosedEvent) => void) => this) & - ((event: "end", listener: (reason: TrackEndEvent) => void) => this) & - ((event: "exception", listener: (reason: TrackExceptionEvent) => void) => this) & - ((event: "resumed", listener: (player: Player) => void) => this) & - ((event: "start", listener: (data: TrackStartEvent) => void) => this) & - ((event: "stuck", listener: (data: TrackStuckEvent) => void) => this) & - ((event: "update", listener: (data: PlayerUpdate) => void) => this); -} - -/** Wrapper object around Lavalink. */ + | "TrackEndEvent" + | "TrackExceptionEvent" + | "TrackStartEvent" + | "TrackStuckEvent" + | "WebSocketClosedEvent"; + +export type PlayOptions = { + track: string; + options?: { + noReplace?: boolean; + pause?: boolean; + startTime?: number; + endTime?: number; + }; +}; + +export type Band = { + band: number; + gain: number; +}; + +export type KaraokeSettings = { + level?: number; + monoLevel?: number; + filterBand?: number; + filterWidth?: number; +}; + +export type TimescaleSettings = { + speed?: number; + pitch?: number; + rate?: number; +}; + +export type FreqSettings = { + frequency?: number; + depth?: number; +}; + +export type RotationSettings = { + rotationHz?: number; +}; + +export type DistortionSettings = { + sinOffset?: number; + sinScale?: number; + cosOffset?: number; + cosScale?: number; + tanOffset?: number; + tanScale?: number; + offset?: number; + scale?: number; +}; + +export type ChannelMixSettings = { + leftToLeft?: number; + leftToRight?: number; + rightToLeft?: number; + rightToRight?: number; +}; + +export type LowPassSettings = { + smoothing?: number; +}; + +export type PlayerEvent = { + op: OpCodes.Event; + type: PlayerEventType; + guildId: string; +}; + +export type TrackStartEvent = PlayerEvent & { + type: "TrackStartEvent"; + track: Track; +}; + +export type TrackEndEvent = PlayerEvent & { + type: "TrackEndEvent"; + track: Track | null; + reason: TrackEndReason; +}; + +export type TrackStuckEvent = PlayerEvent & { + type: "TrackStuckEvent"; + track: Track; + thresholdMs: number; +}; + +export type TrackExceptionEvent = PlayerEvent & { + type: "TrackExceptionEvent"; + exception: Exception; +}; + +export type WebSocketClosedEvent = PlayerEvent & { + type: "WebSocketClosedEvent"; + code: number; + reason: string; + byRemote: boolean; +}; + +export type PlayerUpdate = { + op: OpCodes.PlayerUpdate; + state: { + time: number; + position: number; + connected: boolean; + ping: number; + }; +}; + +export type FilterOptions = { + volume?: number; + equalizer?: Band[]; + karaoke?: KaraokeSettings | null; + timescale?: TimescaleSettings | null; + tremolo?: FreqSettings | null; + vibrato?: FreqSettings | null; + rotation?: RotationSettings | null; + distortion?: DistortionSettings | null; + channelMix?: ChannelMixSettings | null; + lowPass?: LowPassSettings | null; +}; + +/** + * Wrapper object around Lavalink. + */ +// @ts-expect-error ignore this ts(2300) export class Player extends EventEmitter { - /** - * A Guild id on this player. - * @readonly - */ - public readonly guildId; - /** Lavalink node this player is connected to. */ - public node; - /** A identifier of the currently playing track. */ - public trackIdentifier: string | null = null; - /** Global volume of the player. */ - public volume = 100; - /** Pause status in current player. */ - public paused = false; - /** Ping represents the number of milliseconds between heartbeat and ack. Could be `-1` if not connected. */ - public ping = 0; - /** Position in ms of current playing the track. */ - public position = 0; - /** An filters of the player. */ - public filters: FilterOptions = {}; - /** Whether Lavalink is connected to the voice gateway. */ - public connected = false; - /** - * A encoded of the currently playing track. - * @private - * @internal - */ - private _encodedTrack: string | null = null; - private _prepareMove = false; - - /** - * Creates a new Player instance on {@link Node}. - * @param guildId An instance of guildId - * @param node An instance of {@link Node}. (Lavalink API wrapper) - */ - public constructor(guildId: string, node: Node) { - super(); - - this.guildId = guildId; - this.node = node; - - Object.defineProperties(this, { - guildId: { enumerable: true, writable: false }, - _encodedTrack: { enumerable: false, writable: true }, - _prepareMove: { enumerable: false, writable: true } - }); - } - - /** - * A voice connection on this player state. - * @readonly - */ - public get connection(): VoiceConnection { - return this.node.manager.connections.get(this.guildId)!; - } - - /** - * Move player to another node - * @param name Name of node to move to, or the default ideal node - * @returns true if the player was moved, false if not - */ - public async movePlayer(name?: string): Promise { - const idealExcludeCurrentNode = (): Node | undefined => - [...this.node.manager.nodes.values()] - .filter(node => node.name !== this.node.name && node.state === State.Connected) - .sort((a, b) => a.penalties - b.penalties) - .shift(); - const node = this.node.manager.nodes.get(name!) ?? idealExcludeCurrentNode(); - - if (!node || node.name === this.node.name) return false; - if (node.state !== State.Connected) throw new Error("No available nodes to move to"); - - let lastNode = this.node.manager.nodes.get(this.node.name); - - if (!lastNode || lastNode.state !== State.Connected) lastNode = idealExcludeCurrentNode(); - - const ICurrentDataCache = await this.node.manager.redis?.get(RedisKey.NodePlayers(this.node.name.toLowerCase())); - const currentDataCache = ICurrentDataCache ? (JSON.parse(ICurrentDataCache) as VoiceChannelOptions[]) : []; - - currentDataCache.splice( - currentDataCache.indexOf(currentDataCache.find(({ guildId: id }) => id === this.guildId)!), - 1 - ); - - this._prepareMove = true; - - await this.node.manager.redis?.set( - RedisKey.NodePlayers(this.node.name.toLowerCase()), - JSON.stringify(currentDataCache) - ); - if (this.node.state === State.Connected) await this.destroyPlayer(); - - try { - this.node = node; - - const IDataCache = await this.node.manager.redis?.get(RedisKey.NodePlayers(this.node.name.toLowerCase())); - const dataCache = IDataCache ? (JSON.parse(IDataCache) as VoiceChannelOptions[]) : []; - - dataCache.push({ - guildId: this.guildId, - channelId: this.connection.channelId!, - shardId: this.connection.shardId, - deaf: this.connection.deafened, - mute: this.connection.muted - }); - - await this.resumePlayer(); - await this.node.manager.redis?.set(RedisKey.NodePlayers(this.node.name.toLowerCase()), JSON.stringify(dataCache)); - - this._prepareMove = false; - - return true; - } catch { - this.node = lastNode!; - - const IDataCache = await this.node.manager.redis?.get(RedisKey.NodePlayers(this.node.name.toLowerCase())); - const dataCache = IDataCache ? (JSON.parse(IDataCache) as VoiceChannelOptions[]) : []; - - dataCache.push({ - guildId: this.guildId, - channelId: this.connection.channelId!, - shardId: this.connection.shardId, - deaf: this.connection.deafened, - mute: this.connection.muted - }); - - await this.resumePlayer(); - await this.node.manager.redis?.set(RedisKey.NodePlayers(this.node.name.toLowerCase()), JSON.stringify(dataCache)); - - this._prepareMove = false; - - return false; - } - } - - /** Destroys the player in remote lavalink side. */ - public destroyPlayer(): Promise { - return this.node.rest.destroyPlayer(this.guildId); - } - - /** - * Play a new track. - * @param playable Options for playing this track. - */ - public async playTrack(playable: PlayOptions): Promise { - const player = await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { - track: { encoded: playable.track }, - paused: playable.options?.pause, - position: playable.options?.startTime, - endTime: playable.options?.endTime - }, - noReplace: playable.options?.noReplace - }); - - this.trackIdentifier = player.track?.info.identifier ?? null; - this.paused = player.paused; - this.position = player.state.position; - this._encodedTrack = player.track?.encoded ?? null; - } - - /** Stop the currently playing track. */ - public async stopTrack(): Promise { - this.position = 0; - this._encodedTrack = null; - - await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { track: { encoded: null } } - }); - } - - /** - * Pause or unpause the currently playing track. - * @param paused Boolean value to specify whether to pause or unpause the current bot user. - */ - public async setPaused(paused = true): Promise { - const player = await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { paused } - }); - - this.paused = player.paused; - } - - /** - * Seek to a specific time in the currently playing track. - * @param position Position to seek to in milliseconds. - */ - public async seekTo(position: number): Promise { - const player = await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { position } - }); - - this.position = player.state.position; - } - - /** - * Sets the global volume of the player. - * @param volume Target volume 0-1000. - */ - public async setGlobalVolume(volume: number): Promise { - const player = await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { volume }, - noReplace: true - }); - - this.volume = player.volume; - } - - /** - * Sets the filter volume of the player. - * @param volume Target volume 0.0-5.0. - */ - public setFilterVolume(volume: number): Promise { - return this.setFilters({ volume }); - } - - /** - * Change the equalizer settings applied to to the Player State. - * @param equalizer An array of objects that conforms to the Bands type that define volumes at different frequencies. - */ - public setEqualizer(equalizer: Band[]): Promise { - return this.setFilters({ equalizer }); - } - - /** - * Change the karaoke settings applied to to the Player State. - * @param karaoke An object that conforms to the KaraokeSettings type that defines a range of frequencies to mute. - */ - public setKaraoke(karaoke: KaraokeSettings): Promise { - return this.setFilters({ karaoke }); - } - - /** - * Change the timescale settings applied to to the Player State. - * @param timescale An object that conforms to the TimescaleSettings type that defines the time signature to play the audio at. - */ - public setTimescale(timescale: TimescaleSettings): Promise { - return this.setFilters({ timescale }); - } - - /** - * Change the tremolo settings applied to to the Player State. - * @param tremolo An object that conforms to the FreqSettings type that defines an oscillation in volume. - */ - public setTremolo(tremolo: FreqSettings): Promise { - return this.setFilters({ tremolo }); - } - - /** - * Change the vibrato settings applied to to the Player State. - * @param vibrato An object that conforms to the FreqSettings type that defines an oscillation in pitch. - */ - public setVibrato(vibrato: FreqSettings): Promise { - return this.setFilters({ vibrato }); - } - - /** - * Change the rotation settings applied to the Player State. - * @param rotation An object that conforms to the RotationSettings type that defines the frequency of audio rotating round the listener. - */ - public setRotation(rotation: RotationSettings): Promise { - return this.setFilters({ rotation }); - } - - /** - * Change the distortion settings applied to the Player State. - * @param distortion An object that conforms to DistortionSettings that defines distortions in the audio. - */ - public setDistortion(distortion: DistortionSettings): Promise { - return this.setFilters({ distortion }); - } - - /** - * Change the channel mix settings applied to the Player State. - * @param channelMix An object that conforms to ChannelMixSettings that defines how much the left and right channels affect each other. (setting all factors to 0.5 causes both channels to get the same audio) - */ - public setChannelMix(channelMix: ChannelMixSettings): Promise { - return this.setFilters({ channelMix }); - } - - /** - * Change the low pass settings applied to the Player State. - * @param lowPass An object that conforms to LowPassSettings that defines the amount of suppression on higher frequencies. - */ - public setLowPass(lowPass: LowPassSettings): Promise { - return this.setFilters({ lowPass }); - } - - /** - * Change the all filter settings applied to the Player State. - * @param filters An object that conforms to FilterOptions that defines all filters to apply/modify. - */ - public async setFilters(filters: FilterOptions): Promise { - const player = await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { filters }, - noReplace: true - }); - - this.filters = player.filters; - } - - /** Clear all filters applied to the Player State. */ - public clearFilters(): Promise { - return this.setFilters({ - volume: 1, - equalizer: [], - karaoke: null, - timescale: null, - tremolo: null, - vibrato: null, - rotation: null, - distortion: null, - channelMix: null, - lowPass: null - }); - } - - /** - * Resumes the current track after lavalink is disconnect. - * @internal - */ - public async resumePlayer(): Promise { - const { state } = await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { - track: { encoded: this._encodedTrack }, - position: this.position, - volume: this.volume, - paused: this.paused, - filters: this.filters, - voice: { - token: this.connection.serverUpdate!.token, - endpoint: this.connection.serverUpdate!.endpoint, - sessionId: this.connection.sessionId! - } - } - }); - - if (!state.connected) this.connection.sendVoiceUpdate(); - } - - /** - * Cleans this player instance. - * @internal - */ - public clean(): void { - this.trackIdentifier = null; - this.volume = 100; - this.position = 0; - this.filters = {}; - this._encodedTrack = null; - - this.removeAllListeners(); - } - - /** - * Sends server update to lavalink, or resume the current track by node session. - * @internal - */ - public async sendServerUpdate(connection: VoiceConnection): Promise { - const player = await this.node.rest.updatePlayer({ - guildId: this.guildId, - playerOptions: { - voice: { - token: connection.serverUpdate!.token, - endpoint: connection.serverUpdate!.endpoint, - sessionId: connection.sessionId! - } - }, - noReplace: true - }); - - this.trackIdentifier = player.track?.info.identifier ?? null; - this.position = player.state.position; - this.ping = player.state.ping; - this.volume = player.volume; - this.paused = player.paused; - this.filters = player.filters; - this.connected = player.state.connected; - this._encodedTrack = player.track?.encoded ?? null; - } - - /** - * Handle player update data from Lavalink Websocket. - * @internal - */ - public onPlayerUpdate(data: { state: { position: number; ping: number; connected: boolean } }): void { - if (this._prepareMove) return undefined; - - const { position, ping, connected } = data.state; - - this.position = position; - this.ping = ping; - this.connected = connected; - - this.emit("update", data); - } - - /** - * Handle player events received from Lavalink Websocket. - * @param data JSON data from Lavalink. - * @internal - */ - public onPlayerEvent(data: { type: string; track: Track }): void { - if (this._prepareMove) return undefined; - - switch (data.type) { - case "TrackStartEvent": - this.trackIdentifier = data.track.info.identifier; - this._encodedTrack = data.track.encoded; - - this.emit("start", data); - - break; - case "TrackEndEvent": - this.emit("end", data); - - break; - case "TrackStuckEvent": - this.emit("stuck", data); - - break; - case "TrackExceptionEvent": - this.emit("exception", data); - - break; - case "WebSocketClosedEvent": - this.emit("closed", data); - - break; - default: - this.node.manager.emit( - "debug", - `[PLAYER => ${this.node.name}] Unknown player message, type: ${data.type}, guild: ${this.guildId}.` - ); - } - } + /** + * A Guild id on this player. + * + * @readonly + */ + public readonly guildId; + /** + * Lavalink node this player is connected to. + */ + public node; + /** + * A identifier of the currently playing track. + */ + public trackIdentifier: string | null = null; + /** + * Global volume of the player. + */ + public volume = 100; + /** + * Pause status in current player. + */ + public paused = false; + /** + * Ping represents the number of milliseconds between heartbeat and ack. Could be `-1` if not connected. + */ + public ping = 0; + /** + * Position in ms of current playing the track. + */ + public position = 0; + /** + * An filters of the player. + */ + public filters: FilterOptions = {}; + /** + * Whether Lavalink is connected to the voice gateway. + */ + public connected = false; + /** + * A encoded of the currently playing track. + * + * @private + * @internal + */ + private _encodedTrack: string | null = null; + private _prepareMove = false; + + /** + * Creates a new Player instance on {@link Node}. + * + * @param guildId An instance of guildId + * @param node An instance of {@link Node}. (Lavalink API wrapper) + */ + public constructor(guildId: string, node: Node) { + super(); + + this.guildId = guildId; + this.node = node; + + Object.defineProperties(this, { + guildId: { enumerable: true, writable: false }, + _encodedTrack: { enumerable: false, writable: true }, + _prepareMove: { enumerable: false, writable: true } + }); + } + + /** + * A voice connection on this player state. + * + * @readonly + */ + public get connection(): VoiceConnection { + // eslint-disable-next-line typescript/no-non-null-assertion + return this.node.manager.connections.get(this.guildId)!; + } + + /** + * Move player to another node + * + * @param name Name of node to move to, or the default ideal node + * @returns true if the player was moved, false if not + */ + public async movePlayer(name?: string): Promise { + const idealExcludeCurrentNode = (): Node | undefined => [...this.node.manager.nodes.values()] + .filter(node0 => node0.name !== this.node.name && node0.state === State.Connected) + .sort((a, b) => a.penalties - b.penalties) + .shift(); + // eslint-disable-next-line typescript/no-non-null-assertion + const node = this.node.manager.nodes.get(name!) ?? idealExcludeCurrentNode(); + + if (!node || node.name === this.node.name) return false; + if (node.state !== State.Connected) throw new Error("No available nodes to move to"); + + let lastNode = this.node.manager.nodes.get(this.node.name); + + if (!lastNode || lastNode.state !== State.Connected) lastNode = idealExcludeCurrentNode(); + + const ICurrentDataCache = await this.node.manager.redis?.get( + RedisKey.NodePlayers(this.node.name.toLowerCase()) + ); + const currentDataCache = ICurrentDataCache === null ? [] : (JSON.parse(ICurrentDataCache ?? "") as VoiceChannelOptions[]); + + currentDataCache.splice( + // eslint-disable-next-line typescript/no-non-null-assertion + currentDataCache.indexOf(currentDataCache.find(({ guildId: id }) => id === this.guildId)!), + 1 + ); + + this._prepareMove = true; + + await this.node.manager.redis?.set( + RedisKey.NodePlayers(this.node.name.toLowerCase()), + JSON.stringify(currentDataCache) + ); + if (this.node.state === State.Connected) await this.destroyPlayer(); + + try { + this.node = node; + + const IDataCache = await this.node.manager.redis?.get(RedisKey.NodePlayers(this.node.name.toLowerCase())); + const dataCache = IDataCache === null ? [] : (JSON.parse(IDataCache ?? "") as VoiceChannelOptions[]); + + dataCache.push({ + guildId: this.guildId, + // eslint-disable-next-line typescript/no-non-null-assertion + channelId: this.connection.channelId!, + shardId: this.connection.shardId, + deaf: this.connection.deafened, + mute: this.connection.muted + }); + + await this.resumePlayer(); + await this.node.manager.redis?.set( + RedisKey.NodePlayers(this.node.name.toLowerCase()), + JSON.stringify(dataCache) + ); + + this._prepareMove = false; + + return true; + } catch { + // eslint-disable-next-line typescript/no-non-null-assertion + this.node = lastNode!; + + const IDataCache = await this.node.manager.redis?.get(RedisKey.NodePlayers(this.node.name.toLowerCase())); + const dataCache = IDataCache === null ? [] : (JSON.parse(IDataCache ?? "") as VoiceChannelOptions[]); + + dataCache.push({ + guildId: this.guildId, + // eslint-disable-next-line typescript/no-non-null-assertion + channelId: this.connection.channelId!, + shardId: this.connection.shardId, + deaf: this.connection.deafened, + mute: this.connection.muted + }); + + await this.resumePlayer(); + await this.node.manager.redis?.set( + RedisKey.NodePlayers(this.node.name.toLowerCase()), + JSON.stringify(dataCache) + ); + + this._prepareMove = false; + + return false; + } + } + + /** + * Destroys the player in remote lavalink side. + */ + public async destroyPlayer(): Promise { + return this.node.rest.destroyPlayer(this.guildId); + } + + /** + * Play a new track. + * + * @param playable Options for playing this track. + */ + public async playTrack(playable: PlayOptions): Promise { + const player = await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { + track: { encoded: playable.track }, + paused: playable.options?.pause, + position: playable.options?.startTime, + endTime: playable.options?.endTime + }, + noReplace: playable.options?.noReplace + }); + + this.trackIdentifier = player.track?.info.identifier ?? null; + this.paused = player.paused; + this.position = player.state.position; + this._encodedTrack = player.track?.encoded ?? null; + } + + /** + * Stop the currently playing track. + */ + public async stopTrack(): Promise { + this.position = 0; + this._encodedTrack = null; + + await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { track: { encoded: null } } + }); + } + + /** + * Pause or unpause the currently playing track. + * + * @param paused Boolean value to specify whether to pause or unpause the current bot user. + */ + public async setPaused(paused = true): Promise { + const player = await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { paused } + }); + + this.paused = player.paused; + } + + /** + * Seek to a specific time in the currently playing track. + * + * @param position Position to seek to in milliseconds. + */ + public async seekTo(position: number): Promise { + const player = await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { position } + }); + + this.position = player.state.position; + } + + /** + * Sets the global volume of the player. + * + * @param volume Target volume 0-1000. + */ + public async setGlobalVolume(volume: number): Promise { + const player = await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { volume }, + noReplace: true + }); + + this.volume = player.volume; + } + + /** + * Sets the filter volume of the player. + * + * @param volume Target volume 0.0-5.0. + */ + public async setFilterVolume(volume: number): Promise { + return this.setFilters({ volume }); + } + + /** + * Change the equalizer settings applied to to the Player State. + * + * @param equalizer An array of objects that conforms to the Bands type that define volumes at different frequencies. + */ + public async setEqualizer(equalizer: Band[]): Promise { + return this.setFilters({ equalizer }); + } + + /** + * Change the karaoke settings applied to to the Player State. + * + * @param karaoke An object that conforms to the KaraokeSettings type that defines a range of frequencies to mute. + */ + public async setKaraoke(karaoke: KaraokeSettings): Promise { + return this.setFilters({ karaoke }); + } + + /** + * Change the timescale settings applied to to the Player State. + * + * @param timescale An object that conforms to the TimescaleSettings type that defines the time signature to play the audio at. + */ + public async setTimescale(timescale: TimescaleSettings): Promise { + return this.setFilters({ timescale }); + } + + /** + * Change the tremolo settings applied to to the Player State. + * + * @param tremolo An object that conforms to the FreqSettings type that defines an oscillation in volume. + */ + public async setTremolo(tremolo: FreqSettings): Promise { + return this.setFilters({ tremolo }); + } + + /** + * Change the vibrato settings applied to to the Player State. + * + * @param vibrato An object that conforms to the FreqSettings type that defines an oscillation in pitch. + */ + public async setVibrato(vibrato: FreqSettings): Promise { + return this.setFilters({ vibrato }); + } + + /** + * Change the rotation settings applied to the Player State. + * + * @param rotation An object that conforms to the RotationSettings type that defines the frequency of audio rotating round the listener. + */ + public async setRotation(rotation: RotationSettings): Promise { + return this.setFilters({ rotation }); + } + + /** + * Change the distortion settings applied to the Player State. + * + * @param distortion An object that conforms to DistortionSettings that defines distortions in the audio. + */ + public async setDistortion(distortion: DistortionSettings): Promise { + return this.setFilters({ distortion }); + } + + /** + * Change the channel mix settings applied to the Player State. + * + * @param channelMix An object that conforms to ChannelMixSettings that defines how much the left and right channels affect each other. (setting all factors to 0.5 causes both channels to get the same audio) + */ + public async setChannelMix(channelMix: ChannelMixSettings): Promise { + return this.setFilters({ channelMix }); + } + + /** + * Change the low pass settings applied to the Player State. + * + * @param lowPass An object that conforms to LowPassSettings that defines the amount of suppression on higher frequencies. + */ + public async setLowPass(lowPass: LowPassSettings): Promise { + return this.setFilters({ lowPass }); + } + + /** + * Change the all filter settings applied to the Player State. + * + * @param filters An object that conforms to FilterOptions that defines all filters to apply/modify. + */ + public async setFilters(filters: FilterOptions): Promise { + const player = await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { filters }, + noReplace: true + }); + + this.filters = player.filters; + } + + /** + * Clear all filters applied to the Player State. + */ + public async clearFilters(): Promise { + return this.setFilters({ + volume: 1, + equalizer: [], + karaoke: null, + timescale: null, + tremolo: null, + vibrato: null, + rotation: null, + distortion: null, + channelMix: null, + lowPass: null + }); + } + + /** + * Resumes the current track after lavalink is disconnect. + * + * @internal + */ + public async resumePlayer(): Promise { + const { state } = await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { + track: { encoded: this._encodedTrack }, + position: this.position, + paused: this.paused, + filters: this.filters, + voice: { + token: this.connection.serverUpdate?.token ?? "", + endpoint: this.connection.serverUpdate?.endpoint ?? "", + sessionId: this.connection.sessionId ?? "" + } + } + }); + + if (!state.connected) this.connection.sendVoiceUpdate(); + } + + /** + * Cleans this player instance. + * + * @internal + */ + public clean(): void { + this.trackIdentifier = null; + this.volume = 100; + this.position = 0; + this.filters = {}; + this._encodedTrack = null; + + this.removeAllListeners(); + } + + /** + * Sends server update to lavalink, or resume the current track by node session. + * + * @internal + */ + public async sendServerUpdate(connection: VoiceConnection): Promise { + const player = await this.node.rest.updatePlayer({ + guildId: this.guildId, + playerOptions: { + voice: { + token: connection.serverUpdate?.token ?? "", + endpoint: connection.serverUpdate?.endpoint ?? "", + sessionId: connection.sessionId ?? "" + } + }, + noReplace: true + }); + + this.trackIdentifier = player.track?.info.identifier ?? null; + this.position = player.state.position; + this.ping = player.state.ping; + this.volume = player.volume; + this.paused = player.paused; + this.filters = player.filters; + this.connected = player.state.connected; + this._encodedTrack = player.track?.encoded ?? null; + } + + /** + * Handle player update data from Lavalink Websocket. + * + * @internal + */ + public onPlayerUpdate(data: { state: { position: number; ping: number; connected: boolean; }; }): void { + if (this._prepareMove) return undefined; + + const { position, ping, connected } = data.state; + + this.position = position; + this.ping = ping; + this.connected = connected; + + this.emit("update", data); + + return undefined; + } + + /** + * Handle player events received from Lavalink Websocket. + * + * @param data JSON data from Lavalink. + * @internal + */ + public onPlayerEvent(data: { type: string; track: Track; }): void { + if (this._prepareMove) return undefined; + + switch (data.type) { + case "TrackStartEvent": + this.trackIdentifier = data.track.info.identifier; + this._encodedTrack = data.track.encoded; + + this.emit("start", data); + + break; + case "TrackEndEvent": + this.emit("end", data); + + break; + case "TrackStuckEvent": + this.emit("stuck", data); + + break; + case "TrackExceptionEvent": + this.emit("exception", data); + + break; + case "WebSocketClosedEvent": + this.emit("closed", data); + + break; + default: + this.node.manager.emit( + "debug", + `[PLAYER => ${this.node.name}] Unknown player message, type: ${data.type}, guild: ${this.guildId}.` + ); + } + + return undefined; + } } + +// @ts-expect-error ignore this ts(2300) +// eslint-disable-next-line typescript/no-redeclare +export declare type Player = { + on: ((event: "closed", listener: (reason: WebSocketClosedEvent) => void) => Player) & + ((event: "end", listener: (reason: TrackEndEvent) => void) => Player) & + ((event: "exception", listener: (reason: TrackExceptionEvent) => void) => Player) & + ((event: "resumed", listener: (player: Player) => void) => Player) & + ((event: "start", listener: (data: TrackStartEvent) => void) => Player) & + ((event: "stuck", listener: (data: TrackStuckEvent) => void) => Player) & + ((event: "update", listener: (data: PlayerUpdate) => void) => Player); +}; diff --git a/src/guild/VoiceConnection.ts b/src/guild/VoiceConnection.ts index 6f35ca9..02101b4 100644 --- a/src/guild/VoiceConnection.ts +++ b/src/guild/VoiceConnection.ts @@ -1,166 +1,209 @@ -import { EventEmitter, once } from "events"; +/* eslint-disable tsdoc/syntax, id-length */ +import { EventEmitter, once } from "node:events"; +import { setTimeout, clearTimeout } from "node:timers"; import { State, VoiceState } from "../Constants"; -import { Icelink, VoiceChannelOptions } from "../Icelink"; - -export interface StateUpdatePartial { - session_id?: string; - channel_id: string | null; - self_deaf: boolean; - self_mute: boolean; -} - -export interface ServerUpdate { - token: string; - endpoint: string; -} - -/** Represents a connection to a Discord voice channel. */ +import type { Esbatu, VoiceChannelOptions } from "../Esbatu"; + +export type StateUpdatePartial = { + session_id?: string; + channel_id: string | null; + self_deaf: boolean; + self_mute: boolean; +}; + +export type ServerUpdate = { + token: string; + endpoint: string; +}; + +/** + * Represents a connection to a Discord voice channel. + */ export class VoiceConnection extends EventEmitter { - /** - * Main {@link Icelink} class. - * @readonly - */ - public readonly manager; - /** - * A id of Guild that contains the connected voice channel. - * @readonly - */ - public readonly guildId; - /** A id of the connected voice channel. */ - public channelId: string | null; - /** A id of the Shard that contains the guild that contains the connected voice channel. */ - public shardId; - /** Mute status in connected voice channel. */ - public muted; - /** Deafen status in connected voice channel. */ - public deafened; - /** A id of the last channelId connected to. */ - public lastChannelId: string | null = null; - /** A id of the session for voice connection. */ - public sessionId: string | null = null; - /** Region of connected voice channel. */ - public region: string | null = null; - /** Last region of the connected voice channel */ - public lastRegion: string | null = null; - /** Cached serverUpdate event from Lavalink Websocket. */ - public serverUpdate: ServerUpdate | null = null; - /** Connection state. */ - public state: State = State.Disconnected; - - /** - * Creates a new VoiceConnection instance. - * @param manager The manager of this connection. - * @param options The options to pass in connection creation. - */ - public constructor(manager: Icelink, options: VoiceChannelOptions) { - super(); - - this.manager = manager; - this.guildId = options.guildId; - this.channelId = options.channelId; - this.shardId = options.shardId; - this.muted = options.mute ?? false; - this.deafened = options.deaf ?? true; - - Object.defineProperties(this, { - manager: { enumerable: false, writable: false }, - guildId: { enumerable: true, writable: false } - }); - } - - /** - * Set the deafen status for the current bot user. - * @param deaf Boolean value to indicate whether to deafen or undeafen. - * @defaultValue true - */ - public setDeaf(deaf = true): void { - this.deafened = deaf; - - this.sendVoiceUpdate(); - } - - /** - * Set the mute status for the current bot user. - * @param mute Boolean value to indicate whether to mute or unmute. - * @defaultValue false - */ - public setMute(mute = false): void { - this.muted = mute; - - this.sendVoiceUpdate(); - } - - /** - * Disconnect the current bot user from the connected voice channel. - * @internal - */ - public disconnect(): void { - if (this.state === State.Disconnected) return undefined; - - this.channelId = null; - this.state = State.Disconnected; - - this.removeAllListeners(); - this.sendVoiceUpdate(); - - this.manager.emit("debug", `[VOICE => NODE & DISCORD] Connection destroyed, guild: ${this.guildId}.`); - } - - /** - * Connect the current bot user to a voice channel. - * @internal - */ - public async connect(): Promise { - if (this.state === State.Connecting || this.state === State.Connected) return; - - this.state = State.Connecting; - - this.sendVoiceUpdate(); - this.manager.emit("debug", `[VOICE => DISCORD] Requesting connection, guild: ${this.guildId}.`); - - const controller = new AbortController(); - const timeout = setTimeout(() => controller.abort(), this.manager.options.voiceConnectionTimeout * 1_000); - - try { - const [status] = await once(this, "connectionUpdate", { signal: controller.signal }); - - if (status !== VoiceState.SessionReady) - switch (status) { - case VoiceState.SessionIdMissing: - throw new Error("The voice connection is not established due to missing session id"); - case VoiceState.SessionEndpointMissing: - throw new Error("The voice connection is not established due to missing connection endpoint"); - } - - this.manager.emit("debug", `[VOICE => DISCORD] Request connected, guild: ${this.guildId}.`); - - this.state = State.Connected; - } catch (error: any) { - this.manager.emit("debug", `[VOICE => DISCORD] Request connection failure, guild: ${this.guildId}.`); - - if ((error as Error).name === "AbortError") - throw new Error( - `The voice connection is not established in ${this.manager.options.voiceConnectionTimeout} seconds` - ); - - throw error; - } finally { - clearTimeout(timeout); - } - } - - /** - * Send voice data to Discord. - * @internal - */ - public sendVoiceUpdate(): void { - this.manager.sendPacket( - this.shardId, - { - op: 4, - d: { guild_id: this.guildId, channel_id: this.channelId, self_deaf: this.deafened, self_mute: this.muted } - }, - false - ); - } + /** + * Main {@link Esbatu} class. + * + * @readonly + */ + public readonly manager; + /** + * A id of Guild that contains the connected voice channel. + * + * @readonly + */ + public readonly guildId; + /** + * A id of the connected voice channel. + */ + public channelId: string | null; + /** + * A id of the Shard that contains the guild that contains the connected voice channel. + */ + public shardId; + /** + * Mute status in connected voice channel. + */ + public muted; + /** + * Deafen status in connected voice channel. + */ + public deafened; + /** + * A id of the last channelId connected to. + */ + public lastChannelId: string | null = null; + /** + * A id of the session for voice connection. + */ + public sessionId: string | null = null; + /** + * Region of connected voice channel. + */ + public region: string | null = null; + /** + * Last region of the connected voice channel + */ + public lastRegion: string | null = null; + /** + * Cached serverUpdate event from Lavalink Websocket. + */ + public serverUpdate: ServerUpdate | null = null; + /** + * Connection state. + */ + public state: State = State.Disconnected; + + /** + * Creates a new VoiceConnection instance. + * + * @param manager The manager of this connection. + * @param options The options to pass in connection creation. + */ + public constructor(manager: Esbatu, options: VoiceChannelOptions) { + super(); + + this.manager = manager; + this.guildId = options.guildId; + this.channelId = options.channelId; + this.shardId = options.shardId; + this.muted = options.mute ?? false; + this.deafened = options.deaf ?? true; + + Object.defineProperties(this, { + manager: { enumerable: false, writable: false }, + guildId: { enumerable: true, writable: false } + }); + } + + /** + * Set the deafen status for the current bot user. + * + * @param deaf Boolean value to indicate whether to deafen or undeafen. + * @defaultValue true + */ + public setDeaf(deaf = true): void { + this.deafened = deaf; + + this.sendVoiceUpdate(); + } + + /** + * Set the mute status for the current bot user. + * + * @param mute Boolean value to indicate whether to mute or unmute. + * @defaultValue false + */ + public setMute(mute = false): void { + this.muted = mute; + + this.sendVoiceUpdate(); + } + + /** + * Disconnect the current bot user from the connected voice channel. + * + * @internal + */ + public disconnect(): void { + if (this.state === State.Disconnected) return undefined; + + this.channelId = null; + this.state = State.Disconnected; + + this.removeAllListeners(); + this.sendVoiceUpdate(); + + this.manager.emit("debug", `[VOICE => NODE & DISCORD] Connection destroyed, guild: ${this.guildId}.`); + + return undefined; + } + + /** + * Connect the current bot user to a voice channel. + * + * @internal + */ + public async connect(): Promise { + if (this.state === State.Connecting || this.state === State.Connected) return; + + this.state = State.Connecting; + + this.sendVoiceUpdate(); + this.manager.emit("debug", `[VOICE => DISCORD] Requesting connection, guild: ${this.guildId}.`); + + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), this.manager.options.voiceConnectionTimeout * 1_000); + + try { + // eslint-disable-next-line typescript/no-unsafe-assignment + const [status] = await once(this, "connectionUpdate", { signal: controller.signal }); + + if (status !== VoiceState.SessionReady) { + // eslint-disable-next-line default-case + switch (status) { + case VoiceState.SessionIdMissing: + throw new Error("The voice connection is not established due to missing session id"); + case VoiceState.SessionEndpointMissing: + throw new Error("The voice connection is not established due to missing connection endpoint"); + } + } + + this.manager.emit("debug", `[VOICE => DISCORD] Request connected, guild: ${this.guildId}.`); + + this.state = State.Connected; + } catch (error: any) { + this.manager.emit("debug", `[VOICE => DISCORD] Request connection failure, guild: ${this.guildId}.`); + + if ((error as Error).name === "AbortError") { + throw new Error( + `The voice connection is not established in ${this.manager.options.voiceConnectionTimeout} seconds` + ); + } + + throw error; + } finally { + clearTimeout(timeout); + } + } + + /** + * Send voice data to Discord. + * + * @internal + */ + public sendVoiceUpdate(): void { + this.manager.sendPacket( + this.shardId, + { + op: 4, + d: { + guild_id: this.guildId, + channel_id: this.channelId, + self_deaf: this.deafened, + self_mute: this.muted + } + }, + false + ); + } } diff --git a/src/index.ts b/src/index.ts index 59c6d2c..49042dc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,11 @@ -import { version as packageVersion } from "../package.json"; - export * as Constants from "./Constants"; -export * from "./Icelink"; +export * from "./Esbatu"; export * from "./node/index"; export * from "./node/Rest"; export * from "./guild/Player"; export * from "./guild/VoiceConnection"; -/** The {@link https://github.com/stegripe/icelink#readme | Icelink} version that you are currently using. */ -export const version = packageVersion; +/** + * The {@link https://github.com/stegripe/esbatu#readme | Esbatu} version that you are currently using. + */ +export { version } from "../package.json"; diff --git a/src/node/Rest.ts b/src/node/Rest.ts index 366fc19..072153e 100644 --- a/src/node/Rest.ts +++ b/src/node/Rest.ts @@ -1,414 +1,440 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import { Node, NodeInfo, NodeStats } from "./index"; -import { NodeOption } from "../Icelink"; -import { FilterOptions } from "../guild/Player"; +/* eslint-disable typescript/naming-convention, tsdoc/syntax */ +import { setTimeout, clearTimeout } from "node:timers"; +import { URL, URLSearchParams } from "node:url"; import { fetch } from "undici"; +import type { NodeOption } from "../Esbatu"; +import type { FilterOptions } from "../guild/Player"; +import type { Node, NodeInfo, NodeStats } from "./index"; export enum LoadType { - Track = "track", - Playlist = "playlist", - Search = "search", - Empty = "empty", - Error = "error" + Track = "track", + Playlist = "playlist", + Search = "search", + Empty = "empty", + Error = "error" } -export interface Track { - encoded: string; - info: { - identifier: string; - isSeekable: boolean; - author: string; - length: number; - isStream: boolean; - position: number; - title: string; - uri: string | null; - artworkUrl: string | null; - isrc: string | null; - sourceName: string; - }; - pluginInfo: object; -} - -export interface Playlist { - info: { - name: string; - selectedTrack: number; - }; - tracks: Track[]; - pluginInfo: object; -} - -export interface Exception { - message: string; - severity: Severity; - cause: string; -} +export type Track = { + encoded: string; + info: { + identifier: string; + isSeekable: boolean; + author: string; + length: number; + isStream: boolean; + position: number; + title: string; + uri: string | null; + artworkUrl: string | null; + isrc: string | null; + sourceName: string; + }; + pluginInfo: object; +}; + +export type Playlist = { + info: { + name: string; + selectedTrack: number; + }; + tracks: Track[]; + pluginInfo: object; +}; + +export type Exception = { + message: string; + severity: Severity; + cause: string; +}; export type Severity = "common" | "fault" | "suspicious"; export type LavalinkResponse = EmptyResult | ErrorResult | PlaylistResult | SearchResult | TrackResult; -export interface TrackResult { - loadType: LoadType.Track; - data: Track; -} - -export interface PlaylistResult { - loadType: LoadType.Playlist; - data: Playlist; -} - -export interface SearchResult { - loadType: LoadType.Search; - data: Track[]; -} - -export interface EmptyResult { - loadType: LoadType.Empty; - data: null; -} - -export interface ErrorResult { - loadType: LoadType.Error; - data: Exception; -} - -export interface Address { - address: string; - failingTimestamp: number; - failingTime: string; -} - -export interface RoutePlanner { - class: - | "BalancingIpRoutePlanner" - | "NanoIpRoutePlanner" - | "RotatingIpRoutePlanner" - | "RotatingNanoIpRoutePlanner" - | null; - details: { - ipBlock: { - type: string; - size: string; - }; - failingAddresses: Address[]; - rotateIndex: string; - ipIndex: string; - currentAddress: string; - blockIndex: string; - currentAddressIndex: string; - } | null; -} - -export interface LavalinkPlayer { - guildId: string; - track: Track | null; - volume: number; - paused: boolean; - state: LavalinkPlayerState; - voice: LavalinkPlayerVoiceState; - filters: FilterOptions; -} - -export interface LavalinkPlayerState { - time: number; - position: number; - connected: boolean; - ping: number; -} - -export interface LavalinkPlayerVoiceState { - token: string; - endpoint: string; - sessionId: string; -} - -export interface UpdatePlayerInfo { - guildId: string; - playerOptions: UpdatePlayerOptions; - noReplace?: boolean; -} - -export interface UpdatePlayerOptions { - track?: { encoded?: string | null }; - position?: number; - endTime?: number; - volume?: number; - paused?: boolean; - filters?: FilterOptions; - voice?: LavalinkPlayerVoiceState; -} - -export interface SessionInfo { - resuming: boolean; - timeout: number; -} - -interface FetchOptions { - endpoint: string; - options: { - [key: string]: unknown; - headers?: Record; - params?: Record; - method?: string; - body?: Record | string[]; - }; -} - -interface FinalFetchOptions { - method: string; - headers: Record; - signal: AbortSignal; - body?: string; -} - -/** Wrapper around for the Lavalink REST API. */ +export type TrackResult = { + loadType: LoadType.Track; + data: Track; +}; + +export type PlaylistResult = { + loadType: LoadType.Playlist; + data: Playlist; +}; + +export type SearchResult = { + loadType: LoadType.Search; + data: Track[]; +}; + +export type EmptyResult = { + loadType: LoadType.Empty; + data: null; +}; + +export type ErrorResult = { + loadType: LoadType.Error; + data: Exception; +}; + +export type Address = { + address: string; + failingTimestamp: number; + failingTime: string; +}; + +export type RoutePlanner = { + class: + | "BalancingIpRoutePlanner" + | "NanoIpRoutePlanner" + | "RotatingIpRoutePlanner" + | "RotatingNanoIpRoutePlanner" + | null; + details: { + ipBlock: { + type: string; + size: string; + }; + failingAddresses: Address[]; + rotateIndex: string; + ipIndex: string; + currentAddress: string; + blockIndex: string; + currentAddressIndex: string; + } | null; +}; + +export type LavalinkPlayer = { + guildId: string; + track: Track | null; + volume: number; + paused: boolean; + state: LavalinkPlayerState; + voice: LavalinkPlayerVoiceState; + filters: FilterOptions; +}; + +export type LavalinkPlayerState = { + time: number; + position: number; + connected: boolean; + ping: number; +}; + +export type LavalinkPlayerVoiceState = { + token: string; + endpoint: string; + sessionId: string; +}; + +export type UpdatePlayerInfo = { + guildId: string; + playerOptions: UpdatePlayerOptions; + noReplace?: boolean; +}; + +export type UpdatePlayerOptions = { + track?: { encoded?: string | null; }; + position?: number; + endTime?: number; + volume?: number; + paused?: boolean; + filters?: FilterOptions; + voice?: LavalinkPlayerVoiceState; +}; + +export type SessionInfo = { + resuming: boolean; + timeout: number; +}; + +type FetchOptions = { + endpoint: string; + options: { + [key: string]: unknown; + headers?: Record; + params?: Record; + method?: string; + body?: Record | string[]; + }; +}; + +type FinalFetchOptions = { + method: string; + headers: Record; + signal: AbortSignal; + body?: string; +}; + +/** + * Wrapper around for the Lavalink REST API. + */ export class Rest { - /** Decode for single or multiple of track. */ - public decode = { - /** - * Decode a single track into it's info. - * @param encodedTrack A encoded track. - * @returns Promise that resolves to a track. - */ - singleTrack: (encodedTrack: string): Promise => - this.request({ endpoint: "/decodetrack", options: { params: { encodedTrack } } }), - - /** - * Decodes multiple tracks into their info. - * @param encodeds A encodeds track. - * @returns Promise that resolves to an array of tracks. - */ - multipleTracks: (encodeds: string[]): Promise => - this.request({ - endpoint: "/decodetracks", - options: { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: encodeds - } - }) - }; - - /** - * {@link Node} that initialized this instance. - * @readonly - */ - public readonly node; - /** - * A URL of the Lavalink. - * @protected - * @readonly - * @internal - */ - protected readonly url; - /** - * A credentials to access the Lavalink. - * @protected - * @readonly - * @internal - */ - protected readonly authorization; - /** - * Rest version to use. - * @protected - * @readonly - * @internal - */ - protected readonly version: string = "/v4"; - - /** - * Create a Lavalink REST API class instance on {@link Node}. - * @param node An instance of {@link Node}. - * @param options The options to initialize this rest class. - */ - public constructor(node: Node, options: NodeOption) { - this.node = node; - this.url = `${options.secure ? "https" : "http"}://${options.url}`; - this.authorization = options.authorization; - - Object.defineProperties(this, { - decode: { enumerable: false, writable: false }, - node: { enumerable: true, writable: false }, - url: { enumerable: false, writable: false }, - authorization: { enumerable: false, writable: false }, - version: { enumerable: false, writable: false } - }); - } - - /** - * SessionId for Lavalink REST API. (not to be confused with Discord SessionId) - * @protected - * @readonly - * @internal - */ - protected get sessionId(): string { - return this.node.sessionId!; - } - - /** - * Resolve a new track. - * @param identifier A track identifier. - * @returns A promise that resolves to a Lavalink response. - */ - public resolve(identifier: string): Promise { - return this.request({ - endpoint: "/loadtracks", - options: { params: { identifier } } - }); - } - - /** - * Gets all the Player State with the specified sessionId. - * @returns Promise that resolves to an array of Lavalink players. - */ - public getPlayers(): Promise { - return this.request({ endpoint: `/sessions/${this.sessionId}/players`, options: {} }); - } - - /** - * Get the Player State with the specified guildId. - * @param guildId guildId where this player is. - * @returns Promise that resolves to a Lavalink player. - */ - public getPlayer(guildId: string): Promise { - return this.request({ - endpoint: `/sessions/${this.sessionId}/players/${guildId}`, - options: {} - }); - } - - /** - * Update the Player State on the Lavalink Server - * @param data A data for update the Player state. - * @returns Promise that resolves to a Lavalink player. - */ - public updatePlayer(data: UpdatePlayerInfo): Promise { - return this.request({ - endpoint: `/sessions/${this.sessionId}/players/${data.guildId}`, - options: { - method: "PATCH", - params: { noReplace: data.noReplace?.toString() ?? "false" }, - headers: { "Content-Type": "application/json" }, - body: data.playerOptions as Record - } - }); - } - - /** - * Delete the Player State from the Lavalink Server. - * @param guildId guildId where this player is. - */ - public async destroyPlayer(guildId: string): Promise { - await this.request({ - endpoint: `/sessions/${this.sessionId}/players/${guildId}`, - options: { method: "DELETE" } - }); - } - - /** - * Updates the session with a resume boolean and timeout. - * @param resuming Whether resuming is enabled for this session or not. - * @param timeout Timeout to wait for resuming. - * @returns Promise that resolves to a session info response. - */ - public updateSession(resuming: boolean, timeout: number): Promise { - return this.request({ - endpoint: `/sessions/${this.sessionId}`, - options: { - method: "PATCH", - headers: { "Content-Type": "application/json" }, - body: { resuming, timeout } - } - }); - } - - /** - * Gets the status of this node. - * @returns Promise that resolves to a node stats response. - */ - public stats(): Promise { - return this.request({ endpoint: "/stats", options: {} }); - } - - /** - * Get routeplanner status from Lavalink. - * @returns Promise that resolves to a routeplanner response. - */ - public getRoutePlannerStatus(): Promise { - return this.request({ endpoint: "/routeplanner/status", options: {} }); - } - - /** - * Release blacklisted IP address into pool of IPs. - * @param address IP address. - */ - public async unmarkFailedAddress(address: string): Promise { - await this.request({ - endpoint: "/routeplanner/free/address", - options: { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: { address } - } - }); - } - - /** Get a Lavalink information. */ - public getLavalinkInfo(): Promise { - return this.request({ - endpoint: "/info", - options: { headers: { "Content-Type": "application/json" } } - }); - } - - /** - * Make a request to Lavalink. - * @param fetchOptions a options for fetch to get the data from Lavalink REST API. - * @private - * @internal - */ - private async request(fetchOptions: FetchOptions): Promise { - const { endpoint, options } = fetchOptions; - const headers = { - Authorization: this.authorization, - "User-Agent": this.node.manager.options.userAgent, - ...(options.headers ?? {}) - }; - const url = new URL(`${this.url}${this.version}${endpoint}`); - - if (options.params) url.search = new URLSearchParams(options.params).toString(); - - const abortController = new AbortController(); - const timeout = setTimeout(() => abortController.abort(), this.node.manager.options.restTimeout * 1_000); - const method = options.method?.toUpperCase() ?? "GET"; - const finalFetchOptions: FinalFetchOptions = { - method, - headers, - signal: abortController.signal - }; - - if (!["GET", "HEAD"].includes(method) && options.body) finalFetchOptions.body = JSON.stringify(options.body); - - const request = await fetch(url.toString(), finalFetchOptions).finally(() => clearTimeout(timeout)); - - if (!request.ok) { - const response = await request.json().catch(() => null); - - if ("message" in (response as any)) { - throw new Error( - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - `Rest request failed with response code: ${request.status}, message: ${(response as any).message}` - ); - } else { - throw new Error(`Rest request failed with response code: ${request.status}`); - } - } - - try { - return (await request.json()) as T; - } catch { - return undefined as T; - } - } + /** + * Decode for single or multiple of track. + */ + public decode = { + /** + * Decode a single track into it's info. + * + * @param encodedTrack A encoded track. + * @returns Promise that resolves to a track. + */ + singleTrack: async (encodedTrack: string): Promise => this.request({ endpoint: "/decodetrack", options: { params: { encodedTrack } } }), + + /** + * Decodes multiple tracks into their info. + * + * @param encodeds A encodeds track. + * @returns Promise that resolves to an array of tracks. + */ + multipleTracks: async (encodeds: string[]): Promise => this.request({ + endpoint: "/decodetracks", + options: { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: encodeds + } + }) + }; + + /** + * {@link Node} that initialized this instance. + * + * @readonly + */ + public readonly node; + /** + * A URL of the Lavalink. + * + * @protected + * @readonly + * @internal + */ + protected readonly url; + /** + * A credentials to access the Lavalink. + * + * @protected + * @readonly + * @internal + */ + protected readonly authorization; + /** + * Rest version to use. + * + * @protected + * @readonly + * @internal + */ + protected readonly version: string = "/v4"; + + /** + * Create a Lavalink REST API class instance on {@link Node}. + * + * @param node An instance of {@link Node}. + * @param options The options to initialize this rest class. + */ + public constructor(node: Node, options: NodeOption) { + this.node = node; + this.url = `${options.secure ?? false ? "https" : "http"}://${options.url}`; + this.authorization = options.authorization; + + Object.defineProperties(this, { + decode: { enumerable: false, writable: false }, + node: { enumerable: true, writable: false }, + url: { enumerable: false, writable: false }, + authorization: { enumerable: false, writable: false }, + version: { enumerable: false, writable: false } + }); + } + + /** + * SessionId for Lavalink REST API. (not to be confused with Discord SessionId) + * + * @protected + * @readonly + * @internal + */ + protected get sessionId(): string { + // eslint-disable-next-line typescript/no-non-null-assertion + return this.node.sessionId!; + } + + /** + * Resolve a new track. + * + * @param identifier A track identifier. + * @returns A promise that resolves to a Lavalink response. + */ + public async resolve(identifier: string): Promise { + return this.request({ + endpoint: "/loadtracks", + options: { params: { identifier } } + }); + } + + /** + * Gets all the Player State with the specified sessionId. + * + * @returns Promise that resolves to an array of Lavalink players. + */ + public async getPlayers(): Promise { + return this.request({ endpoint: `/sessions/${this.sessionId}/players`, options: {} }); + } + + /** + * Get the Player State with the specified guildId. + * + * @param guildId guildId where this player is. + * @returns Promise that resolves to a Lavalink player. + */ + public async getPlayer(guildId: string): Promise { + return this.request({ + endpoint: `/sessions/${this.sessionId}/players/${guildId}`, + options: {} + }); + } + + /** + * Update the Player State on the Lavalink Server + * + * @param data A data for update the Player state. + * @returns Promise that resolves to a Lavalink player. + */ + public async updatePlayer(data: UpdatePlayerInfo): Promise { + return this.request({ + endpoint: `/sessions/${this.sessionId}/players/${data.guildId}`, + options: { + method: "PATCH", + params: { noReplace: data.noReplace?.toString() ?? "false" }, + headers: { "Content-Type": "application/json" }, + body: data.playerOptions as Record + } + }); + } + + /** + * Delete the Player State from the Lavalink Server. + * + * @param guildId guildId where this player is. + */ + public async destroyPlayer(guildId: string): Promise { + await this.request({ + endpoint: `/sessions/${this.sessionId}/players/${guildId}`, + options: { method: "DELETE" } + }); + } + + /** + * Updates the session with a resume boolean and timeout. + * + * @param resuming Whether resuming is enabled for this session or not. + * @param timeout Timeout to wait for resuming. + * @returns Promise that resolves to a session info response. + */ + public async updateSession(resuming: boolean, timeout: number): Promise { + return this.request({ + endpoint: `/sessions/${this.sessionId}`, + options: { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: { resuming, timeout } + } + }); + } + + /** + * Gets the status of this node. + * + * @returns Promise that resolves to a node stats response. + */ + public async stats(): Promise { + return this.request({ endpoint: "/stats", options: {} }); + } + + /** + * Get routeplanner status from Lavalink. + * + * @returns Promise that resolves to a routeplanner response. + */ + public async getRoutePlannerStatus(): Promise { + return this.request({ endpoint: "/routeplanner/status", options: {} }); + } + + /** + * Release blacklisted IP address into pool of IPs. + * + * @param address IP address. + */ + public async unmarkFailedAddress(address: string): Promise { + await this.request({ + endpoint: "/routeplanner/free/address", + options: { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: { address } + } + }); + } + + /** + * Get a Lavalink information. + */ + public async getLavalinkInfo(): Promise { + return this.request({ + endpoint: "/info", + options: { headers: { "Content-Type": "application/json" } } + }); + } + + /** + * Make a request to Lavalink. + * + * @param fetchOptions a options for fetch to get the data from Lavalink REST API. + * @private + * @internal + */ + private async request(fetchOptions: FetchOptions): Promise { + const { endpoint, options } = fetchOptions; + const headers = { + Authorization: this.authorization, + "User-Agent": this.node.manager.options.userAgent, + ...options.headers + }; + const url = new URL(`${this.url}${this.version}${endpoint}`); + + if (options.params) url.search = new URLSearchParams(options.params).toString(); + + const abortController = new AbortController(); + const timeout = setTimeout(() => abortController.abort(), this.node.manager.options.restTimeout * 1_000); + const method = options.method?.toUpperCase() ?? "GET"; + const finalFetchOptions: FinalFetchOptions = { + method, + headers, + signal: abortController.signal + }; + + if (!["GET", "HEAD"].includes(method) && options.body) finalFetchOptions.body = JSON.stringify(options.body); + + const request = await fetch(url.toString(), finalFetchOptions).finally(() => clearTimeout(timeout)); + + if (!request.ok) { + const response = await request.json().catch(() => null); + + // eslint-disable-next-line unicorn/prefer-ternary + if ("message" in (response as any)) { + throw new Error( + // eslint-disable-next-line typescript/no-unsafe-member-access + `Rest request failed with response code: ${request.status}, message: ${(response as any).message}` + ); + } else { + throw new Error(`Rest request failed with response code: ${request.status}`); + } + } + + try { + return (await request.json()) as T; + } catch { + return undefined as T; + } + } } diff --git a/src/node/index.ts b/src/node/index.ts index e64dfef..8d786ca 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -1,583 +1,660 @@ -/* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/naming-convention, no-case-declarations, max-lines */ -import { IncomingMessage } from "http"; -import { NodeOption, Icelink, VoiceChannelOptions } from "../Icelink"; -import { OpCodes, State, VoiceState, RedisKey } from "../Constants"; -import { Rest } from "./Rest"; +/* eslint-disable stylistic/max-len, typescript/no-unsafe-argument, typescript/no-unsafe-assignment, typescript/no-unsafe-member-access, typescript/no-non-null-assertion, typescript/no-shadow, typescript/naming-convention, tsdoc/syntax, no-await-in-loop, no-param-reassign */ +import { Buffer } from "node:buffer"; +import type { IncomingMessage } from "node:http"; +import { setTimeout } from "node:timers"; +import { URL } from "node:url"; import Websocket from "ws"; +import { OpCodes, State, VoiceState, RedisKey } from "../Constants"; +import type { NodeOption, Esbatu, VoiceChannelOptions } from "../Esbatu"; import { Player } from "../guild/Player"; import { VoiceConnection } from "../guild/VoiceConnection"; +import { Rest } from "./Rest"; -export interface NodeStats { - players: number; - playingPlayers: number; - memory: { - reservable: number; - used: number; - free: number; - allocated: number; - }; - frameStats: { - sent: number; - deficit: number; - nulled: number; - } | null; - cpu: { - cores: number; - systemLoad: number; - lavalinkLoad: number; - }; - uptime: number; -} - -export interface NodeInfo { - version: NodeInfoVersion; - buildTime: number; - git: NodeInfoGit; - jvm: string; - lavaplayer: string; - sourceManagers: string[]; - filters: string[]; - plugins: NodeInfoPlugin[]; -} - -export interface NodeInfoVersion { - semver: string; - major: number; - minor: number; - patch: number; - preRelease: string | null; - build: string | null; -} - -export interface NodeInfoGit { - branch: string; - commit: string; - commitTime: number; -} - -export interface NodeInfoPlugin { - name: string; - version: string; -} - -interface ResumableHeaders { - "Client-Name": string; - "User-Agent": string; - Authorization: string; - "User-Id": string; - "Session-Id": string; -} - -interface NonResumableHeaders extends Omit {} - -/** Represents a Lavalink node. */ +export type NodeStats = { + players: number; + playingPlayers: number; + memory: { + reservable: number; + used: number; + free: number; + allocated: number; + }; + frameStats: { + sent: number; + deficit: number; + nulled: number; + } | null; + cpu: { + cores: number; + systemLoad: number; + lavalinkLoad: number; + }; + uptime: number; +}; + +export type NodeInfo = { + version: NodeInfoVersion; + buildTime: number; + git: NodeInfoGit; + jvm: string; + lavaplayer: string; + sourceManagers: string[]; + filters: string[]; + plugins: NodeInfoPlugin[]; +}; + +export type NodeInfoVersion = { + semver: string; + major: number; + minor: number; + patch: number; + preRelease: string | null; + build: string | null; +}; + +export type NodeInfoGit = { + branch: string; + commit: string; + commitTime: number; +}; + +export type NodeInfoPlugin = { + name: string; + version: string; +}; + +type ResumableHeaders = { + "Client-Name": string; + "User-Agent": string; + Authorization: string; + "User-Id": string; + "Session-Id": string; +}; + +type NonResumableHeaders = Omit & {}; + +/** + * Represents a Lavalink node. + */ export class Node { - /** - * Main {@link Icelink} class. - * @readonly - */ - public readonly manager; - /** - * A Lavalink {@link Rest | REST} API. - * @readonly - */ - public readonly rest; - /** - * Name of this node. - * @readonly - */ - public readonly name; - /** The number of reconnects to Lavalink. */ - public reconnects = 0; - /** The state of this connection. */ - public state: State = State.Disconnected; - /** Statistics from Lavalink. */ - public stats: NodeStats | null = null; - /** Websocket instance for the Lavalink. */ - public ws: Websocket | null = null; - /** SessionId of this Lavalink connection. (not to be confused with Discord SessionId) */ - public sessionId: string | null = null; - /** - * A URL of the Lavalink. - * @protected - * @readonly - * @internal - */ - protected readonly url; - /** - * A credentials to access the Lavalink. - * @protected - * @readonly - * @internal - */ - protected readonly authorization; - /** - * Websocket version this node will use. - * @protected - * @readonly - * @internal - */ - protected readonly version: string = "/v4"; - /** - * Boolean that represents if the node has initialized once. - * @private - * @internal - */ - private initialized = false; - /** - * Boolean that represents if this connection is destroyed. - * @private - * @internal - */ - private destroyed = false; - - /** - * Creates a new Node instance for {@link Icelink}. - * @param manager A {@link Icelink} instance. - * @param options Options on creating this node. - */ - public constructor(manager: Icelink, options: NodeOption) { - this.manager = manager; - this.rest = new (manager.options.structures.rest ?? Rest)(this, options); - this.name = options.name; - this.url = `${options.secure ? "wss" : "ws"}://${options.url}`; - this.authorization = options.authorization; - - Object.defineProperties(this, { - manager: { enumerable: false, writable: false }, - rest: { enumerable: true, writable: false }, - name: { enumerable: true, writable: false }, - url: { enumerable: true, writable: false }, - authorization: { enumerable: false, writable: false }, - version: { enumerable: true, writable: false }, - initialized: { enumerable: false, writable: true }, - destroyed: { enumerable: false, writable: true } - }); - } - - /** - * Penalties for load balancing - * @returns Penalty score - * @readonly - * @internal - */ - public get penalties(): number { - let penalties = 0; - - if (!this.stats) return penalties; - - penalties += this.stats.players; - penalties += Math.round(Math.pow(1.05, 100 * this.stats.cpu.systemLoad) * 10 - 10); - - if (this.stats.frameStats) { - penalties += this.stats.frameStats.deficit; - penalties += this.stats.frameStats.nulled * 2; - } - - return penalties; - } - - /** - * If we should clean this node - * @private - * @readonly - * @internal - */ - private get shouldClean(): boolean { - return this.destroyed || this.reconnects >= this.manager.options.reconnectTries; - } - - /** Connect to the Lavalink Websocket. */ - public async connect(): Promise { - if (!this.manager.id) throw new Error("Don't connect a node when the library is not yet ready"); - if (this.destroyed) - throw new Error("You can't re-use the same instance of a node once disconnected, please re-add the node again"); - if (this.state === State.Connected) return undefined; - - let unSupportedVersion = false; - - try { - const version = await ( - await fetch(`${this.url.replace("ws", "http")}/version`, { - headers: { Authorization: this.authorization, "User-Agent": this.manager.options.userAgent } - }) - ).text(); - const versionRegex = - /^(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-(?(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/; - - if (Number(versionRegex.exec(version)?.at(1) ?? 0) !== 4) unSupportedVersion = true; - } catch { - /* empty */ - } - - if (unSupportedVersion) throw new Error(`This node (${this.name}) is only supported for v4`); - - this.state = State.Connecting; - this.sessionId = (await this.manager.redis?.get(RedisKey.NodeSession(this.name.toLowerCase()))) ?? null; - - const headers: NonResumableHeaders | ResumableHeaders = { - "Client-Name": this.manager.options.userAgent, - "User-Agent": this.manager.options.userAgent, - "User-Id": this.manager.id, - Authorization: this.authorization - }; - - if (this.sessionId) (headers as ResumableHeaders)["Session-Id"] = this.sessionId; - - this.manager.emit( - "debug", - `[WS => ${this.name}] Connecting ${this.url}, lavalink version: ${this.version}, trying to resume? ${Boolean( - this.sessionId - )}.` - ); - - if (!this.initialized) this.initialized = true; - - this.ws = new Websocket(new URL(`${this.url}${this.version}/websocket`), { headers } as Websocket.ClientOptions); - - this.ws.once("upgrade", this.open.bind(this)); - this.ws.once("close", this.close.bind(this)); - this.ws.on("error", this.error.bind(this)); - this.ws.on("message", data => this.message(data).catch(error => this.error(error as Error))); - } - - /** - * Disconnect the from Lavalink Websocket. - * @param code Status code. - * @param reason Reason for the disconnect. - */ - public disconnect(code: number, reason?: string): void { - if (this.destroyed) return undefined; - - this.destroyed = true; - this.state = State.Disconnected; - - if (this.ws) this.ws.close(code, reason); - else void this.clean(); - } - - /** - * Joins a voice channel. - * @param options The options to pass in connection creation. - * @returns The created new Player. - */ - public async joinVoiceChannel(options: VoiceChannelOptions): Promise { - if (this.manager.connections.has(options.guildId)) - throw new Error("This guild already have an existing connection"); - - const connection = new VoiceConnection(this.manager, options); - - this.manager.connections.set(connection.guildId, connection); - - try { - await connection.connect(); - } catch (error) { - this.manager.connections.delete(options.guildId); - - throw error; - } - - try { - const player = new (this.manager.options.structures.player ?? Player)(connection.guildId, this); - - await player.sendServerUpdate(connection); - connection.on("connectionUpdate", async (state: VoiceState) => { - if (state !== VoiceState.SessionReady) return undefined; - - const IDataCache = await this.manager.redis?.get(RedisKey.NodePlayers(player.node.name.toLowerCase())); - const dataCache = IDataCache ? (JSON.parse(IDataCache) as VoiceChannelOptions[]) : []; - const dataIndex = dataCache.indexOf(dataCache.find(({ guildId }) => guildId === connection.guildId)!); - - dataCache.at(dataIndex)!.guildId = connection.guildId; - dataCache.at(dataIndex)!.channelId = connection.channelId!; - dataCache.at(dataIndex)!.shardId = connection.shardId; - dataCache.at(dataIndex)!.deaf = connection.deafened; - dataCache.at(dataIndex)!.mute = connection.muted; - - await this.manager.redis?.set(RedisKey.NodePlayers(player.node.name.toLowerCase()), JSON.stringify(dataCache)); - - return player.sendServerUpdate(connection); - }); - - const IDataCache = await this.manager.redis?.get(RedisKey.NodePlayers(this.name.toLowerCase())); - const dataCache = IDataCache ? (JSON.parse(IDataCache) as VoiceChannelOptions[]) : []; - - if (!dataCache.some(({ guildId }) => guildId === options.guildId)) { - dataCache.push({ - guildId: options.guildId, - channelId: options.channelId, - shardId: options.shardId, - deaf: options.deaf ?? true, - mute: options.mute ?? false - }); - - await this.manager.redis?.set(RedisKey.NodePlayers(this.name.toLowerCase()), JSON.stringify(dataCache)); - } - - this.manager.players.set(player.guildId, player); - - return player; - } catch (error) { - connection.disconnect(); - this.manager.connections.delete(options.guildId); - - throw error; - } - } - - /** - * Leaves a voice channel. - * @param guildId The id of the guild you want to delete. - * @returns The destroyed / disconnected player or undefined if none. - */ - public async leaveVoiceChannel(guildId: string): Promise { - const connection = this.manager.connections.get(guildId); - const player = this.manager.players.get(guildId); - - if (connection) { - connection.disconnect(); - this.manager.connections.delete(guildId); - } - if (player) { - player.clean(); - - try { - await player.destroyPlayer(); - } catch { - /* empty */ - } - - this.manager.players.delete(guildId); - } - - const IDataCache = await this.manager.redis?.get(RedisKey.NodePlayers(this.name.toLowerCase())); - const dataCache = IDataCache ? (JSON.parse(IDataCache) as VoiceChannelOptions[]) : []; - - dataCache.splice(dataCache.indexOf(dataCache.find(({ guildId: id }) => id === guildId)!), 1); - - await this.manager.redis?.set(RedisKey.NodePlayers(this.name.toLowerCase()), JSON.stringify(dataCache)); - } - - /** - * Handle connection open event from the Lavalink Websocket. - * @param response Response from Lavalink Websocket. - * @private - * @internal - */ - private open(response: IncomingMessage): void { - const resumed = response.headers["session-resumed"] === "true"; - - this.manager.emit("debug", `[WS => ${this.name}] Connection handshake done, upgrade headers resumed: ${resumed}.`); - - this.reconnects = 0; - this.state = State.Nearly; - } - - /** - * Handle message from the Lavalink Websocket. - * @param message JSON message. - * @private - * @internal - */ - private async message(message: Websocket.RawData): Promise { - if (Array.isArray(message)) message = Buffer.concat(message); - if (message instanceof ArrayBuffer) message = Buffer.from(message); - - // eslint-disable-next-line @typescript-eslint/no-base-to-string - const data = JSON.parse(message.toString()); - - if (!data) return undefined; - if (this.destroyed || this.state === State.Reconnecting) return undefined; - - this.manager.emit("raw", this.name, data); - - switch (data.op) { - case OpCodes.Stats: - delete data.op; - - this.stats = data; - - this.manager.emit("debug", `[WS => ${this.name}] Node status update, server load of ${this.penalties}.`); - - break; - case OpCodes.Ready: - this.state = State.Connected; - this.sessionId = data.sessionId; - - const players = [...this.manager.players.values()].filter(player => player.node.name === this.name); - const resumeByLibrary = Boolean(this.initialized && this.manager.options.resumeByLibrary && players.length); - - this.manager.emit( - "debug", - `[WS => ${this.name}] Lavalink is ready, lavalink resume: ${data.resumed}, icelink resume: ${resumeByLibrary}.` - ); - - if (resumeByLibrary) { - try { - const playersWithData: Player[] = []; - const playersWithoutData: Player[] = []; - - for (const player of this.manager.players.values()) { - const serverUpdate = this.manager.connections.get(player.guildId)?.serverUpdate; - - if (serverUpdate) playersWithData.push(player); - else playersWithoutData.push(player); - } - - await Promise.allSettled([ - ...playersWithData.map(player => player.resumePlayer()), - ...playersWithoutData.map(({ guildId }) => this.leaveVoiceChannel(guildId)) - ]); - } catch (error) { - this.error(error as Error); - } - } - - if (this.manager.options.resume) { - try { - await this.manager.redis?.set(RedisKey.NodeSession(this.name.toLowerCase()), this.sessionId!); - await this.rest.updateSession(this.manager.options.resume, this.manager.options.resumeTimeout); - - if (data.resumed) { - const IDataCache = await this.manager.redis?.get(RedisKey.NodePlayers(this.name.toLowerCase())); - const dataCache = IDataCache ? (JSON.parse(IDataCache) as VoiceChannelOptions[]) : []; - - for (const { guildId, channelId, shardId, mute, deaf } of dataCache) { - const player = await this.joinVoiceChannel({ - guildId, - channelId, - shardId, - mute, - deaf - }).catch(() => undefined); - - // eslint-disable-next-line max-depth - if (player) continue; - - dataCache.splice(dataCache.indexOf(dataCache.find(({ guildId: id }) => id === guildId)!), 1); - - await this.manager.redis?.set(RedisKey.NodePlayers(this.name.toLowerCase()), JSON.stringify(dataCache)); - } - } - - this.manager.emit("debug", `[WS => ${this.name}] Resuming configured.`); - } catch (error) { - this.error(error as Error); - } - } - - this.manager.emit("ready", this.name, resumeByLibrary || data.resumed); - - break; - case OpCodes.Event: - case OpCodes.PlayerUpdate: - const player = this.manager.players.get(data.guildId); - - if (!player) return undefined; - if (data.op === OpCodes.Event) player.onPlayerEvent(data); - else player.onPlayerUpdate(data); - - break; - default: - this.manager.emit("debug", `[WS => ${this.name}] Unknown opcodes message, type: ${data.op}.`); - } - } - - /** - * Handle closed event from the Lavalink Websocket. - * @param code Status close. - * @param reason Reason for connection close. - * @private - * @internal - */ - private close(code: number, reason: Buffer): void { - this.manager.emit("debug", `[WS => ${this.name}] Connection closed, code: ${code || "unknown"}.`); - this.manager.emit("close", this.name, code, reason.toString()); - - if (this.shouldClean) void this.clean(); - else this.reconnect(); - } - - /** - * To emit error events easily. - * @param error A error message. - * @private - * @internal - */ - private error(error: Error): void { - this.manager.emit("error", this.name, error); - } - - /** - * Destroys the Lavalink Websocket connection. - * @param count A total of players success to move another node. - * @private - * @internal - */ - private destroy(count: number = 0): void { - this.ws?.removeAllListeners(); - this.ws?.close(); - - this.ws = null; - this.sessionId = null; - this.state = State.Disconnected; - - if (!this.shouldClean) return undefined; - - this.destroyed = true; - - this.manager.emit("disconnect", this.name, count); - this.manager.nodes.delete(this.name); - } - - /** - * Cleans and moves players to other nodes if possible. - * @private - * @internal - */ - private async clean(): Promise { - let count = 0; - - if (!this.manager.options.moveOnDisconnect) return this.destroy(count); - - const players = [...this.manager.players.values()].filter(player => player.node.name === this.name); - - try { - const data = await Promise.allSettled(players.map(player => player.movePlayer())); - - count = data.filter(results => results.status === "fulfilled").length; - } catch (error) { - this.error(error as Error); - } - - return this.destroy(count); - } - - /** - * Reconnect to the Lavalink Websocket. - * @private - * @internal - */ - private reconnect(): void { - if (this.state === State.Reconnecting) return undefined; - if (this.state !== State.Disconnected) this.destroy(); - - this.state = State.Reconnecting; - this.reconnects++; - - this.manager.emit( - "reconnecting", - this.name, - this.manager.options.reconnectTries - this.reconnects, - this.manager.options.reconnectInterval - ); - this.manager.emit( - "debug", - `[WS => ${this.name}] Reconnecting in ${this.manager.options.reconnectInterval} seconds, ${ - this.manager.options.reconnectTries - this.reconnects - } tries left.` - ); - - setTimeout(() => this.connect(), this.manager.options.reconnectInterval * 1_000); - } + /** + * Main {@link Esbatu} class. + * + * @readonly + */ + public readonly manager; + /** + * A Lavalink {@link Rest | REST} API. + * + * @readonly + */ + public readonly rest; + /** + * Name of this node. + * + * @readonly + */ + public readonly name; + /** + * The number of reconnects to Lavalink. + */ + public reconnects = 0; + /** + * The state of this connection. + */ + public state: State = State.Disconnected; + /** + * Statistics from Lavalink. + */ + public stats: NodeStats | null = null; + /** + * Websocket instance for the Lavalink. + */ + public ws: Websocket | null = null; + /** + * SessionId of this Lavalink connection. (not to be confused with Discord SessionId) + */ + public sessionId: string | null = null; + /** + * A URL of the Lavalink. + * + * @protected + * @readonly + * @internal + */ + protected readonly url; + /** + * A credentials to access the Lavalink. + * + * @protected + * @readonly + * @internal + */ + protected readonly authorization; + /** + * Websocket version this node will use. + * + * @protected + * @readonly + * @internal + */ + protected readonly version: string = "/v4"; + /** + * Boolean that represents if the node has initialized once. + * + * @private + * @internal + */ + private initialized = false; + /** + * Boolean that represents if this connection is destroyed. + * + * @private + * @internal + */ + private destroyed = false; + + /** + * Creates a new Node instance for {@link Esbatu}. + * + * @param manager A {@link Esbatu} instance. + * @param options Options on creating this node. + */ + public constructor(manager: Esbatu, options: NodeOption) { + this.manager = manager; + this.rest = new (manager.options.structures.rest ?? Rest)(this, options); + this.name = options.name; + this.url = `${options.secure ?? false ? "wss" : "ws"}://${options.url}`; + this.authorization = options.authorization; + + Object.defineProperties(this, { + manager: { enumerable: false, writable: false }, + rest: { enumerable: true, writable: false }, + name: { enumerable: true, writable: false }, + url: { enumerable: true, writable: false }, + authorization: { enumerable: false, writable: false }, + version: { enumerable: true, writable: false }, + initialized: { enumerable: false, writable: true }, + destroyed: { enumerable: false, writable: true } + }); + } + + /** + * Penalties for load balancing + * + * @returns Penalty score + * @readonly + * @internal + */ + public get penalties(): number { + let penalties = 0; + + if (!this.stats) return penalties; + + penalties += this.stats.players; + // eslint-disable-next-line stylistic/no-mixed-operators + penalties += Math.round(1.05 ** (100 * this.stats.cpu.systemLoad) * 10 - 10); + + if (this.stats.frameStats) { + penalties += this.stats.frameStats.deficit; + penalties += this.stats.frameStats.nulled * 2; + } + + return penalties; + } + + /** + * If we should clean this node + * + * @private + * @readonly + * @internal + */ + private get shouldClean(): boolean { + return this.destroyed || this.reconnects >= this.manager.options.reconnectTries; + } + + /** + * Connect to the Lavalink Websocket. + */ + public async connect(): Promise { + if (this.manager.id === null) throw new Error("Don't connect a node when the library is not yet ready"); + if (this.destroyed) { + throw new Error( + "You can't re-use the same instance of a node once disconnected, please re-add the node again" + ); + } + if (this.state === State.Connected) return undefined; + + let unSupportedVersion = false; + + try { + const version = await ( + await fetch(`${this.url.replace("ws", "http")}/version`, { + headers: { Authorization: this.authorization, "User-Agent": this.manager.options.userAgent } + }) + // eslint-disable-next-line unicorn/no-await-expression-member + ).text(); + const versionRegex = + /^(?0|[1-9]\d*)\.(?0|[1-9]\d*)\.(?0|[1-9]\d*)(?:-(?(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][\dA-Za-z-]*))*))?(?:\+(?[\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?$/u; + + if (Number(versionRegex.exec(version)?.at(1) ?? 0) !== 4) unSupportedVersion = true; + } catch { + /* empty */ + } + + if (unSupportedVersion) throw new Error(`This node (${this.name}) is only supported for v4`); + + this.state = State.Connecting; + this.sessionId = await this.manager.redis?.get(RedisKey.NodeSession(this.name.toLowerCase())) ?? null; + + const headers: NonResumableHeaders | ResumableHeaders = { + "Client-Name": this.manager.options.userAgent, + "User-Agent": this.manager.options.userAgent, + "User-Id": this.manager.id, + Authorization: this.authorization + }; + + if (this.sessionId !== null) (headers as ResumableHeaders)["Session-Id"] = this.sessionId; + + this.manager.emit( + "debug", + `[WS => ${this.name}] Connecting ${this.url}, lavalink version: ${this.version}, trying to resume? ${Boolean( + this.sessionId + )}.` + ); + + if (!this.initialized) this.initialized = true; + + this.ws = new Websocket(new URL(`${this.url}${this.version}/websocket`), { + headers + } as Websocket.ClientOptions); + + this.ws.once("upgrade", this.open.bind(this)); + this.ws.once("close", this.close.bind(this)); + this.ws.on("error", this.error.bind(this)); + // eslint-disable-next-line promise/prefer-await-to-then, promise/prefer-await-to-callbacks + this.ws.on("message", async data => this.message(data).catch((error: unknown) => this.error(error as Error))); + + return undefined; + } + + /** + * Disconnect the from Lavalink Websocket. + * + * @param code Status code. + * @param reason Reason for the disconnect. + */ + public disconnect(code: number, reason?: string): void { + if (this.destroyed) return undefined; + + this.destroyed = true; + this.state = State.Disconnected; + + if (this.ws) this.ws.close(code, reason); + else void this.clean(); + + return undefined; + } + + /** + * Joins a voice channel. + * + * @param options The options to pass in connection creation. + * @returns The created new Player. + */ + public async joinVoiceChannel(options: VoiceChannelOptions): Promise { + if (this.manager.connections.has(options.guildId)) throw new Error("This guild already have an existing connection"); + + const connection = new VoiceConnection(this.manager, options); + + this.manager.connections.set(connection.guildId, connection); + + try { + await connection.connect(); + } catch (error) { + this.manager.connections.delete(options.guildId); + + throw error; + } + + try { + const player = new (this.manager.options.structures.player ?? Player)(connection.guildId, this); + + await player.sendServerUpdate(connection); + connection.on("connectionUpdate", async (state: VoiceState) => { + if (state !== VoiceState.SessionReady) return; + + const IDataCache = await this.manager.redis?.get(RedisKey.NodePlayers(player.node.name.toLowerCase())); + const dataCache = IDataCache === null ? [] : (JSON.parse(IDataCache ?? "") as VoiceChannelOptions[]); + const dataIndex = dataCache.indexOf(dataCache.find(({ guildId }) => guildId === connection.guildId)!); + + dataCache.at(dataIndex)!.guildId = connection.guildId; + dataCache.at(dataIndex)!.channelId = connection.channelId!; + dataCache.at(dataIndex)!.shardId = connection.shardId; + dataCache.at(dataIndex)!.deaf = connection.deafened; + dataCache.at(dataIndex)!.mute = connection.muted; + + await this.manager.redis?.set( + RedisKey.NodePlayers(player.node.name.toLowerCase()), + JSON.stringify(dataCache) + ); + + await player.sendServerUpdate(connection); + }); + + const IDataCache = await this.manager.redis?.get(RedisKey.NodePlayers(this.name.toLowerCase())); + const dataCache = IDataCache === null ? [] : (JSON.parse(IDataCache ?? "") as VoiceChannelOptions[]); + + if (!dataCache.some(({ guildId }) => guildId === options.guildId)) { + dataCache.push({ + guildId: options.guildId, + channelId: options.channelId, + shardId: options.shardId, + deaf: options.deaf ?? true, + mute: options.mute ?? false + }); + + await this.manager.redis?.set(RedisKey.NodePlayers(this.name.toLowerCase()), JSON.stringify(dataCache)); + } + + this.manager.players.set(player.guildId, player); + + return player; + } catch (error) { + connection.disconnect(); + this.manager.connections.delete(options.guildId); + + throw error; + } + } + + /** + * Leaves a voice channel. + * + * @param guildId The id of the guild you want to delete. + * @returns The destroyed / disconnected player or undefined if none. + */ + public async leaveVoiceChannel(guildId: string): Promise { + const connection = this.manager.connections.get(guildId); + const player = this.manager.players.get(guildId); + + if (connection) { + connection.disconnect(); + this.manager.connections.delete(guildId); + } + if (player) { + player.clean(); + + try { + await player.destroyPlayer(); + } catch { + /* empty */ + } + + this.manager.players.delete(guildId); + } + + const IDataCache = await this.manager.redis?.get(RedisKey.NodePlayers(this.name.toLowerCase())); + const dataCache = IDataCache === null ? [] : (JSON.parse(IDataCache ?? "") as VoiceChannelOptions[]); + + dataCache.splice(dataCache.indexOf(dataCache.find(({ guildId: id }) => id === guildId)!), 1); + + await this.manager.redis?.set(RedisKey.NodePlayers(this.name.toLowerCase()), JSON.stringify(dataCache)); + } + + /** + * Handle connection open event from the Lavalink Websocket. + * + * @param response Response from Lavalink Websocket. + * @private + * @internal + */ + private open(response: IncomingMessage): void { + const resumed = response.headers["session-resumed"] === "true"; + + this.manager.emit( + "debug", + `[WS => ${this.name}] Connection handshake done, upgrade headers resumed: ${resumed}.` + ); + + this.reconnects = 0; + this.state = State.Nearly; + } + + /** + * Handle message from the Lavalink Websocket. + * + * @param message JSON message. + * @private + * @internal + */ + // eslint-disable-next-line consistent-return + private async message(message: Websocket.RawData): Promise { + if (Array.isArray(message)) message = Buffer.concat(message); + if (message instanceof ArrayBuffer) message = Buffer.from(message); + + // eslint-disable-next-line typescript/no-base-to-string + const data = JSON.parse(message.toString()); + + // eslint-disable-next-line typescript/strict-boolean-expressions + if (!data) return undefined; + if (this.destroyed || this.state === State.Reconnecting) return undefined; + + this.manager.emit("raw", this.name, data); + + switch (data.op) { + case OpCodes.Stats: + delete data.op; + + this.stats = data; + + this.manager.emit( + "debug", + `[WS => ${this.name}] Node status update, server load of ${this.penalties}.` + ); + + break; + case OpCodes.Ready: { + this.state = State.Connected; + this.sessionId = data.sessionId; + + const players = [...this.manager.players.values()].filter(player => player.node.name === this.name); + const resumeByLibrary = Boolean( + this.initialized && this.manager.options.resumeByLibrary && players.length > 0 + ); + + this.manager.emit( + "debug", + `[WS => ${this.name}] Lavalink is ready, lavalink resume: ${data.resumed}, esbatu resume: ${resumeByLibrary}.` + ); + + if (resumeByLibrary) { + try { + const playersWithData: Player[] = []; + const playersWithoutData: Player[] = []; + + for (const player of this.manager.players.values()) { + const serverUpdate = this.manager.connections.get(player.guildId)?.serverUpdate; + + if (serverUpdate) playersWithData.push(player); + else playersWithoutData.push(player); + } + + await Promise.allSettled([ + ...playersWithData.map(async player => player.resumePlayer()), + ...playersWithoutData.map(async ({ guildId }) => this.leaveVoiceChannel(guildId)) + ]); + } catch (error) { + this.error(error as Error); + } + } + + if (this.manager.options.resume) { + try { + await this.manager.redis?.set(RedisKey.NodeSession(this.name.toLowerCase()), this.sessionId!); + await this.rest.updateSession(this.manager.options.resume, this.manager.options.resumeTimeout); + + // eslint-disable-next-line typescript/strict-boolean-expressions + if (data.resumed) { + const IDataCache = await this.manager.redis?.get( + RedisKey.NodePlayers(this.name.toLowerCase()) + ); + const dataCache = IDataCache === null ? [] : (JSON.parse(IDataCache ?? "") as VoiceChannelOptions[]); + + for (const { guildId, channelId, shardId, mute, deaf } of dataCache) { + const player = await this.joinVoiceChannel({ + guildId, + channelId, + shardId, + mute, + deaf + // eslint-disable-next-line typescript/no-empty-function + }).catch(() => {}); + + if (player) continue; + + dataCache.splice( + dataCache.indexOf(dataCache.find(({ guildId: id }) => id === guildId)!), + 1 + ); + + await this.manager.redis?.set( + RedisKey.NodePlayers(this.name.toLowerCase()), + JSON.stringify(dataCache) + ); + } + } + + this.manager.emit("debug", `[WS => ${this.name}] Resuming configured.`); + } catch (error) { + this.error(error as Error); + } + } + + this.manager.emit("ready", this.name, resumeByLibrary || data.resumed); + + break; + } + case OpCodes.Event: + case OpCodes.PlayerUpdate: { + const player = this.manager.players.get(data.guildId); + + if (!player) return undefined; + if (data.op === OpCodes.Event) player.onPlayerEvent(data); + else player.onPlayerUpdate(data); + + break; + } + default: + this.manager.emit("debug", `[WS => ${this.name}] Unknown opcodes message, type: ${data.op}.`); + } + } + + /** + * Handle closed event from the Lavalink Websocket. + * + * @param code Status close. + * @param reason Reason for connection close. + * @private + * @internal + */ + private close(code: number, reason: Buffer): void { + this.manager.emit("debug", `[WS => ${this.name}] Connection closed, code: ${code || "unknown"}.`); + this.manager.emit("close", this.name, code, reason.toString()); + + if (this.shouldClean) void this.clean(); + else this.reconnect(); + } + + /** + * To emit error events easily. + * + * @param error A error message. + * @private + * @internal + */ + private error(error: Error): void { + this.manager.emit("error", this.name, error); + } + + /** + * Destroys the Lavalink Websocket connection. + * + * @param count A total of players success to move another node. + * @private + * @internal + */ + private destroy(count: number = 0): void { + this.ws?.removeAllListeners(); + this.ws?.close(); + + this.ws = null; + this.sessionId = null; + this.state = State.Disconnected; + + if (!this.shouldClean) return undefined; + + this.destroyed = true; + + this.manager.emit("disconnect", this.name, count); + this.manager.nodes.delete(this.name); + + return undefined; + } + + /** + * Cleans and moves players to other nodes if possible. + * + * @private + * @internal + */ + private async clean(): Promise { + let count = 0; + + if (!this.manager.options.moveOnDisconnect) { this.destroy(count); return; } + + const players = [...this.manager.players.values()].filter(player => player.node.name === this.name); + + try { + const data = await Promise.allSettled(players.map(async player => player.movePlayer())); + + count = data.filter(results => results.status === "fulfilled").length; + } catch (error) { + this.error(error as Error); + } + + this.destroy(count); + } + + /** + * Reconnect to the Lavalink Websocket. + * + * @private + * @internal + */ + private reconnect(): void { + if (this.state === State.Reconnecting) return undefined; + if (this.state !== State.Disconnected) this.destroy(); + + this.state = State.Reconnecting; + this.reconnects++; + + this.manager.emit( + "reconnecting", + this.name, + this.manager.options.reconnectTries - this.reconnects, + this.manager.options.reconnectInterval + ); + this.manager.emit( + "debug", + `[WS => ${this.name}] Reconnecting in ${this.manager.options.reconnectInterval} seconds, ${ + this.manager.options.reconnectTries - this.reconnects + } tries left.` + ); + + setTimeout(async () => this.connect(), this.manager.options.reconnectInterval * 1_000); + + return undefined; + } } diff --git a/tsconfig.json b/tsconfig.json index a318484..d221dd3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,53 +1,53 @@ { - // Mapped from https://www.typescriptlang.org/tsconfig - "compilerOptions": { - // Type Checking - "allowUnreachableCode": false, - "allowUnusedLabels": false, - "exactOptionalPropertyTypes": false, - "noFallthroughCasesInSwitch": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noPropertyAccessFromIndexSignature": false, - "noUncheckedIndexedAccess": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "strict": true, + // Mapped from https://www.typescriptlang.org/tsconfig + "compilerOptions": { + // Type Checking + "allowUnreachableCode": false, + "allowUnusedLabels": false, + "exactOptionalPropertyTypes": false, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": false, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true, - // Modules - "allowArbitraryExtensions": false, - "allowImportingTsExtensions": false, - "module": "ESNext", - "moduleResolution": "Bundler", - "resolveJsonModule": true, - "resolvePackageJsonExports": true, - "resolvePackageJsonImports": true, + // Modules + "allowArbitraryExtensions": false, + "allowImportingTsExtensions": false, + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "resolvePackageJsonExports": true, + "resolvePackageJsonImports": true, - // Emit - "declaration": true, - "declarationMap": true, - "importHelpers": false, - "newLine": "lf", - "noEmitHelpers": true, - "outDir": "dist", - "preserveConstEnums": true, - "removeComments": false, - "rootDir": "src", - "sourceMap": true, + // Emit + "declaration": true, + "declarationMap": true, + "importHelpers": false, + "newLine": "lf", + "noEmitHelpers": true, + "outDir": "dist", + "preserveConstEnums": true, + "removeComments": false, + "rootDir": "src", + "sourceMap": true, - // Language and Environment - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": ["ESNext"], - "target": "ESNext", - "useDefineForClassFields": true, + // Language and Environment + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["ESNext"], + "target": "ESNext", + "useDefineForClassFields": true, - // Interop Constraints - "allowSyntheticDefaultImports": true, - "esModuleInterop": false, - "forceConsistentCasingInFileNames": true, - "isolatedModules": true - }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules"] + // Interop Constraints + "allowSyntheticDefaultImports": true, + "esModuleInterop": false, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules"] } diff --git a/tsup-config.json b/tsup-config.json index 9d00640..d7c9cf1 100644 --- a/tsup-config.json +++ b/tsup-config.json @@ -1,22 +1,22 @@ { - "entry": ["src/index.ts"], - "platform": "node", - "format": ["esm", "cjs"], - "target": "es2022", - "skipNodeModulesBundle": true, - "clean": true, - "shims": true, - "cjsInterop": true, - "minify": false, - "terserOptions": { - "mangle": false, - "keep_classnames": true, - "keep_fnames": true - }, - "splitting": false, - "keepNames": true, - "dts": true, - "sourcemap": true, - "treeshake": false, - "outDir": "dist" + "entry": ["src/index.ts"], + "platform": "node", + "format": ["esm", "cjs"], + "target": "es2022", + "skipNodeModulesBundle": true, + "clean": true, + "shims": true, + "cjsInterop": true, + "minify": false, + "terserOptions": { + "mangle": false, + "keep_classnames": true, + "keep_fnames": true + }, + "splitting": false, + "keepNames": true, + "dts": true, + "sourcemap": true, + "treeshake": false, + "outDir": "dist" }