diff --git a/.editorconfig b/.editorconfig index 916e2e5..64f36f6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,9 +5,9 @@ charset = utf-8 end_of_line = lf trim_trailing_whitespace = true insert_final_newline = true -indent_style = space -indent_size = 2 +indent_style = tab +indent_size = 4 quote_type = single [Makefile] -indent_style = space +indent_style = tab diff --git a/.gitignore b/.gitignore index ece695a..656d096 100644 --- a/.gitignore +++ b/.gitignore @@ -1,63 +1,5 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -package-lock.json - -# Eater asked for this dunno why -bot/ -apps/ - -# Enviorment -.env - -# bun -bun-test.js - -# NPM -npm/ - -# DOCS -docs.json -packages/core/docs.json - -# dependencies +pnpm-lock.yaml node_modules -.pnp -.pnp.js -.vscode - -# testing -coverage - -# node -out/ +lib/ dist/ -build -package-lock.json - -# misc -.DS_Store -*.pem -*.vs - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# local env files -.env.local -.env.development.local -.env.test.local -.env.production.local -.env - -# turbo -.turbo - -# tests -__tests__ __test__ - -# changeset -.changeset diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000..0312b76 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +npx lint-staged \ No newline at end of file diff --git a/.swcrc b/.swcrc new file mode 100644 index 0000000..c656cc0 --- /dev/null +++ b/.swcrc @@ -0,0 +1,30 @@ +{ + "sourceMaps": false, + "module": { + "type": "commonjs", + "strictMode": true, + "noInterop": false + }, + "jsc": { + "externalHelpers": false, + "target": "esnext", + "parser": { + "syntax": "typescript", + "tsx": true, + "decorators": true, + "dynamicImport": true + }, + "transform": { + "legacyDecorator": true, + "decoratorMetadata": true, + "react": { + "throwIfNamespace": false, + "useBuiltins": false, + "pragma": "React.createElement", + "pragmaFrag": "React.Fragment", + "importSource": "react" + } + }, + "keepClassNames": true + } +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..70edba8 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "biomejs.biome", + "orta.vscode-twoslash-queries", + "eamodio.gitlens", + "yoavbls.pretty-ts-errors" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..00ad71f --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib" +} \ No newline at end of file diff --git a/README.md b/README.md index a4cee95..ef3b7d6 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,57 @@ -# biscuit +
-## A brand new bleeding edge non bloated Discord library + # **Seyfert** -biscuit + seyfert -## Install (for [node18](https://nodejs.org/en/download/)) + **A brand new bleeding edge non bloated Discord framework** -```sh-session -npm install @biscuitland/core -yarn add @biscuitland/core + [![License](https://img.shields.io/npm/l/seyfert?style=flat-square&logo=apache&color=white)](https://github.com/tiramisulabs/biscuit/blob/main/LICENSE) + [![Version](https://img.shields.io/npm/v/seyfert?color=%23ff0000&logo=npm&style=flat-square)](https://www.npmjs.com/package/seyfert) + [![Discord](https://img.shields.io/discord/1003825077969764412?color=%23406da2&label=support&logo=discord&style=flat-square)](https://discord.com/invite/XNw2RZFzaP) + +
+ +> [!WARNING] +> This readme is work in progress! + +# FAQ +## So, what is `seyfert`? +Seyfert is the ultimate Discord framework! With its highly efficient interaction with the Discord API, you can achieve anything you set your mind to. + +## Why I should use it? +Seyfert has a good scalability, strict types, smooth developing experience... + +> more questions soon... + +# User guide +## Installation +> [!NOTE] +> You **NEED** Node.js 18>= for this to work, also we recomended Node.js 20 LTS and Bun latest +```sh +pnpm add seyfert ``` -for further reading join our [Discord](https://discord.com/invite/XNw2RZFzaP) +> You may use your preferred package manager, for this example I am using PNPM since is more efficient. -## Most importantly, biscuit: -Stands apart from other libraries like Discord.js or Eris as it takes a conscious and dedicated approach, adhering strictly to [simplicity](https://en.wikipedia.org/wiki/Unix_philosophy). We have examined the features and functionalities that contribute to [bloat](https://en.wikipedia.org/wiki/Code_bloat) in libraries, intentionally removing unnecessary complexities we deliver a [minimalistic](https://en.wikipedia.org/wiki/Minimalism_(computing)) and efficient solution that includes only essential components for Discord API interaction, reducing the library's footprint and enabling scalability. - -High RAM usage in other libraries often arises due to unnecessary features and functionalities and suboptimal caching mechanisms tied to the core library. - -### Leveraging the power of meta programming -The Proxy object enables dynamic, flexible and efficient calls to the API, it is typesafe due to TypeScript wizardry, meta programming is not for the weak minded. - -## Why biscuit?: -- Remarkably minimal memory footprint -- Scalable -- Non feature-rich! - -## Example bot (TS/JS) +## Basic bot example ```ts -import { Session } from '@biscuitland/core'; -import { GatewayIntentBits, InteractionType, InteractionResponseType } from '@biscuitland/common'; +import { Client } from 'seyfert'; -const session = new Session({ - intents: GatewayIntentBits.Guilds, - token: 'your token goes here' -}); +const client = new Client(); -const commands = [ - { - name: 'ping', - description: 'Replies with pong!' - } -]; - -session.once('READY', (payload) => { - const username = payload.user.username; - console.log('Logged in as: %s', username); - session.managers.applications.bulkCommands(session.applicationId, commands); -}); - -session.on('INTERACTION_CREATE', (interaction) => { - if (interaction.type !== InteractionType.ApplicationCommand) return; - session.managers.interactions.reply(interaction.id, interaction.token, { - type: InteractionResponseType.ChannelMessageWithSource, - data: { content: 'pong!' } - }); -}); - -session.start(); +(async () => { + await client.start(); + await client.uploadCommands().catch(e => { + console.error(JSON.stringify(e, null, 2)) + process.exit(1) + }) +})(); ``` -## Links -* [Website](https://biscuitjs.com/) -* [Documentation](https://docs.biscuitjs.com/) -* [Discord](https://discord.gg/XNw2RZFzaP) -* [core](https://www.npmjs.com/package/@biscuitland/core) | [rest](https://www.npmjs.com/package/@biscuitland/rest) | [ws](https://www.npmjs.com/package/@biscuitland/ws) | [helpers](https://www.npmjs.com/package/@biscuitland/helpers) +# Useful links + +- [GitHub Repository](https://github.com/tiramisulabs/biscuit) +- [Discord server](https://discord.com/invite/XNw2RZFzaP) +- [npm - core](https://www.npmjs.com/package/seyfert) diff --git a/assets/icon.png b/assets/icon.png index f122d29..9eb27ea 100644 Binary files a/assets/icon.png and b/assets/icon.png differ diff --git a/assets/icon.svg b/assets/icon.svg index ab9169a..3b3e043 100644 --- a/assets/icon.svg +++ b/assets/icon.svg @@ -1,75 +1,345 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/biome.json b/biome.json index becafb4..8fa12e4 100644 --- a/biome.json +++ b/biome.json @@ -1,35 +1,75 @@ { + "$schema": "https://biomejs.dev/schemas/1.5.0/schema.json", "linter": { "enabled": true, "rules": { "all": true, - "style": { - "useWhile": "off", - "noNonNullAssertion": "off" - }, "suspicious": { "noExplicitAny": "off", - "noAssignInExpressions": "off" + "noAssignInExpressions": "off", + "noUnsafeDeclarationMerging": "off", + "noRedeclare": "off", + "noEmptyInterface": "off", + "noConfusingVoidType": "off", + "noImplicitAnyLet": "off" + }, + "style": { + "noNonNullAssertion": "off", + "noParameterAssign": "off" + }, + "correctness": { + "noUnusedVariables": "off" + }, + "nursery": { + "useExportType": "error", + "useImportType": "error", + "useNodejsImportProtocol": "error", + "noUselessLoneBlockStatements": "warn", + "noUselessTernary": "error", + "noEmptyBlockStatements": "off" + }, + "complexity": { + "noBannedTypes": "off", + "noForEach": "off", + "noUselessConstructor": "off", + "noThisInStatic": "off" + }, + "a11y": { + "all": false + }, + "performance": { + "noDelete": "off" } } }, + "json": { + "formatter": { + "enabled": true, + "indentWidth": 2, + "lineWidth": 80 + } + }, "formatter": { "enabled": true, "indentWidth": 2, - "indentStyle": "space", - "lineWidth": 140, + "indentStyle": "tab", + "lineWidth": 120, + "lineEnding": "crlf", "formatWithErrors": true }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "arrowParentheses": "asNeeded", + "bracketSameLine": true, + "semicolons": "always" + } + }, "files": { - "ignore": [ - "node_modules/", - "build", - "dist", - "tsup.config.ts", - "__test__" - ] + "ignoreUnknown": true, + "ignore": ["node_modules/", "build", "lib", "__test__"] }, "organizeImports": { - "enabled": true + "enabled": false } } diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index b6ae1ed..0000000 Binary files a/bun.lockb and /dev/null differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..54a3062 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2688 @@ +{ + "name": "seyfert", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "seyfert", + "version": "0.1.0", + "license": "ISC", + "dependencies": { + "chokidar": "^3.5.3", + "discord-api-types": "^0.37.71", + "magic-bytes.js": "^1.7.0", + "ts-mixer": "^6.0.3", + "ws": "^8.16.0" + }, + "devDependencies": { + "@biomejs/biome": "1.5.0", + "@swc/cli": "^0.1.63", + "@swc/core": "^1.3.102", + "@types/node": "^20.10.7", + "@types/ws": "^8.5.10", + "husky": "^8.0.3", + "lint-staged": "^15.2.2", + "typescript": "^5.3.3" + }, + "optionalDependencies": { + "ioredis": "^5.3.2", + "tweetnacl": "^1.0.3", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.39.0" + } + }, + "node_modules/@biomejs/biome": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.5.0.tgz", + "integrity": "sha512-ln+o5jbs109qpeDoA+5n+vlAPai3DhlK0tHtZXzQvu4tswFgxNiJCeIXmlW1DYHziTmtBImV3Y0uhbm2iVSE3Q==", + "dev": true, + "hasInstallScript": true, + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "1.5.0", + "@biomejs/cli-darwin-x64": "1.5.0", + "@biomejs/cli-linux-arm64": "1.5.0", + "@biomejs/cli-linux-arm64-musl": "1.5.0", + "@biomejs/cli-linux-x64": "1.5.0", + "@biomejs/cli-linux-x64-musl": "1.5.0", + "@biomejs/cli-win32-arm64": "1.5.0", + "@biomejs/cli-win32-x64": "1.5.0" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.5.0.tgz", + "integrity": "sha512-3+D7axf04dpadGMOaqb2q+zyQnhWW0o/Imt7TJBWsoE0N3/+28Wht8g3UEHHcUL5FPuGIfsE+NcYntBaaAsEIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.5.0.tgz", + "integrity": "sha512-8k5aaLWE/B6ZAXLC+z/Vwh9ogyiSaiRIfvg+F9foxuneHl2R/D/2Iy7pvd3Yoi4Kf6/MBdowekPVezGP4/Kbcw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.5.0.tgz", + "integrity": "sha512-RiecxG71E1jnqiJZ3FaikVBDRkk2ohIxBo0O4o68g87y6Hug//G0S83sj6Wqyn8DgKMCRWQg+XYMgk5CwLVowA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.5.0.tgz", + "integrity": "sha512-+1B3J8tWLTOvP3+00Cap+XhEXMvxwCHvVfuywUsB7Sqd66NWic3wKJuGbGcS3PuCWtGuIFsiQMNAGqiOXG4uBQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.5.0.tgz", + "integrity": "sha512-TlTsG+ptSmnDTUsAAYsXyGOXMcFiF8SiwhPdj4YsNkJRgx9M2curEVcTVm66FINIPK6VJTUcEDahFlx3NPUOzA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.5.0.tgz", + "integrity": "sha512-4S2rLluc0WT+XTbLTgcm9+5EEFwJmoGiUEzR6N0P2sIjZD8c5KNf9Ou46BP1Pdg5AgqV+IIClGPK1I80ApSh1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.5.0.tgz", + "integrity": "sha512-sWOi1SR+YqJuXElBncGRnWBR7IN7ni6GQY4Zm/vTpP6nVA0dX5C301eQUW1N/VnFQb6fyrJTcBslDUKyemsN/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.5.0.tgz", + "integrity": "sha512-OoqgUXyzmRwX466bklOsWS7WdcvWtBuxF94DXATNe7bUiBa2tlW8QX7VVZvPnMKH57E5J619AkB3b5fhzyUhXA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.*" + } + }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==", + "optional": true + }, + "node_modules/@mole-inc/bin-wrapper": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", + "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", + "dev": true, + "dependencies": { + "bin-check": "^4.1.0", + "bin-version-check": "^5.0.0", + "content-disposition": "^0.5.4", + "ext-name": "^5.0.0", + "file-type": "^17.1.6", + "filenamify": "^5.0.2", + "got": "^11.8.5", + "os-filter-obj": "^2.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@swc/cli": { + "version": "0.1.65", + "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.65.tgz", + "integrity": "sha512-4NcgsvJVHhA7trDnMmkGLLvWMHu2kSy+qHx6QwRhhJhdiYdNUrhdp+ERxen73sYtaeEOYeLJcWrQ60nzKi6rpg==", + "dev": true, + "dependencies": { + "@mole-inc/bin-wrapper": "^8.0.1", + "commander": "^7.1.0", + "fast-glob": "^3.2.5", + "minimatch": "^9.0.3", + "semver": "^7.3.8", + "slash": "3.0.0", + "source-map": "^0.7.3" + }, + "bin": { + "spack": "bin/spack.js", + "swc": "bin/swc.js", + "swcx": "bin/swcx.js" + }, + "engines": { + "node": ">= 12.13" + }, + "peerDependencies": { + "@swc/core": "^1.2.66", + "chokidar": "^3.5.1" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@swc/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.4.5.tgz", + "integrity": "sha512-4/JGkG4b1Z/QwCGgx+Ub46MlzrsZvBk5JSkxm9PcZ4bSX81c+4Y94Xm3iLp5Ka8NxzS5rD4mJSpcYuN3Tw0ceg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@swc/counter": "^0.1.2", + "@swc/types": "^0.1.5" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.4.5", + "@swc/core-darwin-x64": "1.4.5", + "@swc/core-linux-arm-gnueabihf": "1.4.5", + "@swc/core-linux-arm64-gnu": "1.4.5", + "@swc/core-linux-arm64-musl": "1.4.5", + "@swc/core-linux-x64-gnu": "1.4.5", + "@swc/core-linux-x64-musl": "1.4.5", + "@swc/core-win32-arm64-msvc": "1.4.5", + "@swc/core-win32-ia32-msvc": "1.4.5", + "@swc/core-win32-x64-msvc": "1.4.5" + }, + "peerDependencies": { + "@swc/helpers": "^0.5.0" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.5.tgz", + "integrity": "sha512-toMSkbByHNfGXESyY1aiq5L3KutgijrNWB/THgdHIA1aIbwtrgMdFQfxpSE+INuuvWYi/Fxarv86EnU7ewbI0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.4.5.tgz", + "integrity": "sha512-LN8cbnmb4Gav8UcbBc+L/DEthmzCWZz22rQr6fIEHMN+f0d71fuKnV0ca0hoKbpZn33dlzUmXQE53HRjlRUQbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.5.tgz", + "integrity": "sha512-suRFkhBWmOQxlM4frpos1uqjmHfaEI8FuJ0LL5+yRE7IunNDeQJBKujGZt6taeuxo1KqC0N0Ajr8IluN2wrKpA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.5.tgz", + "integrity": "sha512-mLKxasQArDGmR6k9c0tkPVUdoo8VfUecocMG1Mx9NYvpidJNaZ3xq9nYM77v7uq1fQqrs/59DM1fJTNRWvv/UQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.5.tgz", + "integrity": "sha512-pgKuyRP7S29U/HMDTx+x8dFcklWxwB9cHFNCNWSE6bS4vHR93jc4quwPX9OEQX5CVHxm+c8+xof043I4OGkAXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.5.tgz", + "integrity": "sha512-srR+YN86Oerzoghd0DPCzTbTp08feeJPSr9kkNdmtQWENOa4l/9cJV3+XY6vviw0sEjezPmYnc3SwRxJRaxvEw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.5.tgz", + "integrity": "sha512-aSf41LZtDeG5VXI4RCnzcu0UInPyNm3ip8Kw+sCK+sSqW9o7DgBkyqqbip3RZq84fNUHBQQQQdKXetltsyRRqw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.5.tgz", + "integrity": "sha512-vU3k8JwRUlTkJMfJQY9E4VvLrsIFOpfhnvbuXB84Amo1cJsz+bYQcC6RSvY7qpaDzDKFdUGbJco4uZTRoRf7Mg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.5.tgz", + "integrity": "sha512-856YRh3frRK2XbrSjDOFBgoAqWJLNRkaEtfGzXfeEoyJlOz0BFsSJHxKlHAFkxRfHe2li9DJRUQFTEhXn4OUWw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.5.tgz", + "integrity": "sha512-j1+kV7jmWY1+NbXAvxAEW165781yLXVZKLcoXIZKmw18EatqMF6w8acg1gDG8C+Iw5aWLkRZVS4pijSh7+DtCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true + }, + "node_modules/@swc/types": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.5.tgz", + "integrity": "sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==", + "dev": true + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "dev": true + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ansi-escapes": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", + "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "dev": true, + "dependencies": { + "type-fest": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bin-check": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", + "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", + "dev": true, + "dependencies": { + "execa": "^0.7.0", + "executable": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bin-version": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", + "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "find-versions": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version-check": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.1.0.tgz", + "integrity": "sha512-bYsvMqJ8yNGILLz1KP9zKLzQ6YpljV3ln1gqhuLkUtyfGi3qXKGuK2p+U4NAvjVFzDFiBBtOpCOSFNuYYEGZ5g==", + "dev": true, + "dependencies": { + "bin-version": "^6.0.0", + "semver": "^7.5.3", + "semver-truncate": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/bin-version/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/bin-version/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bin-version/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bin-version/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", + "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", + "dev": true, + "dependencies": { + "slice-ansi": "^5.0.0", + "string-width": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "devOptional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "optional": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/discord-api-types": { + "version": "0.37.71", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.71.tgz", + "integrity": "sha512-oYDVWoiQdblr9DpwOgpi5d78dVhPcoN9YZCCqYZf2T0v9+iICs7k2bYGumoHuYMtaIitpp5aQNs+2guVkgjbOA==" + }, + "node_modules/emoji-regex": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", + "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, + "node_modules/execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "dependencies": { + "mime-db": "^1.28.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "dependencies": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-type": { + "version": "17.1.6", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", + "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", + "dev": true, + "dependencies": { + "readable-web-to-node-stream": "^3.0.2", + "strtok3": "^7.0.0-alpha.9", + "token-types": "^5.0.0-alpha.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/filename-reserved-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", + "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filenamify": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", + "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^3.0.0", + "strip-outer": "^2.0.0", + "trim-repeated": "^2.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-versions": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", + "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", + "dev": true, + "dependencies": { + "semver-regex": "^4.0.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", + "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true, + "bin": { + "husky": "lib/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ioredis": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", + "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==", + "optional": true, + "dependencies": { + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", + "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/lint-staged": { + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", + "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", + "dev": true, + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "3.0.0", + "listr2": "8.0.1", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/lint-staged/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/lint-staged/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/lint-staged/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/lint-staged/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/lint-staged/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lint-staged/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lint-staged/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lint-staged/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/lint-staged/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lint-staged/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/listr2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", + "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", + "dev": true, + "dependencies": { + "cli-truncate": "^4.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.0.0", + "rfdc": "^1.3.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "optional": true + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "optional": true + }, + "node_modules/log-update": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", + "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^7.0.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", + "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", + "dev": true, + "dependencies": { + "get-east-asian-width": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", + "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/magic-bytes.js": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.10.0.tgz", + "integrity": "sha512-/k20Lg2q8LE5xiaaSkMXk4sfvI+9EGEykFS4b0CHHGWqDYU0bGUFSwchNOMA56D7TCs9GwVTkqe9als1/ns8UQ==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "devOptional": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-filter-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", + "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", + "dev": true, + "dependencies": { + "arch": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/peek-readable": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", + "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dev": true, + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "optional": true, + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", + "dev": true + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-truncate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-3.0.0.tgz", + "integrity": "sha512-LJWA9kSvMolR51oDE6PN3kALBNaUdkxzAGcexw8gjMA8xr5zUqK0JiR3CgARSqanYF3Z1YHvsErb1KDgh+v7Rg==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", + "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.0.0", + "is-fullwidth-code-point": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", + "dev": true, + "dependencies": { + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "optional": true + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", + "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", + "dev": true, + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-outer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", + "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strtok3": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", + "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", + "dev": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/token-types": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", + "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", + "dev": true, + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/trim-repeated": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", + "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^5.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-mixer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ts-mixer/-/ts-mixer-6.0.4.tgz", + "integrity": "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==" + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "optional": true + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uWebSockets.js": { + "version": "20.39.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#ec37cb6444a284c4a0a8d50041a23a4bac9e5715", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", + "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/package.json b/package.json index cb3ab1b..2620ca5 100644 --- a/package.json +++ b/package.json @@ -1,70 +1,74 @@ { - "name": "@biscuitland/core", - "workspaces": [ - "packages/*" - ], - "scripts": { - "build": "turbo run build", - "clean": "turbo run clean", - "check": "biome check ./packages/", - "check:apply": "biome check --apply --max-diagnostics 200 --quote-style single --trailing-comma none ./packages/", - "lint": "biome format --write --quote-style single --trailing-comma none ./packages/", - "dev": "turbo run dev --parallel" - }, - "engines": { - "npm": ">=7.0.0", - "node": ">=16.0.0" - }, - "devDependencies": { - "@biomejs/biome": "^1.3.3", - "@changesets/cli": "^2.24.1", - "@types/node": "^20.0.0", - "turbo": "^1.4.2", - "typescript": "^5.0.4" - }, - "packageManager": "npm@8.19.4", - "bugs": { - "url": "https://github.com/oasisjs/biscuit" - }, - "keywords": [ - "api", - "discord", - "bots", - "typescript", - "botdev" - ], - "license": "Apache-2.0", - "author": "Yuzuru ", - "contributors": [ - { - "name": "Yuzuru", - "url": "https://github.com/yuzudev", - "author": true - }, - { - "name": "miia", - "url": "https://github.com/dragurimu" - }, - { - "name": "n128", - "url": "https://github.com/nicolito128" - }, - { - "name": "socram03", - "url": "https://github.com/socram03" - }, - { - "name": "Drylozu", - "url": "https://github.com/Drylozu" - }, - { - "name": "FreeAoi", - "url": "https://github.com/FreeAoi" - } - ], - "homepage": "https://biscuitjs.com", - "repository": { - "type": "git", - "url": "git+https://github.com/oasisjs/biscuit.git" - } -} + "name": "seyfert", + "version": "0.1.0", + "main": "./lib/index.js", + "module": "./lib/index.js", + "types": "./lib/index.d.ts", + "files": [ + "lib/**" + ], + "scripts": { + "build": "tsc --outDir ./lib", + "dev": "swc src -d lib -w", + "prepublishOnly": "npm run build", + "prepare": "npm run build && husky install", + "lint": "biome lint --apply ./src", + "format": "biome format --write ./src", + "check-h": "biome check --apply ./src", + "check": "biome check --apply --changed --no-errors-on-unmatched ./src" + }, + "author": "MARCROCK22", + "license": "ISC", + "dependencies": { + "chokidar": "^3.5.3", + "discord-api-types": "^0.37.71", + "magic-bytes.js": "^1.7.0", + "ts-mixer": "^6.0.3", + "ws": "^8.16.0" + }, + "lint-staged": { + "*.ts": [ + "biome check --apply", + "biome format --write" + ] + }, + "devDependencies": { + "lint-staged": "^15.2.2", + "@biomejs/biome": "1.5.0", + "@swc/cli": "^0.1.63", + "@swc/core": "^1.3.102", + "@types/node": "^20.10.7", + "@types/ws": "^8.5.10", + "husky": "^8.0.3", + "typescript": "^5.3.3" + }, + "optionalDependencies": { + "ioredis": "^5.3.2", + "tweetnacl": "^1.0.3", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.39.0" + }, + "homepage": "https://biscuitjs.com", + "repository": { + "type": "git", + "url": "git+https://github.com/tiramisulabs/biscuit.git" + }, + "bugs": { + "url": "https://github.com/tiramisulabs/biscuit" + }, + "keywords": [ + "api", + "discord", + "bots", + "typescript", + "botdev" + ], + "publishConfig": { + "access": "public" + }, + "contributors": [ + { + "name": "socram03", + "url": "https://github.com/socram03" + } + ] +} \ No newline at end of file diff --git a/packages/common/CHANGELOG.md b/packages/common/CHANGELOG.md deleted file mode 100644 index 7f694c2..0000000 --- a/packages/common/CHANGELOG.md +++ /dev/null @@ -1,31 +0,0 @@ -# @biscuitland/common - -## 0.0.8 - -### Patch Changes - -- idk - -## 0.0.7 - -### Patch Changes - -- fix the silly logger and other silly things affected by this bug - -## 0.0.6 - -### Patch Changes - -- I meessed up - -## 0.0.5 - -### Patch Changes - -- fix: logger on every module - -## 0.0.4 - -### Patch Changes - -- first 3.0.\* without bugs diff --git a/packages/common/README.md b/packages/common/README.md deleted file mode 100644 index b7813fb..0000000 --- a/packages/common/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# @biscuitland/common -## Most importantly, biscuit's common is: -Custom types, functions and utility classes, a feature-rich package for sharing in the biscuit libraries - -[](https://github.com/oasisjs/biscuit) -[](https://discord.gg/XNw2RZFzaP) - -biscuit - -## Install (for [node18](https://nodejs.org/en/download/)) - -```sh-session -npm install @biscuitland/common -yarn add @biscuitland/common -``` -## Links -* [Website](https://biscuitjs.com/) -* [Documentation](https://docs.biscuitjs.com/) -* [Discord](https://discord.gg/XNw2RZFzaP) -* [core](https://www.npmjs.com/package/@biscuitland/core) | [rest](https://www.npmjs.com/package/@biscuitland/rest) | [ws](https://www.npmjs.com/package/@biscuitland/ws) | [helpers](https://www.npmjs.com/package/@biscuitland/helpers) diff --git a/packages/common/package.json b/packages/common/package.json deleted file mode 100644 index 2546ec1..0000000 --- a/packages/common/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "@biscuitland/common", - "version": "0.0.10", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "type": "module", - "types": "./dist/index.d.ts", - "files": [ - "dist/**" - ], - "scripts": { - "build": "tsup", - "clean": "rm -rf dist && rm -rf .turbo", - "dev": "tsup --watch" - }, - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "require": "./dist/index.cjs" - } - }, - "devDependencies": { - "tsup": "^7.0.0" - }, - "license": "Apache-2.0", - "author": "Yuzuru ", - "contributors": [ - { - "name": "Yuzuru", - "url": "https://github.com/yuzudev" - }, - { - "name": "miia", - "url": "https://github.com/dragurimu" - }, - { - "name": "n128", - "url": "https://github.com/nicolito128" - }, - { - "name": "socram03", - "url": "https://github.com/socram03", - "author": true - }, - { - "name": "Drylozu", - "url": "https://github.com/Drylozu" - } - ], - "homepage": "https://biscuitjs.com", - "repository": { - "type": "git", - "url": "git+https://github.com/oasisjs/biscuit.git" - }, - "bugs": { - "url": "https://github.com/oasisjs/biscuit" - }, - "keywords": [ - "api", - "discord", - "bots", - "typescript", - "botdev" - ], - "publishConfig": { - "access": "public" - }, - "dependencies": { - "discord-api-types": "^0.37.39" - } -} diff --git a/packages/common/src/Collection.ts b/packages/common/src/Collection.ts deleted file mode 100644 index 48bf42b..0000000 --- a/packages/common/src/Collection.ts +++ /dev/null @@ -1,165 +0,0 @@ -// https://github.com/discordeno/discordeno/blob/main/packages/utils/src/Collection.ts -export class Collection extends Map { - /** - * The maximum amount of items allowed in this collection. To disable cache, set it 0, set to undefined to make it infinite. - * @default undefined - */ - maxSize: number | undefined; - /** Handler to remove items from the collection every so often. */ - sweeper: (CollectionSweeper & { intervalId?: NodeJS.Timeout }) | undefined; - - constructor(entries?: (ReadonlyArray | null) | Map, options?: CollectionOptions) { - super(entries ?? []); - - this.maxSize = options?.maxSize; - - if (!options?.sweeper) return; - - this.startSweeper(options.sweeper); - } - - startSweeper(options: CollectionSweeper): NodeJS.Timer { - if (this.sweeper?.intervalId) clearInterval(this.sweeper.intervalId); - - this.sweeper = options; - this.sweeper.intervalId = setInterval(() => { - // biome-ignore lint/complexity/noForEach: - this.forEach((value, key) => { - if (!this.sweeper?.filter(value, key)) return; - - this.delete(key); - return key; - }); - }, options.interval); - - return this.sweeper.intervalId; - } - - stopSweeper(): void { - clearInterval(this.sweeper?.intervalId); - } - - changeSweeperInterval(newInterval: number): void { - if (this.sweeper == null) return; - - this.startSweeper({ filter: this.sweeper.filter, interval: newInterval }); - } - - changeSweeperFilter(newFilter: (value: V, key: K) => boolean): void { - if (this.sweeper == null) return; - - this.startSweeper({ filter: newFilter, interval: this.sweeper.interval }); - } - - /** Add an item to the collection. Makes sure not to go above the maxSize. */ - set(key: K, value: V): this { - // When this collection is maxSized make sure we can add first - if ((this.maxSize !== undefined || this.maxSize === 0) && this.size >= this.maxSize) { - return this; - } - - return super.set(key, value); - } - - /** Add an item to the collection, no matter what the maxSize is. */ - forceSet(key: K, value: V): this { - return super.set(key, value); - } - - /** Convert the collection to an array. */ - array(): V[] { - return [...this.values()]; - } - - /** Retrieve the value of the first element in this collection. */ - first(): V | undefined { - return this.values().next().value; - } - - /** Retrieve the value of the last element in this collection. */ - last(): V | undefined { - return [...this.values()][this.size - 1]; - } - - /** Retrieve the value of a random element in this collection. */ - random(): V | undefined { - const array = [...this.values()]; - return array[Math.floor(Math.random() * array.length)]; - } - - /** Find a specific element in this collection. */ - find(callback: (value: V, key: K) => boolean): NonNullable | undefined { - for (const key of this.keys()) { - const value = this.get(key)!; - if (callback(value, key)) return value; - } - return undefined; - } - - /** Find all elements in this collection that match the given pattern. */ - filter(callback: (value: V, key: K) => boolean): Collection { - const relevant = new Collection(); - // biome-ignore lint/complexity/noForEach: - this.forEach((value, key) => { - if (callback(value, key)) relevant.set(key, value); - }); - - return relevant; - } - - /** Converts the collection into an array by running a callback on all items in the collection. */ - map(callback: (value: V, key: K) => T): T[] { - const results = []; - for (const key of this.keys()) { - const value = this.get(key)!; - results.push(callback(value, key)); - } - return results; - } - - /** Check if one of the items in the collection matches the pattern. */ - some(callback: (value: V, key: K) => boolean): boolean { - for (const key of this.keys()) { - const value = this.get(key)!; - if (callback(value, key)) return true; - } - - return false; - } - - /** Check if all of the items in the collection matches the pattern. */ - every(callback: (value: V, key: K) => boolean): boolean { - for (const key of this.keys()) { - const value = this.get(key)!; - if (!callback(value, key)) return false; - } - - return true; - } - - /** Runs a callback on all items in the collection, merging them into a single value. */ - reduce(callback: (accumulator: T, value: V, key: K) => T, initialValue?: T): T { - let accumulator: T = initialValue!; - - for (const key of this.keys()) { - const value = this.get(key)!; - accumulator = callback(accumulator, value, key); - } - - return accumulator; - } -} - -export interface CollectionOptions { - /** Handler to clean out the items in the collection every so often. */ - sweeper?: CollectionSweeper; - /** The maximum number of items allowed in the collection. */ - maxSize?: number; -} - -export interface CollectionSweeper { - /** The filter to determine whether an element should be deleted or not */ - filter: (value: V, key: K, ...args: any[]) => boolean; - /** The interval in which the sweeper should run */ - interval: number; -} diff --git a/packages/common/src/Constants.ts b/packages/common/src/Constants.ts deleted file mode 100644 index 78152c2..0000000 --- a/packages/common/src/Constants.ts +++ /dev/null @@ -1,20 +0,0 @@ -export const DiscordEpoch = 14200704e5; - -export const API_VERSION = '10'; - -export const BASE_URL = `/api/v${API_VERSION}`; -export const BASE_HOST = 'https://discord.com'; - -export const CDN_URL = 'https://cdn.discordapp.com'; - -export const GATEWAY_BASE_URL = 'wss://gateway.discord.gg/?v=10&encoding=json'; - -export const OK_STATUS_CODES = [200, 201, 204, 304]; - -export enum HTTPMethods { - Delete = 'DELETE', - Get = 'GET', - Patch = 'PATCH', - Post = 'POST', - Put = 'PUT' -} diff --git a/packages/common/src/Logger.ts b/packages/common/src/Logger.ts deleted file mode 100644 index 7b141bc..0000000 --- a/packages/common/src/Logger.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { Options, bgBrightWhite, black, bold, cyan, gray, italic, red, yellow } from './Util'; - -export enum LogLevels { - Debug = 0, - Info = 1, - Warn = 2, - Error = 3, - Fatal = 4 -} - -export enum LogDepth { - Minimal = 0, - Full = 1 -} - -export type LoggerOptions = { - logLevel?: LogLevels; - name?: string; - active?: boolean; -}; - -export class Logger { - readonly options: Required; - - constructor(options: LoggerOptions) { - this.options = Options(Logger.DEFAULT_OPTIONS, options); - } - - set level(level: LogLevels) { - this.options.logLevel = level; - } - - get level(): LogLevels { - return this.options.logLevel; - } - - set active(active: boolean) { - this.options.active = active; - } - - get active(): boolean { - return this.options.active; - } - - set name(name: string) { - this.options.name = name; - } - - get name(): string { - return this.options.name; - } - - rawLog(level: LogLevels, ...args: unknown[]) { - if (!this.active) return; - if (level < this.level) return; - - const color = Logger.colorFunctions.get(level) ?? Logger.noColor; - - const date = new Date(); - const log = [ - bgBrightWhite(black(`[${date.toLocaleDateString()} ${date.toLocaleTimeString()}]`)), - color(Logger.prefixes.get(level) ?? 'DEBUG'), - this.name ? `${this.name} >` : '>', - ...args - ]; - - switch (level) { - case LogLevels.Debug: - return console.debug(...log); - case LogLevels.Info: - return console.info(...log); - case LogLevels.Warn: - return console.warn(...log); - case LogLevels.Error: - return console.error(...log); - case LogLevels.Fatal: - return console.error(...log); - default: - return console.log(...log); - } - } - - debug(...args: any[]) { - this.rawLog(LogLevels.Debug, ...args); - } - - info(...args: any[]) { - this.rawLog(LogLevels.Info, ...args); - } - - warn(...args: any[]) { - this.rawLog(LogLevels.Warn, ...args); - } - - error(...args: any[]) { - this.rawLog(LogLevels.Error, ...args); - } - - fatal(...args: any[]) { - this.rawLog(LogLevels.Fatal, ...args); - } - - static DEFAULT_OPTIONS: Required = { - logLevel: LogLevels.Info, - name: 'BISCUIT', - active: true - }; - - static noColor(msg: string) { - return msg; - } - - static colorFunctions = new Map string>([ - [LogLevels.Debug, gray], - [LogLevels.Info, cyan], - [LogLevels.Warn, yellow], - [LogLevels.Error, (str: string) => red(str)], - [LogLevels.Fatal, (str: string) => red(bold(italic(str)))] - ]); - - static prefixes = new Map([ - [LogLevels.Debug, 'DEBUG'], - [LogLevels.Info, 'INFO'], - [LogLevels.Warn, 'WARN'], - [LogLevels.Error, 'ERROR'], - [LogLevels.Fatal, 'FATAL'] - ]); -} diff --git a/packages/common/src/Types.ts b/packages/common/src/Types.ts deleted file mode 100644 index cc71c38..0000000 --- a/packages/common/src/Types.ts +++ /dev/null @@ -1,46 +0,0 @@ -export type Tail = A extends [unknown, ...infer rest] ? rest : A extends [unknown] ? [] : A extends (infer first)[] ? first[] : never; - -export type ValueOf = T[keyof T]; - -export type ArrayFirsElement = A extends [...infer arr] ? arr[0] : never; - -export type RestToKeys = T extends [infer V, ...infer Keys] ? { [K in Extract]: V } : never; - -export type Identify = T extends infer U ? { [K in keyof U]: U[K] } : never; - -export type TypeArray = T | T[]; - -export type When = T extends true ? A : B; - -export type PickPartial = { - [P in keyof T]?: T[P] | undefined; -} & { - [P in K]: T[P]; -}; - -export type MakeRequired = T & { [P in K]-?: T[P] }; - -export type CamelCase = S extends `${infer P1}_${infer P2}${infer P3}` - ? `${Lowercase}${Uppercase}${CamelCase}` - : Lowercase; - -export type SnakeCase = S extends `${infer A}${infer Rest}` - ? A extends Uppercase - ? `_${Lowercase}${SnakeCase}` - : `${A}${SnakeCase}` - : Lowercase; - -export type ObjectToLower = Identify<{ - [K in keyof T as CamelCase>]: T[K] extends unknown[] - ? Identify[]> - : T[K] extends object - ? Identify> - : T[K]; -}>; -export type ObjectToSnake = Identify<{ - [K in keyof T as SnakeCase>]: T[K] extends unknown[] - ? Identify[]> - : T[K] extends object - ? Identify> - : T[K]; -}>; diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts deleted file mode 100644 index eee595e..0000000 --- a/packages/common/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './Constants'; -export * from './Util'; -export * from './Types'; -export * from 'discord-api-types/v10'; -export * from './Collection'; -export * from './Logger'; diff --git a/packages/common/tsconfig.json b/packages/common/tsconfig.json deleted file mode 100644 index 9b4f197..0000000 --- a/packages/common/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "include": ["src/**/*"] -} diff --git a/packages/common/tsup.config.ts b/packages/common/tsup.config.ts deleted file mode 100644 index dfbea63..0000000 --- a/packages/common/tsup.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'tsup'; - -const isProduction = process.env.NODE_ENV === 'production'; - -export default defineConfig({ - clean: true, - dts: true, - entry: ['src/index.ts'], - format: ['cjs', 'esm'], - minify: isProduction, - sourcemap: false -}); diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md deleted file mode 100644 index 2f2085f..0000000 --- a/packages/core/CHANGELOG.md +++ /dev/null @@ -1,171 +0,0 @@ -# @biscuitland/core - -## 3.0.12 - -### Patch Changes - -- new changes -- new changes -- Updated dependencies -- Updated dependencies - - @biscuitland/ws@3.0.12 - -## 3.0.8 - -### Patch Changes - -- Updated dependencies - - @biscuitland/common@0.0.8 - - @biscuitland/ws@3.0.8 - -## 3.0.7 - -### Patch Changes - -- Updated dependencies - - @biscuitland/common@0.0.7 - - @biscuitland/ws@3.0.7 - -## 3.0.6 - -### Patch Changes - -- I meessed up -- Updated dependencies - - @biscuitland/common@0.0.6 - - @biscuitland/rest@3.0.6 - - @biscuitland/ws@3.0.6 - -## 3.0.5 - -### Patch Changes - -- fix: logger on every module -- Updated dependencies - - @biscuitland/common@0.0.5 - - @biscuitland/rest@3.0.5 - - @biscuitland/ws@3.0.5 - -## 3.0.4 - -### Patch Changes - -- first 3.0.\* without bugs -- Updated dependencies - - @biscuitland/common@0.0.4 - - @biscuitland/rest@3.0.4 - - @biscuitland/ws@3.0.4 - -## 2.3.0 - -### Minor Changes - -- fix TODO - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.3.0 - - @biscuitland/rest@2.3.0 - - @biscuitland/ws@2.3.0 - -## 2.2.3 - -### Patch Changes - -- bug fixes -- Updated dependencies - - @biscuitland/api-types@2.2.3 - - @biscuitland/rest@2.2.3 - - @biscuitland/ws@2.2.3 - -## 2.2.2 - -### Patch Changes - -- rename guildLocales to guildLocale in interactions -- Updated dependencies - - @biscuitland/api-types@2.2.2 - - @biscuitland/rest@2.2.2 - - @biscuitland/ws@2.2.2 - -## 2.2.1 - -### Patch Changes - -- select menu options now can be empty since the latest Discord API update -- Updated dependencies - - @biscuitland/api-types@2.2.1 - - @biscuitland/rest@2.2.1 - - @biscuitland/ws@2.2.1 - -## 2.2.0 - -### Minor Changes - -- Functionality to delete ephemeral messages added, select menus were updated - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.2.0 - - @biscuitland/rest@2.2.0 - - @biscuitland/ws@2.2.0 - -## 2.1.2 - -### Patch Changes - -- minor changes -- Updated dependencies - - @biscuitland/api-types@2.1.2 - - @biscuitland/rest@2.1.2 - - @biscuitland/ws@2.1.2 - -## 2.1.1 - -### Patch Changes - -- dumb hotfix that LH asked for (blame Yuzu) -- Updated dependencies - - @biscuitland/api-types@2.1.1 - - @biscuitland/rest@2.1.1 - - @biscuitland/ws@2.1.1 - -## 2.1.0 - -### Minor Changes - -- Changes to cache and forum channels ✨ -- Forum channels and updates to @biscuitland/cache ✨ - -### Patch Changes - -- Updated dependencies -- Updated dependencies - - @biscuitland/api-types@2.1.0 - - @biscuitland/rest@2.1.0 - - @biscuitland/ws@2.1.0 - -## 2.0.6 - -### Patch Changes - -- Minor fixes -- Updated dependencies - - @biscuitland/api-types@2.0.6 - - @biscuitland/rest@2.0.6 - - @biscuitland/ws@2.0.6 - -## 2.0.5 - -### Major Changes - -- publish - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.0.5 - - @biscuitland/rest@2.0.5 - - @biscuitland/ws@2.0.5 diff --git a/packages/core/README.md b/packages/core/README.md deleted file mode 100644 index 1c808ab..0000000 --- a/packages/core/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# @biscuitland/core -Core contains the essentials to launch you to develop your own customized and scalable bot. - -[](https://github.com/oasisjs/biscuit) -[](https://discord.gg/XNw2RZFzaP) - -## Getting Started - -### Install (for [node18](https://nodejs.org/en/download/)) - -```sh-session -npm install @biscuitland/core -yarn add @biscuitland/core -``` - -### Example bot -`project/index.js`: -```ts -import { Session } from '@biscuitland/core'; -import { GatewayIntentBits } from '@biscuitland/common'; - -const session = new Session({ token: 'your token', intents: GatewayIntentBits.Guilds }); - -session.on('READY', (payload, shardId) => { - console.log('Logged in as: %s in shard #%s', payload.user.username, shardId); -}); - -session.start(); -``` - -### Execute -For node 18.+: -``` -B:\project> node index.js -``` - -For node 16.+: -``` -B:\project> node --experimental-fetch index.js -``` - -## Links -* [Website](https://biscuitjs.com/) -* [Documentation](https://docs.biscuitjs.com/) -* [Discord](https://discord.gg/XNw2RZFzaP) -* [rest](https://www.npmjs.com/package/@biscuitland/rest) | [ws](https://www.npmjs.com/package/@biscuitland/ws) | [helpers](https://www.npmjs.com/package/@biscuitland/helpers) diff --git a/packages/core/package.json b/packages/core/package.json deleted file mode 100644 index 417be0f..0000000 --- a/packages/core/package.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "name": "@biscuitland/core", - "version": "3.0.12", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "files": [ - "dist/**" - ], - "scripts": { - "build": "tsup", - "clean": "rm -rf dist && rm -rf .turbo", - "dev": "tsup --watch" - }, - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.mjs" - }, - "require": "./dist/index.js" - } - }, - "dependencies": { - "@biscuitland/common": "^0.0.10", - "@biscuitland/rest": "^3.0.7", - "@biscuitland/ws": "^3.0.12", - "eventemitter2": "^6.4.9" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "tsup": "^7.0.0" - }, - "license": "Apache-2.0", - "author": "Yuzuru ", - "contributors": [ - { - "name": "Yuzuru", - "url": "https://github.com/yuzudev" - }, - { - "name": "miia", - "url": "https://github.com/dragurimu" - }, - { - "name": "n128", - "url": "https://github.com/nicolito128" - }, - { - "name": "socram03", - "url": "https://github.com/socram03", - "author": true - }, - { - "name": "Drylozu", - "url": "https://github.com/Drylozu" - } - ], - "homepage": "https://biscuitjs.com", - "repository": { - "type": "git", - "url": "git+https://github.com/oasisjs/biscuit.git" - }, - "bugs": { - "url": "https://github.com/oasisjs/biscuit" - }, - "keywords": [ - "api", - "discord", - "bots", - "typescript", - "botdev" - ], - "publishConfig": { - "access": "public" - } -} \ No newline at end of file diff --git a/packages/core/src/events/handler.ts b/packages/core/src/events/handler.ts deleted file mode 100644 index ff1c4da..0000000 --- a/packages/core/src/events/handler.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { GatewayEvents } from '@biscuitland/ws'; -import type { Session } from '../index'; - -export function actionHandler([session, payload, shardId]: Parameters) { - // @ts-expect-error At this point, typescript sucks - session.emit(payload.t, payload.d, shardId); - // @ts-expect-error At this point, typescript sucks - session.emit('RAW', payload.d, shardId); -} - -export type ActionHandler = ( - ...args: [Session, { t: G; d: GatewayEvents[G] }, number] -) => unknown; - -export type Handler = { - [K in keyof GatewayEvents]: (...args: [GatewayEvents[K], number]) => unknown; -}; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts deleted file mode 100644 index 21584ea..0000000 --- a/packages/core/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export * from './utils/types'; -export * from './utils/utils'; -export * from './session'; -export { Session as Biscuit } from './session'; -export * from './managers/MainManager'; -export * from './events/handler'; diff --git a/packages/core/src/managers/ApplicationManager.ts b/packages/core/src/managers/ApplicationManager.ts deleted file mode 100644 index d3a9a6f..0000000 --- a/packages/core/src/managers/ApplicationManager.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { - APIApplicationCommand, - Identify, - MakeRequired, - RESTGetAPIApplicationCommandsQuery, - RESTGetAPIApplicationGuildCommandsQuery, - RESTPatchAPIApplicationCommandJSONBody, - RESTPatchAPIApplicationGuildCommandJSONBody, - RESTPostAPIApplicationCommandsJSONBody, - RESTPostAPIApplicationGuildCommandsJSONBody, - RESTPutAPIApplicationCommandPermissionsJSONBody, - RESTPutAPIApplicationCommandsJSONBody, - RESTPutAPIApplicationGuildCommandsJSONBody, - RESTPutAPIApplicationRoleConnectionMetadataJSONBody -} from '@biscuitland/common'; -import { Session } from '..'; - -export class ApplicationManager { - readonly session!: Session; - constructor(session: Session) { - Object.defineProperty(this, 'session', { - value: session, - writable: false - }); - } - - getBotGateway() { - return this.session.api.gateway.bot.get(); - } - - getGateway() { - return this.session.api.gateway.get(); - } - - getNitroStickerPacks() { - return this.session.api['sticker-packs'].get(); - } - - getRoleConnectionMetadata(applicationId: string) { - return this.session.api.applications(applicationId)['role-connections'].metadata.get(); - } - - editRoleConnectionMetadata(applicationId: string, body: RESTPutAPIApplicationRoleConnectionMetadataJSONBody) { - return this.session.api.applications(applicationId)['role-connections'].metadata.put({ body }); - } - - getCommands( - applicationId: string, - query: RESTGetAPIApplicationCommandsQuery - ): Promise; - getCommands(applicationId: string, query?: RESTGetAPIApplicationCommandsQuery) { - return this.session.api.applications(applicationId).commands.get({ query }); - } - - createCommand(applicationId: string, body: RESTPostAPIApplicationCommandsJSONBody) { - return this.session.api.applications(applicationId).commands.post({ body }); - } - - getCommand(applicationId: string, commandId: string) { - return this.session.api.applications(applicationId).commands(commandId).get(); - } - - editCommand(applicationId: string, commandId: string, body: RESTPatchAPIApplicationCommandJSONBody) { - return this.session.api.applications(applicationId).commands(commandId).patch({ body }); - } - - deleteCommand(applicationId: string, commandId: string) { - return this.session.api.applications(applicationId).commands(commandId).delete(); - } - - bulkCommands(applicationId: string, body: RESTPutAPIApplicationCommandsJSONBody) { - return this.session.api.applications(applicationId).commands.put({ body }); - } - - getCommandPermissions(applicationId: string, guildId: string, commandId: string) { - return this.session.api.applications(applicationId).guilds(guildId).commands(commandId).permissions.get(); - } - - editCommandPermissions(applicationId: string, guildId: string, commandId: string, body: RESTPutAPIApplicationCommandPermissionsJSONBody) { - return this.session.api.applications(applicationId).guilds(guildId).commands(commandId).permissions.put({ body }); - } - - getGuildCommands( - applicationId: string, - guildId: string, - query: RESTGetAPIApplicationGuildCommandsQuery - ): Promise; - getGuildCommands(applicationId: string, guildId: string, query?: RESTGetAPIApplicationGuildCommandsQuery) { - return this.session.api.applications(applicationId).guilds(guildId).commands.get({ query }); - } - - createGuildCommand(applicationId: string, guildId: string, body: RESTPostAPIApplicationGuildCommandsJSONBody) { - return this.session.api.applications(applicationId).guilds(guildId).commands.post({ body }); - } - - getGuildCommand(applicationId: string, guildId: string, commandId: string) { - return this.session.api.applications(applicationId).guilds(guildId).commands(commandId).get(); - } - - editGuildCommand(applicationId: string, guildId: string, commandId: string, body: RESTPatchAPIApplicationGuildCommandJSONBody) { - return this.session.api.applications(applicationId).guilds(guildId).commands(commandId).patch({ body }); - } - - deleteGuildCommand(applicationId: string, guildId: string, commandId: string) { - return this.session.api.applications(applicationId).guilds(guildId).commands(commandId).delete(); - } - - bulkGuildCommands(applicationId: string, guildId: string, body: RESTPutAPIApplicationGuildCommandsJSONBody) { - return this.session.api.applications(applicationId).guilds(guildId).commands.put({ body }); - } - - getGuildCommandPermissions(applicationId: string, guildId: string) { - return this.session.api.applications(applicationId).guilds(guildId).commands.permissions.get(); - } -} - -export type RESTGetAPIApplicationCommandsWithLocalizationsResult = Identify< - MakeRequired ->[]; - -export type RESTGetAPIApplicationGuildCommandsWithLocalizationsResult = RESTGetAPIApplicationCommandsWithLocalizationsResult; diff --git a/packages/core/src/managers/ChannelManager.ts b/packages/core/src/managers/ChannelManager.ts deleted file mode 100644 index 5dfa652..0000000 --- a/packages/core/src/managers/ChannelManager.ts +++ /dev/null @@ -1,214 +0,0 @@ -import type { - APIChannel, - RESTGetAPIChannelMessageReactionUsersQuery, - RESTGetAPIChannelThreadMemberQuery, - RESTGetAPIChannelThreadMembersQuery, - RESTGetAPIChannelThreadsArchivedQuery, - RESTPatchAPIChannelJSONBody, - RESTPatchAPIChannelMessageJSONBody, - RESTPatchAPIStageInstanceJSONBody, - RESTPostAPIChannelFollowersJSONBody, - RESTPostAPIChannelInviteJSONBody, - RESTPostAPIChannelMessageJSONBody, - RESTPostAPIChannelMessagesBulkDeleteJSONBody, - RESTPostAPIChannelMessagesThreadsJSONBody, - RESTPostAPIChannelThreadsJSONBody, - RESTPostAPIChannelThreadsResult, - RESTPostAPIChannelWebhookJSONBody, - RESTPostAPIGuildForumThreadsJSONBody, - RESTPutAPIChannelPermissionJSONBody, - RESTPutAPIChannelRecipientJSONBody -} from '@biscuitland/common'; -import type { RawFile } from '@biscuitland/rest'; - -import type { Session } from '../session'; - -export class ChannelManager { - readonly session!: Session; - constructor(session: Session) { - Object.defineProperty(this, 'session', { - value: session, - writable: false - }); - } - - get(id: string) { - return this.session.api.channels(id).get() as Promise; - } - - getWebhooks(channelId: string) { - return this.session.api.channels(channelId).webhooks.get(); - } - - createWebhook(channelId: string, body: RESTPostAPIChannelWebhookJSONBody) { - return this.session.api.channels(channelId).webhooks.post({ body }); - } - - edit(id: string, data: RESTPatchAPIChannelJSONBody) { - return this.session.api.channels(id).patch({ body: data }); - } - - delete(id: string) { - return this.session.api.channels(id).delete(); - } - - getMessages(id: string, limit = 50) { - return this.session.api.channels(id).messages.get({ - query: { limit } - }); - } - - getMessage(id: string, messageId: string) { - return this.session.api.channels(id).messages(messageId).get(); - } - - createMessage(id: string, data: RESTPostAPIChannelMessageJSONBody) { - return this.session.api.channels(id).messages.post({ body: data }); - } - - sendTyping(id: string) { - return this.session.api.channels(id).typing.post(); - } - - getArchivedThreads(channelId: string, options: RESTGetAPIChannelThreadsArchivedOptions) { - const { type, ...query } = options; - if (type === 'private') { - return this.session.api.channels(channelId).threads.archived.private.get({ query }); - } - - return this.session.api.channels(channelId).threads.archived.public.get({ query }); - } - - crosspostMessage(channelId: string, messageId: string) { - return this.session.api.channels(channelId).messages(messageId).crosspost.post({}); - } - - createReaction(channelId: string, messageId: string, emoji: string) { - return this.session.api.channels(channelId).messages(messageId).reactions(emoji)('@me').put({}); - } - - deleteReaction(channelId: string, messageId: string, emoji: string, user = '@me') { - return this.session.api.channels(channelId).messages(messageId).reactions(emoji)(user).delete(); - } - - getReactions(channelId: string, messageId: string, emoji: string, query?: RESTGetAPIChannelMessageReactionUsersQuery) { - return this.session.api.channels(channelId).messages(messageId).reactions(emoji).get({ query }); - } - - deleteAllReactions(channelId: string, messageId: string, emoji?: string) { - if (emoji?.length) return this.session.api.channels(channelId).messages(messageId).reactions(emoji).delete(); - return this.session.api.channels(channelId).messages(messageId).reactions.delete(); - } - - editMessage(channelId: string, messageId: string, body: RESTPatchAPIChannelMessageJSONBody, files?: RawFile[]) { - return this.session.api.channels(channelId).messages(messageId).patch({ - body, - files - }); - } - - deleteMessage(channelId: string, messageId: string, reason?: string) { - return this.session.api.channels(channelId).messages(messageId).delete({ reason }); - } - - bulkMessages(channelId: string, body: RESTPostAPIChannelMessagesBulkDeleteJSONBody, reason?: string) { - return this.session.api.channels(channelId).messages['bulk-delete'].post({ body, reason }); - } - - editPermissions(channelId: string, overwriteId: string, body: RESTPutAPIChannelPermissionJSONBody, reason?: string) { - return this.session.api.channels(channelId).permissions(overwriteId).put({ body, reason }); - } - - deletePermission(channelId: string, overwriteId: string, reason?: string) { - return this.session.api.channels(channelId).permissions(overwriteId).delete({ reason }); - } - - getInvites(channelId: string) { - return this.session.api.channels(channelId).invites.get(); - } - - createInvite(channelId: string, body: RESTPostAPIChannelInviteJSONBody) { - return this.session.api.channels(channelId).invites.post({ body }); - } - - followAnnoucement(channelId: string, body: RESTPostAPIChannelFollowersJSONBody) { - return this.session.api.channels(channelId).followers.post({ body }); - } - - getPinnedMessages(channelId: string) { - return this.session.api.channels(channelId).pins.get(); - } - - pinMessage(channelId: string, messageId: string, reason?: string) { - return this.session.api.channels(channelId).pins(messageId).put({ reason }); - } - - unpinMessage(channelId: string, messageId: string, reason?: string) { - return this.session.api.channels(channelId).pins(messageId).delete({ reason }); - } - - groupDMAddRecipient(channelId: string, userId: string, body: RESTPutAPIChannelRecipientJSONBody) { - return this.session.api.channels(channelId).recipients(userId).put({ body }); - } - - groupDMRemoveRecipient(channelId: string, userId: string) { - return this.session.api.channels(channelId).recipients(userId).delete(); - } - - startThreadFromMessage(channelId: string, messageId: string, body: RESTPostAPIChannelMessagesThreadsJSONBody, reason?: string) { - return this.session.api.channels(channelId).messages(messageId).threads.post({ body, reason }); - } - - startThread(channelId: string, body: RESTPostAPIChannelThreadsJSONBody, reason?: string): Promise; - startThread(channelId: string, body: RESTPostAPIGuildForumThreadsJSONBody, reason?: string) { - return this.session.api.channels(channelId).threads.post({ body, reason }); - } - - getListJoinedPrivateArchivedThreads(channelId: string, query?: RESTGetAPIChannelThreadsArchivedQuery) { - return this.session.api.channels(channelId).users('@me').threads.archived.private.get({ query }); - } - - getThreadMembers(channelId: string, query?: RESTGetAPIChannelThreadMembersQuery) { - return this.session.api.channels(channelId)['thread-members'].get({ query }); - } - - getThreadMember(channelId: string, userId: string, query?: RESTGetAPIChannelThreadMemberQuery) { - return this.session.api.channels(channelId)['thread-members'](userId).get({ query }); - } - - addThreadMember(channelId: string, userId: string) { - return this.session.api.channels(channelId)['thread-members'](userId).put({}); - } - - removeThreadMember(channelId: string, userId: string) { - return this.session.api.channels(channelId)['thread-members'](userId).delete(); - } - - leaveThread(channelId: string) { - return this.session.api.channels(channelId)['thread-members']('@me').delete(); - } - - joinThread(channelId: string) { - return this.session.api.channels(channelId)['thread-members']('@me').put({}); - } - - getVoiceRegions() { - return this.session.api.voice.region.get(); - } - - getStageInstance(channelId: string) { - return this.session.api['stage-instances'](channelId).get(); - } - - editStageInstance(channelId: string, body: RESTPatchAPIStageInstanceJSONBody, reason?: string) { - return this.session.api['stage-instances'](channelId).patch({ body, reason }); - } - - deleteStageInstance(channelId: string, reason?: string) { - return this.session.api['stage-instances'](channelId).delete({ reason }); - } -} - -export type RESTGetAPIChannelThreadsArchivedOptions = { - type: 'private' | 'public'; -} & RESTGetAPIChannelThreadsArchivedQuery; diff --git a/packages/core/src/managers/GuildManager.ts b/packages/core/src/managers/GuildManager.ts deleted file mode 100644 index 55db2e0..0000000 --- a/packages/core/src/managers/GuildManager.ts +++ /dev/null @@ -1,348 +0,0 @@ -import type { - APIGuildChannel, - GuildChannelType, - GuildMFALevel, - RESTGetAPIAuditLogQuery, - RESTGetAPIGuildBansQuery, - RESTGetAPIGuildMembersQuery, - RESTGetAPIGuildMembersSearchQuery, - RESTGetAPIGuildPruneCountQuery, - RESTGetAPIGuildScheduledEventQuery, - RESTGetAPIGuildScheduledEventUsersQuery, - RESTGetAPIGuildScheduledEventsQuery, - RESTGetAPIGuildWidgetImageQuery, - RESTPatchAPIAutoModerationRuleJSONBody, - RESTPatchAPICurrentGuildMemberJSONBody, - RESTPatchAPIGuildChannelPositionsJSONBody, - RESTPatchAPIGuildEmojiJSONBody, - RESTPatchAPIGuildJSONBody, - RESTPatchAPIGuildMemberJSONBody, - RESTPatchAPIGuildRoleJSONBody, - RESTPatchAPIGuildRolePositionsJSONBody, - RESTPatchAPIGuildScheduledEventJSONBody, - RESTPatchAPIGuildStickerJSONBody, - RESTPatchAPIGuildTemplateJSONBody, - RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody, - RESTPatchAPIGuildVoiceStateUserJSONBody, - RESTPatchAPIGuildWelcomeScreenJSONBody, - RESTPatchAPIGuildWidgetSettingsJSONBody, - RESTPostAPIAutoModerationRuleJSONBody, - RESTPostAPIGuildChannelJSONBody, - RESTPostAPIGuildEmojiJSONBody, - RESTPostAPIGuildPruneJSONBody, - RESTPostAPIGuildRoleJSONBody, - RESTPostAPIGuildScheduledEventJSONBody, - RESTPostAPIGuildStickerFormDataBody, - RESTPostAPIGuildTemplatesJSONBody, - RESTPostAPIGuildsJSONBody, - RESTPostAPITemplateCreateGuildJSONBody, - RESTPutAPIGuildBanJSONBody, - RESTPutAPIGuildMemberJSONBody -} from '@biscuitland/common'; -import type { Session } from '../session'; - -export class GuildManager { - readonly session!: Session; - constructor(session: Session) { - Object.defineProperty(this, 'session', { - value: session, - writable: false - }); - } - - get(guildId: string) { - return this.session.api.guilds(guildId).get(); - } - - create(options: RESTPostAPIGuildsJSONBody) { - return this.session.api.guilds.post({ body: options }); - } - - delete(guildId: string) { - return this.session.api.guilds(guildId).delete(); - } - - edit(guildId: string, options: RESTPatchAPIGuildJSONBody) { - return this.session.api.guilds(guildId).patch({ body: options }); - } - - getChannels(guildId: string) { - return this.session.api.guilds(guildId).channels.get(); - } - - createChannel>(guildId: string, body: RESTPostAPIGuildChannelJSONBody) { - return this.session.api.guilds(guildId).channels.post({ body }) as Promise; - } - - editChannelPositions(guildId: string, body: RESTPatchAPIGuildChannelPositionsJSONBody): Promise { - return this.session.api.guilds(guildId).channels.patch({ body }); - } - - getThreads(guildId: string) { - return this.session.api.guilds(guildId).threads.active.get(); - } - - getBans(guildId: string, query: RESTGetAPIGuildBansQuery = {}) { - return this.session.api.guilds(guildId).bans.get({ - query - }); - } - - getBan(guildId: string, userId: string) { - return this.session.api.guilds(guildId).bans(userId).get(); - } - - createBan(guildId: string, userId: string, body: RESTPutAPIGuildBanJSONBody) { - return this.session.api.guilds(guildId).bans(userId).put({ body }); - } - - removeBan(guildId: string, userId: string) { - return this.session.api.guilds(guildId).bans(userId).delete(); - } - - getRoles(guildId: string) { - return this.session.api.guilds(guildId).roles.get(); - } - - createRole(guildId: string, options: RESTPostAPIGuildRoleJSONBody) { - return this.session.api.guilds(guildId).roles.post({ body: options }); - } - - editRolePositions(guildId: string, options: RESTPatchAPIGuildRolePositionsJSONBody) { - return this.session.api.guilds(guildId).roles.patch({ body: options }); - } - - editRole(guildId: string, roleId: string, options: RESTPatchAPIGuildRoleJSONBody) { - return this.session.api.guilds(guildId).roles(roleId).patch({ body: options }); - } - - deleteRole(guildId: string, roleId: string) { - return this.session.api.guilds(guildId).roles(roleId).delete(); - } - - editGuildMFALevel(guildId: string, level: GuildMFALevel) { - return this.session.api.guilds(guildId).mfa.post({ body: { level } }); - } - - getPruneCount(guildId: string, query: RESTGetAPIGuildPruneCountQuery) { - return this.session.api.guilds(guildId).prune.get({ - query - }); - } - - beginGuildPrune(guildId: string, options: RESTPostAPIGuildPruneJSONBody) { - return this.session.api.guilds(guildId).prune.post({ body: options }); - } - - getVoiceRegions(guildId: string) { - return this.session.api.guilds(guildId).regions.get(); - } - - getInvites(guildId: string) { - return this.session.api.guilds(guildId).invites.get(); - } - - getIntegrations(guildId: string) { - return this.session.api.guilds(guildId).integrations.get(); - } - - deleteIntegration(guildId: string, integrationId: string) { - return this.session.api.guilds(guildId).integrations(integrationId).delete(); - } - - getWidget(guildId: string) { - return this.session.api.guilds(guildId).widget.get(); - } - - editWidget(guildId: string, options: RESTPatchAPIGuildWidgetSettingsJSONBody) { - return this.session.api.guilds(guildId).widget.patch({ body: options }); - } - - getVanityUrl(guildId: string) { - return this.session.api.guilds(guildId)['vanity-url'].get(); - } - - getWelcomeScreen(guildId: string) { - return this.session.api.guilds(guildId)['welcome-screen'].get(); - } - - editWelcomeScreen(guildId: string, options: RESTPatchAPIGuildWelcomeScreenJSONBody) { - return this.session.api.guilds(guildId)['welcome-screen'].patch({ body: options }); - } - - getAuditLog(guildId: string, query?: RESTGetAPIAuditLogQuery) { - return this.session.api.guilds(guildId)['audit-logs'].get({ query }); - } - - getAutoModerationRules(guildId: string) { - return this.session.api.guilds(guildId)['auto-moderation'].rules.get(); - } - - getAutoModerationRule(guildId: string, ruleId: string) { - return this.session.api.guilds(guildId)['auto-moderation'].rules(ruleId).get(); - } - - createAutoModerationRule(guildId: string, body: RESTPostAPIAutoModerationRuleJSONBody, reason?: string) { - return this.session.api.guilds(guildId)['auto-moderation'].rules.post({ body, reason }); - } - - editAutoModerationRule(guildId: string, ruleId: string, body: RESTPatchAPIAutoModerationRuleJSONBody, reason?: string) { - return this.session.api.guilds(guildId)['auto-moderation'].rules(ruleId).patch({ body, reason }); - } - - deleteAutoModerationRule(guildId: string, ruleId: string, reason?: string) { - return this.session.api.guilds(guildId)['auto-moderation'].rules(ruleId).delete({ reason }); - } - - getTemplate(code: string) { - return this.session.api.guilds.templates(code).get(); - } - - createTemplate(code: string, body: RESTPostAPITemplateCreateGuildJSONBody) { - return this.session.api.guilds.templates(code).post({ body }); - } - - getWebhooks(guildId: string) { - return this.session.api.guilds(guildId).webhooks.get(); - } - - getPreview(guildId: string) { - return this.session.api.guilds(guildId).preview.get(); - } - - getMembers(guildId: string, query?: RESTGetAPIGuildMembersQuery) { - return this.session.api.guilds(guildId).members.get({ query }); - } - - searchMembers(guildId: string, query?: RESTGetAPIGuildMembersSearchQuery) { - return this.session.api.guilds(guildId).members.search.get({ query }); - } - - editCurrentMember(guildId: string, body: RESTPatchAPICurrentGuildMemberJSONBody) { - return this.session.api.guilds(guildId).members['@me'].patch({ body }); - } - - getMember(guildId: string, memberId: string) { - return this.session.api.guilds(guildId).members(memberId).get(); - } - - addMember(guildId: string, memberId: string, body: RESTPutAPIGuildMemberJSONBody) { - return this.session.api.guilds(guildId).members(memberId).put({ body }); - } - - editMember(guildId: string, memberId: string, body: RESTPatchAPIGuildMemberJSONBody) { - return this.session.api.guilds(guildId).members(memberId).patch({ body }); - } - - removeMember(guildId: string, memberId: string) { - return this.session.api.guilds(guildId).members(memberId).delete(); - } - - addRoleMember(guildId: string, memberId: string, roleId: string) { - return this.session.api.guilds(guildId).members(memberId).roles(roleId).put({}); - } - - removeRoleMember(guildId: string, memberId: string, roleId: string) { - return this.session.api.guilds(guildId).members(memberId).roles(roleId).delete({}); - } - - getWidgetJson(guildId: string) { - return this.session.api.guilds(guildId)['widget.json'].get(); - } - - getWidgetPng(guildId: string, query?: RESTGetAPIGuildWidgetImageQuery) { - return this.session.api.guilds(guildId)['widget.png'].get({ query }); - } - - getEmojis(guildId: string) { - return this.session.api.guilds(guildId).emojis.get(); - } - - createEmoji(guildId: string, body: RESTPostAPIGuildEmojiJSONBody) { - return this.session.api.guilds(guildId).emojis.post({ body }); - } - - getEmoji(guildId: string, emojiId: string) { - return this.session.api.guilds(guildId).emojis(emojiId).get(); - } - - editEmoji(guildId: string, emojiId: string, body: RESTPatchAPIGuildEmojiJSONBody) { - return this.session.api.guilds(guildId).emojis(emojiId).patch({ body }); - } - - deleteEmoji(guildId: string, emojiId: string) { - return this.session.api.guilds(guildId).emojis(emojiId).delete(); - } - - editCurrentVoiceState(guildId: string, body: RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody) { - return this.session.api.guilds(guildId)['voice-states']['@me'].patch({ body }); - } - - editMemberVoiceState(guildId: string, memberId: string, body: RESTPatchAPIGuildVoiceStateUserJSONBody) { - return this.session.api.guilds(guildId)['voice-states'](memberId).patch({ body }); - } - - getStickers(guildId: string) { - return this.session.api.guilds(guildId).stickers.get(); - } - - createSticker(guildId: string, body: RESTPostAPIGuildStickerFormDataBody) { - return this.session.api.guilds(guildId).stickers.post({ body }); - } - - getSticker(guildId: string, stickerId: string) { - return this.session.api.guilds(guildId).stickers(stickerId).get(); - } - - editSticker(guildId: string, stickerId: string, body: RESTPatchAPIGuildStickerJSONBody) { - return this.session.api.guilds(guildId).stickers(stickerId).patch({ body }); - } - - deleteSticker(guildId: string, stickerId: string) { - return this.session.api.guilds(guildId).stickers(stickerId).delete(); - } - - getScheduledEvents(guildId: string, query?: RESTGetAPIGuildScheduledEventsQuery) { - return this.session.api.guilds(guildId)['scheduled-events'].get({ query }); - } - - createScheduledEvent(guildId: string, body: RESTPostAPIGuildScheduledEventJSONBody) { - return this.session.api.guilds(guildId)['scheduled-events'].post({ body }); - } - - getScheduledEvent(guildId: string, scheduledEvent: string, query?: RESTGetAPIGuildScheduledEventQuery) { - return this.session.api.guilds(guildId)['scheduled-events'](scheduledEvent).get({ query }); - } - - editScheduledEvent(guildId: string, scheduledEvent: string, body: RESTPatchAPIGuildScheduledEventJSONBody) { - return this.session.api.guilds(guildId)['scheduled-events'](scheduledEvent).patch({ body }); - } - - deleteScheduledEvent(guildId: string, scheduledEvent: string) { - return this.session.api.guilds(guildId)['scheduled-events'](scheduledEvent).delete(); - } - - getUsersScheduledEvent(guildId: string, scheduledEvent: string, query: RESTGetAPIGuildScheduledEventUsersQuery) { - return this.session.api.guilds(guildId)['scheduled-events'](scheduledEvent).users.get({ query }); - } - - getGuildTemplates(guildId: string) { - return this.session.api.guilds(guildId).templates.get(); - } - - createGuildTemplate(guildId: string, body: RESTPostAPIGuildTemplatesJSONBody) { - return this.session.api.guilds(guildId).templates.post({ body }); - } - - syncGuildTemplate(guildId: string, code: string) { - return this.session.api.guilds(guildId).templates(code).put({}); - } - - modifyGuildTemaplte(guildId: string, code: string, body: RESTPatchAPIGuildTemplateJSONBody) { - return this.session.api.guilds(guildId).templates(code).patch({ body }); - } - - deleteCodeTemplate(guildId: string, code: string) { - return this.session.api.guilds(guildId).templates(code).delete(); - } -} diff --git a/packages/core/src/managers/InteractionManager.ts b/packages/core/src/managers/InteractionManager.ts deleted file mode 100644 index 46d0529..0000000 --- a/packages/core/src/managers/InteractionManager.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { - RESTPatchAPIWebhookWithTokenMessageJSONBody, - RESTPostAPIInteractionCallbackJSONBody, - RESTPostAPIInteractionFollowupJSONBody -} from '@biscuitland/common'; -import type { RawFile } from '@biscuitland/rest'; -import type { Session } from '..'; - -export class InteractionManager { - readonly session!: Session; - constructor(session: Session) { - Object.defineProperty(this, 'session', { - value: session, - writable: false - }); - } - - reply( - interactionId: string, - token: string, - body: T, - files?: RawFile[] - ) { - return this.session.api.interactions(interactionId)(token).callback.post({ - body, - files - }); - } - - getResponse(applicationId: string, token: string, messageId = '@original') { - return this.session.api.webhooks(applicationId)(token).messages(messageId).get(); - } - - editResponse( - applicationId: string, - token: string, - messageId: string, - body: RESTPatchAPIWebhookWithTokenMessageJSONBody, - files?: RawFile[] - ) { - return this.session.api.webhooks(applicationId)(token).messages(messageId).patch({ - body, - files - }); - } - - deleteResponse(applicationId: string, token: string, messageId = '@original') { - return this.session.api.webhooks(applicationId)(token).messages(messageId).delete(); - } - - followUp(applicationId: string, token: string, body: RESTPostAPIInteractionFollowupJSONBody, files?: RawFile[]) { - return this.session.api.webhooks(applicationId)(token).post({ - body, - files - }); - } -} diff --git a/packages/core/src/managers/MainManager.ts b/packages/core/src/managers/MainManager.ts deleted file mode 100644 index 1211942..0000000 --- a/packages/core/src/managers/MainManager.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Session } from '../session'; -import { ApplicationManager } from './ApplicationManager'; -import { ChannelManager } from './ChannelManager'; -import { GuildManager } from './GuildManager'; -import { InteractionManager } from './InteractionManager'; -import { MemberManager } from './MemberManager'; -import { UserManager } from './UserManager'; -import { WebhookManager } from './WebhookManager'; - -export class MainManager { - constructor(private readonly session: Session) { - this.users = new UserManager(this.session); - this.guilds = new GuildManager(this.session); - this.members = new MemberManager(this.session); - this.channels = new ChannelManager(this.session); - this.applications = new ApplicationManager(this.session); - this.interactions = new InteractionManager(this.session); - this.webhooks = new WebhookManager(this.session); - } - - users: UserManager; - guilds: GuildManager; - members: MemberManager; - channels: ChannelManager; - applications: ApplicationManager; - interactions: InteractionManager; - webhooks: WebhookManager; -} diff --git a/packages/core/src/managers/MemberManager.ts b/packages/core/src/managers/MemberManager.ts deleted file mode 100644 index a588184..0000000 --- a/packages/core/src/managers/MemberManager.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { APIGuildMember, MakeRequired } from '@biscuitland/common'; -import type { ImageOptions, Session } from '../index'; -import { formatImageURL } from '../index'; - -export class MemberManager { - constructor(private readonly session: Session) {} - - dynamicAvatarURL({ avatar, guild_id, user }: DynamicMember, { size, format }: ImageOptions = {}): string { - if (avatar?.length) { - return formatImageURL(this.session.cdn.guilds(guild_id).users(user.id).avatars(avatar).get(), size, format); - } - - return this.session.managers.users.avatarURL(user, { size, format }); - } -} - -export type DynamicMember = MakeRequired & { - guild_id: string; -}; diff --git a/packages/core/src/managers/UserManager.ts b/packages/core/src/managers/UserManager.ts deleted file mode 100644 index d0a9c7c..0000000 --- a/packages/core/src/managers/UserManager.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { - APIUser, - RESTGetAPICurrentUserGuildsQuery, - RESTPatchAPICurrentUserJSONBody, - RESTPutAPICurrentUserApplicationRoleConnectionJSONBody -} from '@biscuitland/common'; -import type { ImageOptions, Session } from '../index'; -import { formatImageURL } from '../index'; - -export class UserManager { - readonly session!: Session; - constructor(session: Session) { - Object.defineProperty(this, 'session', { - value: session, - writable: false - }); - } - - get(userId = '@me') { - return this.session.api.users(userId).get(); - } - - avatarURL(user: APIUser, { size, format }: ImageOptions = {}) { - if (user.avatar?.length) { - return formatImageURL(this.session.cdn.avatars(user.id).get(user.avatar), size, format); - } - - return formatImageURL(this.session.cdn.embed.avatars.get(Number(user.discriminator) % 5)); - } - - createDM(userId: string) { - return this.session.api.users('@me').channels.post({ body: { recipient_id: userId } }); - } - - editCurrent(body: RESTPatchAPICurrentUserJSONBody) { - return this.session.api.users('@me').patch({ - body - }); - } - - getGuilds(query?: RESTGetAPICurrentUserGuildsQuery) { - return this.session.api.users('@me').guilds.get({ query }); - } - - getGuildMember(guildId: string) { - return this.session.api.users('@me').guilds(guildId).member.get(); - } - - leaveGuild(guildId: string) { - return this.session.api.users('@me').guilds(guildId).delete(); - } - - getConnections() { - return this.session.api.users('@me').connections.get(); - } - - getRoleConnections(applicationId: string) { - return this.session.api.users('@me').applications(applicationId)['role-connection'].get(); - } - - updateRoleConnection(applicationId: string, body: RESTPutAPICurrentUserApplicationRoleConnectionJSONBody) { - return this.session.api.users('@me').applications(applicationId)['role-connection'].put({ body }); - } -} diff --git a/packages/core/src/managers/WebhookManager.ts b/packages/core/src/managers/WebhookManager.ts deleted file mode 100644 index fa8272a..0000000 --- a/packages/core/src/managers/WebhookManager.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - Identify, - RESTPatchAPIWebhookJSONBody, - RESTPatchAPIWebhookResult, - RESTPatchAPIWebhookWithTokenJSONBody, - RESTPatchAPIWebhookWithTokenMessageJSONBody, - RESTPatchAPIWebhookWithTokenResult, - RESTPostAPIChannelWebhookJSONBody, - RESTPostAPIWebhookWithTokenGitHubQuery, - RESTPostAPIWebhookWithTokenGitHubWaitResult, - RESTPostAPIWebhookWithTokenJSONBody, - RESTPostAPIWebhookWithTokenQuery, - RESTPostAPIWebhookWithTokenSlackQuery, - RESTPostAPIWebhookWithTokenSlackWaitResult, - RESTPostAPIWebhookWithTokenWaitResult -} from '@biscuitland/common'; -import type { Session } from '..'; - -export class WebhookManager { - readonly session!: Session; - constructor(session: Session) { - Object.defineProperty(this, 'session', { - value: session, - writable: false - }); - } - - create(channelId: string, body: RESTPostAPIChannelWebhookJSONBody) { - return this.session.api.channels(channelId).webhooks.post({ body }); - } - - getChannelWebhooks(channelId: string) { - return this.session.api.channels(channelId).webhooks.get(); - } - - getGuildWebhooks(guildId: string) { - return this.session.api.guilds(guildId).webhooks.get(); - } - - get(webhookdId: string, token?: string) { - if (!token?.length) return this.session.api.webhooks(webhookdId).get(); - return this.session.api.webhooks(webhookdId)(token).get(); - } - - edit(webhookId: string, body: RESTPatchAPIWebhookJSONBody): Promise; - edit(webhookId: string, body: RESTPatchAPIWebhookWithTokenJSONBody, token: string): Promise; - edit(webhookId: string, body: RESTPatchAPIWebhookJSONBody, token?: string) { - if (!token?.length) { - return this.session.api.webhooks(webhookId).patch({ body }); - } - return this.session.api.webhooks(webhookId)(token).patch({ body }); - } - - delete(webhookdId: string, token?: string) { - if (!token?.length) return this.session.api.webhooks(webhookdId).delete(); - return this.session.api.webhooks(webhookdId)(token).delete(); - } - - execute( - webhookId: string, - token: string, - body: RESTPostAPIWebhookWithTokenJSONBody, - query: RESTPostAPIWebhookWithTokenWaitQuery - ): Promise; - execute(webhookId: string, token: string, body: RESTPostAPIWebhookWithTokenJSONBody, query?: RESTPostAPIWebhookWithTokenQuery) { - return this.session.api.webhooks(webhookId)(token).post({ - body, - query - }); - } - - executeGithub( - webhookId: string, - token: string, - body: RESTPostAPIWebhookWithTokenJSONBody, - query: Identify - ): Promise; - executeGithub( - webhookId: string, - token: string, - body: RESTPostAPIWebhookWithTokenJSONBody, - query?: RESTPostAPIWebhookWithTokenGitHubQuery - ) { - return this.session.api.webhooks(webhookId)(token).github.post({ - body, - query - }); - } - - executeSlack( - webhookId: string, - token: string, - body: RESTPostAPIWebhookWithTokenJSONBody, - query: Identify - ): Promise; - executeSlack(webhookId: string, token: string, body: RESTPostAPIWebhookWithTokenJSONBody, query?: RESTPostAPIWebhookWithTokenSlackQuery) { - return this.session.api.webhooks(webhookId)(token).slack.post({ - body, - query - }); - } - - getMessage(webhookId: string, token: string, messageId: string, query?: { thread_id?: string }) { - return this.session.api.webhooks(webhookId)(token).messages(messageId).get({ - query - }); - } - - editMessage( - webhookId: string, - token: string, - messageId: string, - body: RESTPatchAPIWebhookWithTokenMessageJSONBody, - query?: { thread_id?: string } - ) { - return this.session.api.webhooks(webhookId)(token).messages(messageId).patch({ query, body }); - } - - deleteMessage(webhookId: string, token: string, messageId: string, query?: { thread_id?: string }) { - return this.session.api.webhooks(webhookId)(token).messages(messageId).delete({ query }); - } -} - -export type RESTPostAPIWebhookWithTokenWaitQuery = Identify; diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts deleted file mode 100644 index 6f2e7fc..0000000 --- a/packages/core/src/session.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { GatewayIntentBits, Identify, When } from '@biscuitland/common'; -import type { BiscuitRESTOptions, CDNRoutes, Routes } from '@biscuitland/rest'; -import { BiscuitREST, CDN, Router } from '@biscuitland/rest'; -import { GatewayEvents, ShardManager, ShardManagerOptions } from '@biscuitland/ws'; -import EventEmitter2 from 'eventemitter2'; -import { MainManager, getBotIdFromToken } from '.'; -import { Handler, actionHandler } from './events/handler'; - -export class Session extends EventEmitter2 { - constructor(public options: BiscuitOptions) { - super(); - this.rest = this.createRest(this.options.rest); - this.api = new Router(this.rest).createProxy(); - this.cdn = CDN.createProxy(); - this.managers = new MainManager(this); - } - rest: BiscuitREST; - api: Routes; - cdn: CDNRoutes; - managers: MainManager; - gateway!: When; - private _applicationId?: string; - private _botId?: string; - - override on(event: `${K}`, func: Handler[K]): this; - override on(event: `${K}`, func: (...args: unknown[]) => unknown): this { - const ev = super.on(event, func); - - // @ts-expect-error Eventemitter can sometimes return a listener - return ev.emitter ? ev.emitter : ev; - } - override off(event: `${K}`, func: Handler[K]): this; - override off(event: `${K}`, func: (...args: unknown[]) => unknown): this { - return super.off(event, func); - } - - override once(event: `${K}`, func: Handler[K]): this; - override once(event: `${K}`, func: (...args: unknown[]) => unknown): this { - const ev = super.on(event, func); - - // @ts-expect-error Eventemitter can sometimes return a listener - return ev.emitter ? ev.emitter : ev; - } - - override emit(event: `${K}`, ...params: Parameters): boolean; - override emit(event: `${K}`, ...params: unknown[]): boolean { - return super.emit(event, ...params); - } - - set botId(id: string) { - this._botId = id; - } - - set applicationId(id: string) { - this._applicationId = id; - } - - get botId() { - return this._botId ?? getBotIdFromToken(this.options.token); - } - - get applicationId() { - return this._applicationId ?? this.botId; - } - - private createRest(rest: any) { - if (!rest) { - return new BiscuitREST({ - token: this.options.token, - ...this.options.defaultRestOptions - }); - } - - if (rest instanceof BiscuitREST || rest.cRest) { - return rest; - } - - throw new Error('[CORE] REST not found'); - } - - async start() { - // alias fixed `this` on handlePayload - const ctx = this as Session; - - ctx.gateway = new ShardManager({ - token: this.options.token, - intents: this.options.intents ?? 0, - info: this.options.defaultGatewayOptions?.info ?? (await this.api.gateway.bot.get()), - async handlePayload(shard, data) { - const { t, d } = data; - if (!(t && d)) return; - // @ts-expect-error - actionHandler([ctx, { t, d }, shard]); - }, - ...this.options.defaultGatewayOptions - }); - - ctx.once('READY', (payload) => { - const { user, application } = payload; - this.botId = user.id; - this.applicationId = application.id; - }); - - await ctx.gateway.spawnShards(); - } - - async stop() { - this.removeAllListeners(); - await this.gateway.disconnectAll(); - } -} - -export type HandlePayload = Pick['handlePayload']; - -export interface BiscuitOptions { - token: string; - intents: number | GatewayIntentBits; - rest?: BiscuitREST; - defaultRestOptions?: Partial; - defaultGatewayOptions?: Identify>>; -} diff --git a/packages/core/src/utils/types.ts b/packages/core/src/utils/types.ts deleted file mode 100644 index d692ca6..0000000 --- a/packages/core/src/utils/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { ImageFormat } from '@biscuitland/common'; - -export type EditNickname = { nick?: string; reason?: string }; - -/** - * @link https://discord.com/developers/docs/reference#image-formatting - */ -export type ImageSize = 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096; -export type ImageOptions = { - format?: ImageFormat; - size?: ImageSize; -}; - -export enum ThreadTypes { - AnnouncementThread = 10, - PublicThread = 11, - PrivateThread = 12 -} diff --git a/packages/core/src/utils/utils.ts b/packages/core/src/utils/utils.ts deleted file mode 100644 index 627a6c5..0000000 --- a/packages/core/src/utils/utils.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { ReplaceRegex } from '@biscuitland/common'; -import { DiscordEpoch } from '@biscuitland/common'; -import { ImageFormat } from '@biscuitland/common'; -import type { ImageSize } from './types'; - -/** - * Convert a timestamp to a snowflake. - * @param timestamp The timestamp to convert. - * @returns The snowflake. - */ -export function snowflakeToTimestamp(id: string): number { - return (Number(id) >> 22) + DiscordEpoch; -} - -/** - * Format an image URL. - * @param url The URL to format. - * @param size The size of the image. - * @param format The format of the image. - * @returns The formatted URL. - */ -export function formatImageURL(url: string, size: ImageSize = 128, format?: ImageFormat): string { - return `${url}.${format ?? (url.includes('/a_') ? 'gif' : 'jpg')}?size=${size}`; -} - -/** - * Get the bot ID from a token. - * @param token The token to get the bot ID from. - * @returns The bot ID. - * @warning Discord staff has mentioned this may not be stable forever xd. - */ -export function getBotIdFromToken(token: string): string { - return Buffer.from(token.split('.')[0], 'base64').toString('ascii'); -} - -/** - * Convert an object to a URLSearchParams object. - * @param obj The object to convert. - * @returns The URLSearchParams object. - */ -export function objectToParams(obj: object): URLSearchParams { - const query = new URLSearchParams(); - for (const [key, value] of Object.entries(obj)) { - if (!value) continue; - query.append(ReplaceRegex.snake(key), String(value)); - } - - return query; -} - -/** - * Get the channel link from a channel ID and guild ID. - * - * @param channelId The channel ID. - * @param guildId The guild ID. - * @returns The channel link. - */ -export function channelLink(channelId: string, guildId?: string) { - return `https://discord.com/channels/${guildId ?? '@me'}/${channelId}`; -} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json deleted file mode 100644 index 9b4f197..0000000 --- a/packages/core/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "include": ["src/**/*"] -} diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts deleted file mode 100644 index dfbea63..0000000 --- a/packages/core/tsup.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'tsup'; - -const isProduction = process.env.NODE_ENV === 'production'; - -export default defineConfig({ - clean: true, - dts: true, - entry: ['src/index.ts'], - format: ['cjs', 'esm'], - minify: isProduction, - sourcemap: false -}); diff --git a/packages/helpers/CHANGELOG.md b/packages/helpers/CHANGELOG.md deleted file mode 100644 index 6152f50..0000000 --- a/packages/helpers/CHANGELOG.md +++ /dev/null @@ -1,52 +0,0 @@ -# @biscuitland/helpers - -## 3.0.14 - -### Patch Changes - -- new changes -- new changes - -## 3.0.11 - -### Patch Changes - -- Updated dependencies - - @biscuitland/common@0.0.8 - -## 3.0.10 - -### Patch Changes - -- Updated dependencies - - @biscuitland/common@0.0.7 - -## 3.0.9 - -### Patch Changes - -- I meessed up -- Updated dependencies - - @biscuitland/common@0.0.6 - -## 3.0.8 - -### Patch Changes - -- fix: logger on every module -- Updated dependencies - - @biscuitland/common@0.0.5 - -## 3.0.7 - -### Patch Changes - -- fix mixer - -## 3.0.6 - -### Patch Changes - -- first 3.0.\* without bugs -- Updated dependencies - - @biscuitland/common@0.0.4 diff --git a/packages/helpers/README.md b/packages/helpers/README.md deleted file mode 100644 index 8a49d07..0000000 --- a/packages/helpers/README.md +++ /dev/null @@ -1,21 +0,0 @@ -# @biscuitland/helpers -## Most importantly, helpers is: -A collection of builders to make your life easier, not built into the core library due to performance concerns. - -[](https://github.com/oasisjs/biscuit) -[](https://discord.gg/XNw2RZFzaP) - -biscuit - -## Install (for [node18](https://nodejs.org/en/download/)) - -```sh-session -npm install @biscuitland/helpers -yarn add @biscuitland/helpers -``` - -## Links -* [Website](https://biscuitjs.com/) -* [Documentation](https://docs.biscuitjs.com/) -* [Discord](https://discord.gg/XNw2RZFzaP) -* [core](https://www.npmjs.com/package/@biscuitland/core) | [rest](https://www.npmjs.com/package/@biscuitland/rest) | [ws](https://www.npmjs.com/package/@biscuitland/ws) \ No newline at end of file diff --git a/packages/helpers/package.json b/packages/helpers/package.json deleted file mode 100644 index 7275302..0000000 --- a/packages/helpers/package.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "name": "@biscuitland/helpers", - "version": "3.0.14", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "files": [ - "dist/**" - ], - "scripts": { - "build": "tsup", - "clean": "rm -rf dist && rm -rf .turbo", - "dev": "tsup --watch" - }, - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.mjs" - }, - "require": "./dist/index.js" - } - }, - "dependencies": { - "@biscuitland/common": "^0.0.10", - "ts-mixer": "^6.0.3" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "tsup": "^7.0.0" - }, - "license": "Apache-2.0", - "author": "Yuzuru ", - "contributors": [ - { - "name": "Yuzuru", - "url": "https://github.com/yuzudev", - "author": true - }, - { - "name": "miia", - "url": "https://github.com/dragurimu" - }, - { - "name": "n128", - "url": "https://github.com/nicolito128" - }, - { - "name": "socram03", - "url": "https://github.com/socram03" - }, - { - "name": "Drylozu", - "url": "https://github.com/Drylozu" - } - ], - "homepage": "https://biscuitjs.com", - "repository": { - "type": "git", - "url": "git+https://github.com/oasisjs/biscuit.git" - }, - "bugs": { - "url": "https://github.com/oasisjs/biscuit" - }, - "keywords": [ - "api", - "discord", - "bots", - "typescript", - "botdev" - ], - "publishConfig": { - "access": "public" - } -} diff --git a/packages/helpers/src/Collector.ts b/packages/helpers/src/Collector.ts deleted file mode 100644 index 507922e..0000000 --- a/packages/helpers/src/Collector.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { EventEmitter } from 'node:events'; -import { MakeRequired, Options } from '@biscuitland/common'; -import { Handler, type Session } from '@biscuitland/core'; -import { GatewayEvents } from '@biscuitland/ws'; - -interface CollectorOptions { - event: `${E}`; - filter?: (...args: Parameters) => unknown; - max?: number; - time?: number; - idle?: number; -} - -export const DEFAULT_OPTIONS = { - filter: () => true, - max: -1 -}; - -export enum CollectorStatus { - Idle = 0, - Started = 1, - Ended = 2 -} - -export class EventCollector extends EventEmitter { - collected = new Set[0]>(); - status: CollectorStatus = CollectorStatus.Idle; - options: MakeRequired, 'filter' | 'max'>; - private timeout: NodeJS.Timeout | null = null; - - constructor(readonly session: Session, rawOptions: CollectorOptions) { - super(); - this.options = Options(DEFAULT_OPTIONS, rawOptions); - } - - start() { - this.session.setMaxListeners(this.session.getMaxListeners() + 1); - this.session.on(this.options.event, (...args: unknown[]) => this.collect(...(args as Parameters))); - this.timeout = setTimeout(() => this.stop('time'), this.options.idle ?? this.options.time); - } - - private collect(...args: Parameters) { - if (this.options.filter?.(...args)) { - this.collected.add(args[0]); - this.emit('collect', ...args); - } - - if (this.options.idle) { - if (this.timeout) clearTimeout(this.timeout); - this.timeout = setTimeout(() => this.stop('time'), this.options.idle); - } - - if (this.collected.size >= this.options.max!) this.stop('max'); - } - - stop(reason = 'User stopped') { - if (this.status === CollectorStatus.Ended) return; - - if (this.timeout) clearTimeout(this.timeout); - - this.session.removeListener(this.options.event, (...args: unknown[]) => this.collect(...(args as Parameters))); - this.session.setMaxListeners(this.session.getMaxListeners() - 1); - - this.status = CollectorStatus.Ended; - this.emit('end', reason, this.collected); - } - - on(event: 'collect', listener: (...args: Parameters) => unknown): this; - on(event: 'end', listener: (reason: string | null | undefined, collected: Set[0]>) => void): this; - on(event: string, listener: unknown): this { - return super.on(event, listener as () => unknown); - } - - once(event: 'collect', listener: (...args: Parameters) => unknown): this; - once(event: 'end', listener: (reason: string | null | undefined, collected: Set[0]>) => void): this; - once(event: string, listener: unknown): this { - return super.once(event, listener as () => unknown); - } -} diff --git a/packages/helpers/src/MessageEmbed.ts b/packages/helpers/src/MessageEmbed.ts deleted file mode 100644 index f7352b1..0000000 --- a/packages/helpers/src/MessageEmbed.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter, ObjectToLower, TypeArray, toSnakeCase } from '@biscuitland/common'; - -export class MessageEmbed { - constructor(public data: Partial = {}) { - if (!data.fields) this.data.fields = []; - } - - setAuthor(author: ObjectToLower): this { - this.data.author = toSnakeCase(author); - return this; - } - - // TODO: Color resolve - setColor(color: number): this { - this.data.color = color; - return this; - } - - setDescription(desc: string): this { - this.data.description = desc; - return this; - } - - addFields(field: TypeArray): this { - this.data.fields = this.data.fields!.concat(field); - return this; - } - - setFields(fields: APIEmbedField[]): this { - this.data.fields = fields; - return this; - } - - setFooter(footer: ObjectToLower): this { - this.data.footer = toSnakeCase(footer); - return this; - } - - setImage(url: string): this { - this.data.image = { url }; - return this; - } - - setTimestamp(time: string | number | Date = Date.now()): this { - this.data.timestamp = new Date(time).toISOString(); - return this; - } - - setTitle(title: string): this { - this.data.title = title; - return this; - } - - setURL(url: string): this { - this.data.url = url; - return this; - } - - toJSON(): APIEmbed { - return { ...this.data }; - } -} diff --git a/packages/helpers/src/Permissions.ts b/packages/helpers/src/Permissions.ts deleted file mode 100644 index a5339a7..0000000 --- a/packages/helpers/src/Permissions.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { PermissionFlagsBits } from '@biscuitland/common'; - -export type PermissionsStrings = keyof typeof PermissionFlagsBits; -export type PermissionResolvable = bigint | PermissionsStrings | PermissionsStrings[] | PermissionsStrings | PermissionsStrings[]; - -export class Permissions { - /** Stores a reference to BitwisePermissionFlags */ - static Flags = PermissionFlagsBits; - - /** Falsy; Stores the lack of permissions*/ - static None = 0n; - - /** Stores all entity permissions */ - bitfield: bigint; - - /** - * Wheter to grant all other permissions to the administrator - * **Not to get confused with Permissions#admin** - */ - __admin__ = true; - - constructor(bitfield: PermissionResolvable) { - this.bitfield = Permissions.resolve(bitfield); - } - - /** Wheter the bitfield has the administrator flag */ - get admin(): boolean { - return this.has(Permissions.Flags.Administrator); - } - - get array(): PermissionsStrings[] { - // unsafe cast, do not edit - const permissions = Object.keys(Permissions.Flags) as PermissionsStrings[]; - return permissions.filter((bit) => this.has(bit)); - } - - add(...bits: PermissionResolvable[]): this { - let reduced = 0n; - for (const bit of bits) { - reduced |= Permissions.resolve(bit); - } - this.bitfield |= reduced; - return this; - } - - remove(...bits: PermissionResolvable[]): this { - let reduced = 0n; - for (const bit of bits) { - reduced |= Permissions.resolve(bit); - } - this.bitfield &= ~reduced; - return this; - } - - has(bit: PermissionResolvable): boolean { - const bbit = Permissions.resolve(bit); - - if (this.__admin__ && this.bitfield & BigInt(Permissions.Flags.Administrator)) { - return true; - } - - return (this.bitfield & bbit) === bbit; - } - - any(bit: PermissionResolvable): boolean { - const bbit = Permissions.resolve(bit); - - if (this.__admin__ && this.bitfield & BigInt(Permissions.Flags.Administrator)) { - return true; - } - - return (this.bitfield & bbit) !== Permissions.None; - } - - equals(bit: PermissionResolvable): boolean { - return !!(this.bitfield & Permissions.resolve(bit)); - } - - /** Gets all permissions */ - static get All(): bigint { - let reduced = 0n; - for (const key in PermissionFlagsBits) { - const perm = PermissionFlagsBits[key]; - - reduced = reduced | perm; - } - return reduced; - } - - static resolve(bit: PermissionResolvable): bigint { - switch (typeof bit) { - case 'bigint': - return bit; - case 'number': - return BigInt(bit); - case 'string': - return BigInt(Permissions.Flags[bit]); - case 'object': - return Permissions.resolve( - bit - .map((p) => (typeof p === 'string' ? BigInt(Permissions.Flags[p]) : BigInt(p))) - .reduce((acc, cur) => acc | cur, Permissions.None) - ); - default: - throw new TypeError(`Cannot resolve permission: ${bit}`); - } - } - - static sum(permissions: (bigint | number)[]) { - return permissions.reduce((y, x) => BigInt(y) | BigInt(x), Permissions.None); - } - - static reduce(permissions: PermissionResolvable[]): Permissions { - const solved = permissions.map(Permissions.resolve); - - return new Permissions(solved.reduce((y, x) => y | x, Permissions.None)); - } - - *[Symbol.iterator]() { - yield* this.array; - } - - valueOf() { - return this.bitfield; - } - - toJSON(): { fields: string[] } { - const fields = Object.keys(Permissions.Flags).filter((bit) => typeof bit === 'number' && this.has(bit)); - - return { fields }; - } -} diff --git a/packages/helpers/src/Utils.ts b/packages/helpers/src/Utils.ts deleted file mode 100644 index 4bc3e95..0000000 --- a/packages/helpers/src/Utils.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { APIMessageActionRowComponent, APIModalActionRowComponent, ComponentType } from '@biscuitland/common'; -import { - ChannelSelectMenu, - MentionableSelectMenu, - MessageButton, - ModalTextInput, - RoleSelectMenu, - StringSelectMenu, - UserSelectMenu -} from './components'; -import { BaseComponent } from './components/BaseComponent'; - -export function createComponent(data: APIMessageActionRowComponent): HelperComponents; -export function createComponent(data: APIModalActionRowComponent): HelperComponents; -export function createComponent(data: HelperComponents): HelperComponents; -export function createComponent(data: HelperComponents | APIMessageActionRowComponent | APIModalActionRowComponent): HelperComponents { - if (data instanceof BaseComponent) { - return data; - } - - switch (data.type) { - case ComponentType.Button: - return new MessageButton(data); - case ComponentType.StringSelect: - return new StringSelectMenu(data); - case ComponentType.TextInput: - return new ModalTextInput(data); - case ComponentType.UserSelect: - return new UserSelectMenu(data); - case ComponentType.RoleSelect: - return new RoleSelectMenu(data); - case ComponentType.MentionableSelect: - return new MentionableSelectMenu(data); - case ComponentType.ChannelSelect: - return new ChannelSelectMenu(data); - } -} - -export type OptionValuesLength = { max: number; min: number }; -export type MessageSelectMenus = RoleSelectMenu | UserSelectMenu | StringSelectMenu | ChannelSelectMenu | MentionableSelectMenu; -export type MessageComponents = MessageButton | MessageSelectMenus; -export type HelperComponents = MessageComponents | ModalTextInput; diff --git a/packages/helpers/src/commands/contextMenu/ContextCommand.ts b/packages/helpers/src/commands/contextMenu/ContextCommand.ts deleted file mode 100644 index 7200efb..0000000 --- a/packages/helpers/src/commands/contextMenu/ContextCommand.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { ApplicationCommandType, LocalizationMap, RESTPostAPIContextMenuApplicationCommandsJSONBody } from '@biscuitland/common'; -import { PermissionResolvable, Permissions } from '../../Permissions'; - -export type ContextCommandType = ApplicationCommandType.Message | ApplicationCommandType.User; - -export class ContextCommand { - name: string = undefined!; - name_localizations?: LocalizationMap; - type: ContextCommandType = undefined!; - default_permission: boolean | undefined = undefined; - default_member_permissions: string | undefined = undefined; - dm_permission: boolean | undefined = undefined; - - setName(name: string): this { - this.name = name; - return this; - } - - setType(type: ContextCommandType) { - this.type = type; - return this; - } - - addNameLocalizations(locals: LocalizationMap): this { - this.name_localizations = locals; - Reflect; - return this; - } - - setDMPermission(value = true): this { - this.dm_permission = value; - return this; - } - - setDefautlMemberPermissions(permissions: PermissionResolvable[]): this { - this.default_member_permissions = Permissions.reduce(permissions).bitfield.toString(); - return this; - } - - toJSON(): RESTPostAPIContextMenuApplicationCommandsJSONBody { - return { ...this }; - } -} diff --git a/packages/helpers/src/commands/index.ts b/packages/helpers/src/commands/index.ts deleted file mode 100644 index 47bc1e4..0000000 --- a/packages/helpers/src/commands/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './contextMenu/ContextCommand'; -export * from './slash/SlashCommand'; -export * from './slash/SlashCommandOption'; diff --git a/packages/helpers/src/commands/slash/SlashCommand.ts b/packages/helpers/src/commands/slash/SlashCommand.ts deleted file mode 100644 index c79fe32..0000000 --- a/packages/helpers/src/commands/slash/SlashCommand.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ApplicationCommandType, RESTPostAPIChatInputApplicationCommandsJSONBody } from '@biscuitland/common'; -import { Mixin } from 'ts-mixer'; -import { PermissionResolvable, Permissions } from '../../Permissions'; -import { AllSlashOptions, SlashSubcommandGroupOption, SlashSubcommandOption } from './SlashCommandOption'; - -class SlashCommandB { - constructor(public data: Partial = {}) {} - - setDMPermission(value = true): this { - this.data.dm_permission = value; - return this; - } - - setNSFW(value = true): this { - this.data.nsfw = value; - return this; - } - - setDefautlMemberPermissions(permissions: PermissionResolvable[]): this { - this.data.default_member_permissions = Permissions.reduce(permissions).bitfield.toString(); - return this; - } - - addSubcommandGroup(fn: (option: SlashSubcommandGroupOption) => SlashSubcommandGroupOption): this { - const option = fn(new SlashSubcommandGroupOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addSubcommand(fn: (option: SlashSubcommandOption) => SlashSubcommandOption): this { - const option = fn(new SlashSubcommandOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addRawOption(option: ReturnType) { - this.data.options ??= []; - // @ts-expect-error discord-api-types bad typing, again - this.data.options.push(option); - } - - toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody { - return { - ...this.data, - type: ApplicationCommandType.ChatInput - } as RESTPostAPIChatInputApplicationCommandsJSONBody & { - type: ApplicationCommandType.ChatInput; - }; - } -} - -export const SlashCommand = Mixin(SlashCommandB, SlashSubcommandOption); -export type SlashCommand = InstanceType; diff --git a/packages/helpers/src/commands/slash/SlashCommandOption.ts b/packages/helpers/src/commands/slash/SlashCommandOption.ts deleted file mode 100644 index f78b693..0000000 --- a/packages/helpers/src/commands/slash/SlashCommandOption.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { - APIApplicationCommandAttachmentOption, - APIApplicationCommandBooleanOption, - APIApplicationCommandChannelOption, - APIApplicationCommandIntegerOption as AACIO, - APIApplicationCommandMentionableOption, - APIApplicationCommandNumberOption as AACNO, - APIApplicationCommandOption, - APIApplicationCommandOptionBase, - APIApplicationCommandOptionChoice, - APIApplicationCommandRoleOption, - APIApplicationCommandStringOption as AACSO, - APIApplicationCommandSubcommandGroupOption as AACSGO, - APIApplicationCommandSubcommandOption as AACSCO, - APIApplicationCommandUserOption, - ApplicationCommandOptionType, - ChannelType, - LocalizationMap, - RestToKeys, - TypeArray, - When -} from '@biscuitland/common'; -import { OptionValuesLength } from '../../'; - -export type SlashBaseOptionTypes = - | Exclude - | APIApplicationCommandStringOption - | APIApplicationCommandNumberOption - | APIApplicationCommandIntegerOption - | APIApplicationCommandSubcommandOption; - -export type ApplicationCommandBasicOptions = - | APIApplicationCommandAttachmentOption - | APIApplicationCommandChannelOption - | APIApplicationCommandIntegerOption - | APIApplicationCommandMentionableOption - | APIApplicationCommandNumberOption - | APIApplicationCommandStringOption - | APIApplicationCommandRoleOption - | APIApplicationCommandBooleanOption - | APIApplicationCommandUserOption; - -export abstract class SlashBaseOption { - constructor(public data: Partial = {}) {} - - setName(name: string): this { - this.data.name = name; - return this; - } - - setDesciption(desc: string): this { - this.data.description = desc; - return this; - } - - addLocalizations(locals: RestToKeys<[LocalizationMap, 'name', 'description']>): this { - this.data.name_localizations = locals.name; - this.data.description_localizations = locals.description; - return this; - } - - toJSON(): DataType { - return { ...this.data } as DataType; - } -} - -export type SlashRequiredOptionTypes = Exclude; - -export class SlashRequiredOption extends SlashBaseOption { - setRequired(required = true): this { - this.data.required = required; - return this; - } -} - -/** - * Temporal fix type - * I didn't find the correct way to set this with discord-api-types - * Author: socram03 - */ -export interface APIApplicationCommandStringOption - extends APIApplicationCommandOptionBase { - /** - * For option type `STRING`, the minimum allowed length (minimum of `0`, maximum of `6000`). - */ - min_length?: number; - /** - * For option type `STRING`, the maximum allowed length (minimum of `1`, maximum of `6000`). - */ - max_length?: number; - - autocomplete: When; - - choices: When[], never>; -} - -export class SlashStringOption extends SlashRequiredOption> { - constructor(data: Partial> = {}) { - super({ ...data, type: ApplicationCommandOptionType.String }); - } - - addChoices(choices: TypeArray>): SlashStringOption { - const ctx = this as SlashStringOption; - ctx.data.choices ??= []; - ctx.data.choices = ctx.data.choices!.concat(choices); - return ctx; - } - - setAutocomplete(auto = true): SlashStringOption { - const ctx = this as SlashStringOption; - ctx.data.autocomplete = auto; - return ctx; - } - - setLength({ min, max }: OptionValuesLength): this { - this.data.min_length = min; - this.data.max_length = max; - return this; - } -} - -/** - * Temporal fix type - * I didn't find the correct way to set this with discord-api-types - * Author: socram03 - */ -interface APIApplicationCommandNumberOption - extends APIApplicationCommandOptionBase { - /** - * If the option is an `INTEGER` or `NUMBER` type, the minimum value permitted. - */ - min_value?: number; - /** - * If the option is an `INTEGER` or `NUMBER` type, the maximum value permitted. - */ - max_value?: number; - - autocomplete: When; - - choices: When[], never>; -} - -export class SlashNumberOption extends SlashRequiredOption> { - constructor(data: Partial> = {}) { - super({ ...data, type: ApplicationCommandOptionType.Number }); - } - - addChoices(choices: TypeArray>): SlashNumberOption { - const ctx = this as SlashNumberOption; - ctx.data.choices ??= []; - ctx.data.choices = ctx.data.choices.concat(choices); - return ctx; - } - - setValueRange({ min, max }: OptionValuesLength): this { - this.data.max_value = max; - this.data.min_value = min; - return this; - } - - setAutocomplete(auto = true): SlashNumberOption { - const ctx = this as SlashNumberOption; - ctx.data.autocomplete = auto; - return ctx; - } -} - -/** - * Temporal fix type - * I didn't find the correct way to set this with discord-api-types - * Author: socram03 - */ -interface APIApplicationCommandIntegerOption - extends APIApplicationCommandOptionBase { - /** - * If the option is an `INTEGER` or `NUMBER` type, the minimum value permitted. - */ - min_value?: number; - /** - * If the option is an `INTEGER` or `NUMBER` type, the maximum value permitted. - */ - max_value?: number; - - autocomplete: When; - - choices: When[], never>; -} - -export class SlashIntegerOption extends SlashRequiredOption> { - constructor(data: Partial> = {}) { - super({ ...data, type: ApplicationCommandOptionType.Integer }); - } -} - -export class SlashUserOption extends SlashRequiredOption { - constructor(data: Partial = {}) { - super({ ...data, type: ApplicationCommandOptionType.User }); - } -} - -export type SlashChannelOptionChannelTypes = Exclude; - -export class SlashChannelOption extends SlashRequiredOption { - constructor(data: Partial = {}) { - super({ ...data, type: ApplicationCommandOptionType.Channel }); - } - - setChannelTypes(types: SlashChannelOptionChannelTypes[]): this { - this.data.channel_types = types; - return this; - } -} - -export class SlashRoleOption extends SlashRequiredOption { - constructor(data: Partial = {}) { - super({ ...data, type: ApplicationCommandOptionType.Role }); - } -} - -export class SlashMentionableOption extends SlashRequiredOption { - constructor(data: Partial = {}) { - super({ ...data, type: ApplicationCommandOptionType.Mentionable }); - } -} - -export class SlashAttachmentOption extends SlashRequiredOption { - constructor(data: Partial = {}) { - super({ ...data, type: ApplicationCommandOptionType.Attachment }); - } -} - -export class SlashBooleanOption extends SlashRequiredOption { - constructor(data: Partial = {}) { - super({ ...data, type: ApplicationCommandOptionType.Boolean }); - } -} - -export type BasicSlashOptions = - | SlashStringOption - | SlashAttachmentOption - | SlashChannelOption - | SlashIntegerOption - | SlashNumberOption - | SlashRoleOption - | SlashMentionableOption - | SlashUserOption - | SlashBooleanOption; - -export type APIApplicationCommandSubcommandOption = AACSCO & { - options?: ApplicationCommandBasicOptions[]; -}; - -export class SlashSubcommandOption extends SlashBaseOption { - constructor(data: Partial = {}) { - super({ ...data, type: ApplicationCommandOptionType.Subcommand }); - } - - addStringOption(fn: (option: SlashStringOption) => SlashStringOption): this { - const option = fn(new SlashStringOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addNumberOption(fn: (option: SlashNumberOption) => SlashNumberOption): this { - const option = fn(new SlashNumberOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addIntegerOption(fn: (option: SlashIntegerOption) => SlashIntegerOption): this { - const option = fn(new SlashIntegerOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addChannelOption(fn: (option: SlashChannelOption) => SlashChannelOption): this { - const option = fn(new SlashChannelOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addUserOption(fn: (option: SlashUserOption) => SlashUserOption): this { - const option = fn(new SlashUserOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addRoleOption(fn: (option: SlashRoleOption) => SlashRoleOption): this { - const option = fn(new SlashRoleOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addMentionableOption(fn: (option: SlashMentionableOption) => SlashMentionableOption): this { - const option = fn(new SlashMentionableOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addAttachmentOption(fn: (option: SlashAttachmentOption) => SlashAttachmentOption): this { - const option = fn(new SlashAttachmentOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addBooleanOption(fn: (option: SlashBooleanOption) => SlashBooleanOption): this { - const option = fn(new SlashBooleanOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addRawOption(option: ApplicationCommandBasicOptions) { - this.data.options ??= []; - this.data.options.push(option); - } -} - -export type APIApplicationCommandSubcommandGroupOption = AACSGO & { - options?: APIApplicationCommandSubcommandOption[]; -}; - -export type AllSlashOptions = BasicSlashOptions | SlashSubcommandGroupOption | SlashSubcommandOption; - -export class SlashSubcommandGroupOption extends SlashBaseOption { - constructor(data: Partial = {}) { - if (!data.options) data.options = []; - super({ ...data, type: ApplicationCommandOptionType.SubcommandGroup }); - } - - addSubCommand(fn: (option: SlashSubcommandOption) => SlashSubcommandOption): this { - const option = fn(new SlashSubcommandOption()); - this.addRawOption(option.toJSON()); - return this; - } - - addRawOption(option: ReturnType) { - this.data.options ??= []; - this.data.options.push(option); - } -} diff --git a/packages/helpers/src/components/ActionRow.ts b/packages/helpers/src/components/ActionRow.ts deleted file mode 100644 index dfe6f55..0000000 --- a/packages/helpers/src/components/ActionRow.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { APIActionRowComponent, APIMessageActionRowComponent, ComponentType, TypeArray } from '@biscuitland/common'; -import { MessageComponents, createComponent } from '../Utils'; -import { BaseComponent } from './BaseComponent'; - -export class MessageActionRow extends BaseComponent> { - constructor({ components, ...data }: Partial> = {}) { - super({ ...data, type: ComponentType.ActionRow }); - this.components = (components?.map(createComponent) ?? []) as T[]; - } - components: T[]; - - addComponents(component: TypeArray): this { - this.components = this.components.concat(component); - return this; - } - - setComponents(component: T[]): this { - this.components = [...component]; - return this; - } - - toJSON(): APIActionRowComponent { - return { - ...this.data, - components: this.components.map((c) => c.toJSON()) - } as APIActionRowComponent>; - } -} diff --git a/packages/helpers/src/components/BaseComponent.ts b/packages/helpers/src/components/BaseComponent.ts deleted file mode 100644 index c88dcf9..0000000 --- a/packages/helpers/src/components/BaseComponent.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { APIBaseComponent, ComponentType } from '@biscuitland/common'; - -export abstract class BaseComponent> = APIBaseComponent,> { - constructor(public data: Partial) {} - - toJSON(): TYPE { - return { ...this.data } as TYPE; - } -} diff --git a/packages/helpers/src/components/MessageButton.ts b/packages/helpers/src/components/MessageButton.ts deleted file mode 100644 index 9c03f36..0000000 --- a/packages/helpers/src/components/MessageButton.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { APIButtonComponentBase, APIMessageComponentEmoji, ButtonStyle, ComponentType, When } from '@biscuitland/common'; -import { BaseComponent } from './BaseComponent'; - -export type ButtonStylesForID = Exclude; - -export interface APIButtonComponent - extends APIButtonComponentBase> { - url: When; - - custom_id: When; -} - -export class MessageButton extends BaseComponent> { - constructor(data: Partial> = {}) { - super({ ...data, type: ComponentType.Button }); - } - - setLabel(label: string): this { - this.data.label = label; - return this; - } - - setEmoji(emoji: APIMessageComponentEmoji): this { - this.data.emoji = emoji; - return this; - } - - setDisabled(disabled = true): this { - this.data.disabled = disabled; - return this; - } - - setURL(url: string): MessageButton { - const ctx = this as MessageButton; - ctx.data.url = url; - return ctx; - } - - setStyle(style: When): this { - this.data.style = style; - return this; - } - - setCustomId(id: string): MessageButton { - const ctx = this as MessageButton; - ctx.data.custom_id = id; - return ctx; - } -} diff --git a/packages/helpers/src/components/SelectMenu.ts b/packages/helpers/src/components/SelectMenu.ts deleted file mode 100644 index 6edcdec..0000000 --- a/packages/helpers/src/components/SelectMenu.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { - APIChannelSelectComponent, - APIMentionableSelectComponent, - APIMessageComponentEmoji, - APIRoleSelectComponent, - APISelectMenuComponent, - APISelectMenuOption, - APIStringSelectComponent, - APIUserSelectComponent, - ChannelType, - ComponentType, - TypeArray -} from '@biscuitland/common'; -import { OptionValuesLength } from '..'; -import { BaseComponent } from './BaseComponent'; - -class SelectMenu { - setCustomId(id: string): this { - this.data.custom_id = id; - return this; - } - - setPlaceholder(placeholder: string): this { - this.data.placeholder = placeholder; - return this; - } - - setValuesLength({ max, min }: Partial): this { - this.data.max_values = max; - this.data.min_values = min; - return this; - } - - setDisabled(disabled = true): this { - this.data.disabled = disabled; - return this; - } -} - -export class UserSelectMenu extends SelectMenu { - constructor(data: Partial = {}) { - super({ ...data, type: ComponentType.UserSelect }); - } -} - -export class RoleSelectMenu extends SelectMenu { - constructor(data: Partial = {}) { - super({ ...data, type: ComponentType.RoleSelect }); - } -} - -export class MentionableSelectMenu extends SelectMenu { - constructor(data: Partial = {}) { - super({ ...data, type: ComponentType.MentionableSelect }); - } -} - -export class ChannelSelectMenu extends SelectMenu { - constructor(data: Partial = {}) { - super({ ...data, type: ComponentType.ChannelSelect }); - } - - setChannelTypes(types: ChannelType[]): this { - this.data.channel_types = types; - return this; - } -} - -export class StringSelectMenu extends SelectMenu { - constructor(data: Partial = {}) { - super({ ...data, type: ComponentType.StringSelect }); - } - - addOption(option: TypeArray): this { - this.data.options ??= []; - this.data.options = this.data.options.concat(option); - return this; - } - - setOptions(options: APISelectMenuOption[]): this { - this.data.options = options; - return this; - } -} - -export class StringSelectOption { - // biome-ignore lint/nursery/noEmptyBlockStatements: - constructor(public data: Partial = {}) {} - - setLabel(label: string): this { - this.data.label = label; - return this; - } - - setValue(value: string): this { - this.data.value = value; - return this; - } - - setDescription(description: string): this { - this.data.description = description; - return this; - } - - setDefault(Default = true): this { - this.data.default = Default; - return this; - } - - setEmoji(emoji: APIMessageComponentEmoji): this { - this.data.emoji = emoji; - return this; - } - - toJSON(): APISelectMenuOption { - return { ...this.data } as APISelectMenuOption; - } -} diff --git a/packages/helpers/src/components/TextInput.ts b/packages/helpers/src/components/TextInput.ts deleted file mode 100644 index ade6b72..0000000 --- a/packages/helpers/src/components/TextInput.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { APITextInputComponent, ComponentType, TextInputStyle } from '@biscuitland/common'; -import { OptionValuesLength } from '..'; -import { BaseComponent } from './BaseComponent'; - -export class ModalTextInput extends BaseComponent { - constructor(data: Partial = {}) { - super({ ...data, type: ComponentType.TextInput }); - } - - setStyle(style: TextInputStyle): this { - this.data.style = style; - return this; - } - - setLabel(label: string): this { - this.data.label = label; - return this; - } - - setPlaceholder(placeholder: string): this { - this.data.placeholder = placeholder; - return this; - } - - setLength({ max, min }: Partial): this { - this.data.max_length = max; - this.data.min_length = min; - return this; - } - - setCustomId(id: string): this { - this.data.custom_id = id; - return this; - } - - setValue(value: string): this { - this.data.value = value; - return this; - } - - setRequired(required = true): this { - this.data.required = required; - return this; - } -} diff --git a/packages/helpers/src/components/index.ts b/packages/helpers/src/components/index.ts deleted file mode 100644 index f76ad29..0000000 --- a/packages/helpers/src/components/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './ActionRow'; -export * from './BaseComponent'; -export * from './MessageButton'; -export * from './SelectMenu'; -export * from './TextInput'; diff --git a/packages/helpers/src/index.ts b/packages/helpers/src/index.ts deleted file mode 100644 index b6dd0e5..0000000 --- a/packages/helpers/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './MessageEmbed'; -export * from './Permissions'; -export * from './Utils'; -export * from './commands'; -export * from './components'; diff --git a/packages/helpers/tsconfig.json b/packages/helpers/tsconfig.json deleted file mode 100644 index 9b4f197..0000000 --- a/packages/helpers/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "include": ["src/**/*"] -} diff --git a/packages/helpers/tsup.config.ts b/packages/helpers/tsup.config.ts deleted file mode 100644 index dfbea63..0000000 --- a/packages/helpers/tsup.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'tsup'; - -const isProduction = process.env.NODE_ENV === 'production'; - -export default defineConfig({ - clean: true, - dts: true, - entry: ['src/index.ts'], - format: ['cjs', 'esm'], - minify: isProduction, - sourcemap: false -}); diff --git a/packages/rest/CHANGELOG.md b/packages/rest/CHANGELOG.md deleted file mode 100644 index 604dd1f..0000000 --- a/packages/rest/CHANGELOG.md +++ /dev/null @@ -1,113 +0,0 @@ -# @biscuitland/rest - -## 3.0.6 - -### Patch Changes - -- I meessed up - -## 3.0.5 - -### Patch Changes - -- fix: logger on every module - -## 3.0.4 - -### Patch Changes - -- first 3.0.\* without bugs - -## 2.3.0 - -### Minor Changes - -- fix TODO - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.3.0 - -## 2.2.3 - -### Patch Changes - -- bug fixes -- Updated dependencies - - @biscuitland/api-types@2.2.3 - -## 2.2.2 - -### Patch Changes - -- rename guildLocales to guildLocale in interactions -- Updated dependencies - - @biscuitland/api-types@2.2.2 - -## 2.2.1 - -### Patch Changes - -- select menu options now can be empty since the latest Discord API update -- Updated dependencies - - @biscuitland/api-types@2.2.1 - -## 2.2.0 - -### Minor Changes - -- Functionality to delete ephemeral messages added, select menus were updated - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.2.0 - -## 2.1.2 - -### Patch Changes - -- minor changes -- Updated dependencies - - @biscuitland/api-types@2.1.2 - -## 2.1.1 - -### Patch Changes - -- dumb hotfix that LH asked for (blame Yuzu) -- Updated dependencies - - @biscuitland/api-types@2.1.1 - -## 2.1.0 - -### Minor Changes - -- Changes to cache and forum channels ✨ -- Forum channels and updates to @biscuitland/cache ✨ - -### Patch Changes - -- Updated dependencies -- Updated dependencies - - @biscuitland/api-types@2.1.0 - -## 2.0.6 - -### Patch Changes - -- Minor fixes -- Updated dependencies - - @biscuitland/api-types@2.0.6 - -## 2.0.5 - -### Major Changes - -- publish - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.0.5 diff --git a/packages/rest/README.md b/packages/rest/README.md deleted file mode 100644 index dddf1bb..0000000 --- a/packages/rest/README.md +++ /dev/null @@ -1,65 +0,0 @@ -# @biscuitland/rest -## Most importantly, biscuit's rest is: -A standalone rest library that is yet easy to use and easy to host on a serverless infrastructure, it is meant to be used with biscuit's libraries. - -[](https://github.com/oasisjs/biscuit) -[](https://discord.gg/XNw2RZFzaP) - -biscuit - -## Install (for [node18](https://nodejs.org/en/download/)) - -```sh-session -npm install @biscuitland/rest -yarn add @biscuitland/rest -``` - -## Example (Standalone rest) -```ts -import { BiscuitREST } from "@biscuitland/rest"; -import Fastify from "fastify"; - -const manager = new BiscuitREST({ - api: "http://any.rest.proxy/", - version: 10, - token: "your token goes here" -}); - -const app = Fastify({}); - -app.all("*", (req, reply) => { - let response: unknown; - - switch (req.method) { - case "GET": - response = await rest.get(req.url, req.body); - break; - case "POST": - response = await rest.post(req.url, req.body); - break; - case "PUT": - response = await rest.put(req.url, req.body); - break; - case "PATCH": - response = await rest.patch(req.url, req.body); - break; - case "DELETE": - response = await rest.delete(req.url, req.body); - break; - } - - if (response) - reply.status(200).send({ status: 200, data: response }); - - else - reply.status(204).send({ status: 204, data: null }); -}); - -app.listen({ port: "port..." }); -``` - -## Links -* [Website](https://biscuitjs.com/) -* [Documentation](https://docs.biscuitjs.com/) -* [Discord](https://discord.gg/XNw2RZFzaP) -* [core](https://www.npmjs.com/package/@biscuitland/core) | [ws](https://www.npmjs.com/package/@biscuitland/ws) | [helpers](https://www.npmjs.com/package/@biscuitland/helpers) diff --git a/packages/rest/package.json b/packages/rest/package.json deleted file mode 100644 index e794545..0000000 --- a/packages/rest/package.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "@biscuitland/rest", - "version": "3.0.7", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "files": [ - "dist/**" - ], - "scripts": { - "build": "tsup", - "clean": "rm -rf dist && rm -rf .turbo", - "dev": "tsup --watch" - }, - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.mjs" - }, - "require": "./dist/index.js" - } - }, - "devDependencies": { - "tsup": "^7.0.0" - }, - "license": "Apache-2.0", - "author": "Yuzuru ", - "contributors": [ - { - "name": "Yuzuru", - "url": "https://github.com/yuzudev" - }, - { - "name": "miia", - "url": "https://github.com/dragurimu" - }, - { - "name": "n128", - "url": "https://github.com/nicolito128" - }, - { - "name": "socram03", - "url": "https://github.com/socram03", - "author": true - }, - { - "name": "Drylozu", - "url": "https://github.com/Drylozu" - } - ], - "homepage": "https://biscuitjs.com", - "repository": { - "type": "git", - "url": "git+https://github.com/oasisjs/biscuit.git" - }, - "bugs": { - "url": "https://github.com/oasisjs/biscuit" - }, - "keywords": [ - "api", - "discord", - "bots", - "typescript", - "botdev" - ], - "publishConfig": { - "access": "public" - }, - "dependencies": { - "@discordjs/rest": "^2.0.0" - } -} \ No newline at end of file diff --git a/packages/rest/src/CDN.ts b/packages/rest/src/CDN.ts deleted file mode 100644 index 1b078fb..0000000 --- a/packages/rest/src/CDN.ts +++ /dev/null @@ -1,68 +0,0 @@ -export interface CDNRoutes { - embed: { - avatars: { - get(embed: UserAvatarDefault): string; - }; - }; - avatars(id: string): { - get(hash: string): string; - }; - icons(guildId: string): { - get(hash: string): string; - }; - splashes(guildId: string): { - get(hash: string): string; - }; - 'discovery-splashes'(guidId: string): { - get(hash: string): string; - }; - banners(id: string): { - get(hash: string): string; - }; - guilds(id: string): { - users(id: string): { - avatars(hash: string): { - get(): string; - }; - banners(hash: string): { - get(): string; - }; - }; - }; - emojis(id: string): { - get(): string; - }; - appIcons(appId: string): { - get(iconOrCover: string): string; - }; - 'app-assets'(appId: string): { - get(asset: string): string; - achievements(id: string): { - icons(hash: string): { - get(): string; - }; - }; - }; - 'team-icons'(teamId: string): { - get(hash: string): string; - }; - stickers(id: string): { - get(): string; - }; - 'role-icons'(roleId: string): { - get(icon: string): string; - }; - 'guild-events'(id: string): { - get(cover: string): string; - }; -} - -export interface CDNRoutes { - 'app-assets'(id: '710982414301790216'): { - store(packBannerId: string): { - get(): string; - }; - }; -} - -export type UserAvatarDefault = 1 | 2 | 3 | 4 | 5 | number; diff --git a/packages/rest/src/REST.ts b/packages/rest/src/REST.ts deleted file mode 100644 index 9cf5ec0..0000000 --- a/packages/rest/src/REST.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { Identify } from '@biscuitland/common'; -import type { RawFile, RequestData } from '@discordjs/rest'; -import { REST } from '@discordjs/rest'; -import type { RequestMethod } from './Router'; - -export class BiscuitREST { - api: REST; - constructor(public options: BiscuitRESTOptions) { - const { token, ...restOptions } = this.options; - this.api = new REST(restOptions).setToken(token); - } - - async get(route: string, options?: RequestObject): Promise { - const data = await this.api.get(route as `/${string}`, { - ...options, - query: options?.query ? new URLSearchParams(options.query) : undefined - }); - - return data as T; - } - - async post(route: string, body?: RequestObject): Promise { - const data = await this.api.post(route as `/${string}`, { - ...body, - body: body?.body, - query: body?.query ? new URLSearchParams(body.query) : undefined, - files: body?.files - }); - - return data as T; - } - - async put(route: string, body?: RequestObject): Promise { - const data = await this.api.put(route as `/${string}`, { - ...body, - body: body?.body, - query: body?.query ? new URLSearchParams(body.query) : undefined, - files: body?.files - }); - - return data as T; - } - - async patch(route: string, body?: RequestObject): Promise { - const data = await this.api.patch(route as `/${string}`, { - ...body, - body: body?.body, - query: body?.query ? new URLSearchParams(body.query) : undefined, - files: body?.files - }); - - return data as T; - } - - async delete(route: string, options?: RequestObject): Promise { - const data = await this.api.delete(route as `/${string}`, { - ...options, - query: options?.query ? new URLSearchParams(options.query) : undefined - }); - - return data as T; - } -} - -export type BiscuitRESTOptions = Identify[0] & { token: string }>; - -export type RequestOptions = Pick; - -export type RequestObject, Q = Record> = { - query?: Q; -} & RequestOptions & - (M extends `${RequestMethod.Get}` - ? unknown - : { - body?: B; - files?: RawFile[]; - }); - -export type RestArguments = any> = M extends RequestMethod.Get - ? Q extends never - ? RequestObject - : never - : RequestObject; diff --git a/packages/rest/src/Router.ts b/packages/rest/src/Router.ts deleted file mode 100644 index 900541b..0000000 --- a/packages/rest/src/Router.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { CDN_URL } from '@biscuitland/common'; -import type { CDNRoutes, Routes } from './'; -import { BiscuitREST } from './REST'; - -export enum RequestMethod { - Delete = 'delete', - Get = 'get', - Patch = 'patch', - Post = 'post', - Put = 'put' -} - -const ArrRequestsMethods = Object.values(RequestMethod) as string[]; - -export class Router { - noop = () => { - return; - }; - - constructor(private rest: BiscuitREST) {} - - createProxy(route = [] as string[]): Routes { - return new Proxy(this.noop, { - get: (_, key: string) => { - if (ArrRequestsMethods.includes(key)) { - return (...options: any[]) => this.rest[key](`/${route.join('/')}`, ...options); - } - return this.createProxy([...route, key]); - }, - apply: (...[, _, args]) => { - return this.createProxy([...route, ...args.filter((x) => x != null)]); - } - }) as unknown as Routes; - } -} - -export class CDN { - static createProxy(route = [] as string[]): CDNRoutes { - const noop = () => { - return; - }; - return new Proxy(noop, { - get: (_, key: string) => { - if (key === 'get') { - return (value?: string) => { - const lastRoute = `${CDN_URL}/${route.join('/')}`; - if (value) { - if (typeof value !== 'string') { - // rome-ignore lint/nursery/noParameterAssign: fix multiples value types - value = String(value); - } - return `${lastRoute}/${value}`; - } - return lastRoute; - }; - } - return this.createProxy([...route, key]); - }, - apply: (...[, _, args]) => { - return this.createProxy([...route, ...args.filter((x) => x != null)]); - } - }) as unknown as CDNRoutes; - } -} diff --git a/packages/rest/src/Routes/applications.ts b/packages/rest/src/Routes/applications.ts deleted file mode 100644 index 77ce2b9..0000000 --- a/packages/rest/src/Routes/applications.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { - RESTGetAPIApplicationCommandResult, - RESTGetAPIApplicationCommandsQuery, - RESTGetAPIApplicationCommandsResult, - RESTGetAPIApplicationGuildCommandResult, - RESTGetAPIApplicationGuildCommandsQuery, - RESTGetAPIApplicationGuildCommandsResult, - RESTGetAPIApplicationRoleConnectionMetadataResult, - RESTGetAPIGuildApplicationCommandsPermissionsResult, - RESTPatchAPIApplicationCommandJSONBody, - RESTPatchAPIApplicationCommandResult, - RESTPatchAPIApplicationGuildCommandJSONBody, - RESTPatchAPIApplicationGuildCommandResult, - RESTPostAPIApplicationCommandsJSONBody, - RESTPostAPIApplicationCommandsResult, - RESTPostAPIApplicationGuildCommandsJSONBody, - RESTPostAPIApplicationGuildCommandsResult, - RESTPutAPIApplicationCommandPermissionsJSONBody, - RESTPutAPIApplicationCommandsJSONBody, - RESTPutAPIApplicationCommandsResult, - RESTPutAPIApplicationGuildCommandsJSONBody, - RESTPutAPIApplicationGuildCommandsResult, - RESTPutAPIApplicationRoleConnectionMetadataJSONBody, - RESTPutAPIApplicationRoleConnectionMetadataResult, - RESTPutAPIGuildApplicationCommandsPermissionsResult -} from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface ApplicationRoutes { - applications: { - (id: string): { - guilds: { - (id: string): { - commands: { - get( - args?: RestArguments - ): Promise; - post( - args: RestArguments - ): Promise; - put( - args: RestArguments - ): Promise; - permissions: { - get(args?: RestArguments): Promise; - // put(args: RestArguments): Promise - }; - (id: string): { - get(args?: RestArguments): Promise; - patch( - args: RestArguments - ): Promise; - delete(args?: RestArguments): Promise; - permissions: { - get(args?: RestArguments): Promise; - put( - args: RestArguments - ): Promise; - }; - }; - }; - }; - }; - commands: { - get(args?: RestArguments): Promise; - post( - args: RestArguments - ): Promise; - put(args: RestArguments): Promise; - (id: string): { - get(args?: RestArguments): Promise; - patch( - args: RestArguments - ): Promise; - delete(args?: RestArguments): Promise; - }; - }; - 'role-connections': { - metadata: { - get(args?: RestArguments): Promise; - put( - args: RestArguments - ): Promise; - }; - }; - }; - }; -} diff --git a/packages/rest/src/Routes/channels.ts b/packages/rest/src/Routes/channels.ts deleted file mode 100644 index 5ee0992..0000000 --- a/packages/rest/src/Routes/channels.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { - RESTDeleteAPIChannelAllMessageReactionsResult, - RESTDeleteAPIChannelMessageReactionResult, - RESTDeleteAPIChannelMessageResult, - RESTDeleteAPIChannelPermissionResult, - RESTDeleteAPIChannelPinResult, - RESTDeleteAPIChannelRecipientResult, - RESTDeleteAPIChannelResult, - RESTDeleteAPIChannelThreadMembersResult, - RESTGetAPIChannelInvitesResult, - RESTGetAPIChannelMessageReactionUsersQuery, - RESTGetAPIChannelMessageReactionUsersResult, - RESTGetAPIChannelMessageResult, - RESTGetAPIChannelMessagesQuery, - RESTGetAPIChannelMessagesResult, - RESTGetAPIChannelPinsResult, - RESTGetAPIChannelResult, - RESTGetAPIChannelThreadMemberQuery, - RESTGetAPIChannelThreadMemberResult, - RESTGetAPIChannelThreadMembersQuery, - RESTGetAPIChannelThreadMembersResult, - RESTGetAPIChannelThreadsArchivedPrivateResult, - RESTGetAPIChannelThreadsArchivedPublicResult, - RESTGetAPIChannelThreadsArchivedQuery, - RESTGetAPIChannelUsersThreadsArchivedResult, - RESTGetAPIGuildWebhooksResult, - RESTPatchAPIChannelJSONBody, - RESTPatchAPIChannelMessageJSONBody, - RESTPatchAPIChannelMessageResult, - RESTPatchAPIChannelResult, - RESTPostAPIChannelFollowersJSONBody, - RESTPostAPIChannelFollowersResult, - RESTPostAPIChannelInviteJSONBody, - RESTPostAPIChannelInviteResult, - RESTPostAPIChannelMessageCrosspostResult, - RESTPostAPIChannelMessageJSONBody, - RESTPostAPIChannelMessageResult, - RESTPostAPIChannelMessagesBulkDeleteJSONBody, - RESTPostAPIChannelMessagesBulkDeleteResult, - RESTPostAPIChannelMessagesThreadsJSONBody, - RESTPostAPIChannelMessagesThreadsResult, - RESTPostAPIChannelThreadsJSONBody, - RESTPostAPIChannelThreadsResult, - RESTPostAPIChannelTypingResult, - RESTPostAPIChannelWebhookJSONBody, - RESTPostAPIChannelWebhookResult, - RESTPostAPIGuildForumThreadsJSONBody, - RESTPutAPIChannelMessageReactionResult, - RESTPutAPIChannelPermissionJSONBody, - RESTPutAPIChannelPermissionResult, - RESTPutAPIChannelPinResult, - RESTPutAPIChannelRecipientJSONBody, - RESTPutAPIChannelRecipientResult, - RESTPutAPIChannelThreadMembersResult -} from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface ChannelRoutes { - channels(id: string): { - //. - get(args?: RestArguments): Promise; - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - users: { - (id: '@me'): { - threads: { - archived: { - private: { - //. - get( - args?: RestArguments - ): Promise; - }; - }; - }; - }; - }; - 'thread-members': { - //. - get(args?: RestArguments): Promise; - (id: '@me'): { - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - threads: { - //. - post( - args: RestArguments - ): Promise; - archived: { - public: { - //. - get( - args?: RestArguments - ): Promise; - }; - private: { - //. - get( - args?: RestArguments - ): Promise; - }; - }; - }; - recipients: { - (id: string): { - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - pins: { - //. - get(args?: RestArguments): Promise; - (id: string): { - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - followers: { - //. - post(args: RestArguments): Promise; - }; - permissions: { - (id: string): { - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - invites: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - }; - messages: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - 'bulk-delete': { - //. - post( - args: RestArguments - ): Promise; - }; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - threads: { - //. - post( - args: RestArguments - ): Promise; - }; - crosspost: { - //. - post(args: RestArguments): Promise; - }; - reactions: { - //. - delete(args?: RestArguments): Promise; - (emoji: string): { - //. - get( - args?: RestArguments - ): Promise; - //. - delete(args?: RestArguments): Promise; - (id: '@me'): { - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - (id: string): { - //. - delete(args?: RestArguments): Promise; - }; - }; - }; - }; - }; - typing: { - //. - post(args?: RestArguments): Promise; - }; - webhooks: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - }; - }; -} diff --git a/packages/rest/src/Routes/gateway.ts b/packages/rest/src/Routes/gateway.ts deleted file mode 100644 index de46831..0000000 --- a/packages/rest/src/Routes/gateway.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RESTGetAPIGatewayBotResult, RESTGetAPIGatewayResult } from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface GatewayRoutes { - gateway: { - get(args?: RestArguments): Promise; - bot: { - get(args?: RestArguments): Promise; - }; - }; -} diff --git a/packages/rest/src/Routes/guilds.ts b/packages/rest/src/Routes/guilds.ts deleted file mode 100644 index fbc2f13..0000000 --- a/packages/rest/src/Routes/guilds.ts +++ /dev/null @@ -1,381 +0,0 @@ -import { - APIThreadChannel, - Identify, - RESTDeleteAPIAutoModerationRuleResult, - RESTDeleteAPIGuildBanResult, - RESTDeleteAPIGuildEmojiResult, - RESTDeleteAPIGuildIntegrationResult, - RESTDeleteAPIGuildMemberResult, - RESTDeleteAPIGuildMemberRoleResult, - RESTDeleteAPIGuildResult, - RESTDeleteAPIGuildRoleResult, - RESTDeleteAPIGuildScheduledEventResult, - RESTDeleteAPIGuildStickerResult, - RESTDeleteAPIGuildTemplateResult, - RESTGetAPIAuditLogQuery, - RESTGetAPIAuditLogResult, - RESTGetAPIAutoModerationRuleResult, - RESTGetAPIAutoModerationRulesResult, - RESTGetAPIGuildBanResult, - RESTGetAPIGuildBansQuery, - RESTGetAPIGuildBansResult, - RESTGetAPIGuildChannelsResult, - RESTGetAPIGuildEmojiResult, - RESTGetAPIGuildEmojisResult, - RESTGetAPIGuildIntegrationsResult, - RESTGetAPIGuildInvitesResult, - RESTGetAPIGuildMemberResult, - RESTGetAPIGuildMembersQuery, - RESTGetAPIGuildMembersResult, - RESTGetAPIGuildMembersSearchQuery, - RESTGetAPIGuildMembersSearchResult, - RESTGetAPIGuildPreviewResult, - RESTGetAPIGuildPruneCountQuery, - RESTGetAPIGuildPruneCountResult, - RESTGetAPIGuildQuery, - RESTGetAPIGuildResult, - RESTGetAPIGuildRolesResult, - RESTGetAPIGuildScheduledEventQuery, - RESTGetAPIGuildScheduledEventResult, - RESTGetAPIGuildScheduledEventUsersQuery, - RESTGetAPIGuildScheduledEventUsersResult, - RESTGetAPIGuildScheduledEventsQuery, - RESTGetAPIGuildScheduledEventsResult, - RESTGetAPIGuildStickerResult, - RESTGetAPIGuildStickersResult, - RESTGetAPIGuildTemplatesResult, - RESTGetAPIGuildThreadsResult, - RESTGetAPIGuildVanityUrlResult, - RESTGetAPIGuildVoiceRegionsResult, - RESTGetAPIGuildWebhooksResult, - RESTGetAPIGuildWelcomeScreenResult, - RESTGetAPIGuildWidgetImageQuery, - RESTGetAPIGuildWidgetImageResult, - RESTGetAPIGuildWidgetJSONResult, - RESTGetAPIGuildWidgetSettingsResult, - RESTGetAPITemplateResult, - RESTPatchAPIAutoModerationRuleJSONBody, - RESTPatchAPIAutoModerationRuleResult, - RESTPatchAPICurrentGuildMemberJSONBody, - RESTPatchAPIGuildChannelPositionsJSONBody, - RESTPatchAPIGuildChannelPositionsResult, - RESTPatchAPIGuildEmojiJSONBody, - RESTPatchAPIGuildEmojiResult, - RESTPatchAPIGuildJSONBody, - RESTPatchAPIGuildMemberJSONBody, - RESTPatchAPIGuildMemberResult, - RESTPatchAPIGuildResult, - RESTPatchAPIGuildRoleJSONBody, - RESTPatchAPIGuildRolePositionsJSONBody, - RESTPatchAPIGuildRolePositionsResult, - RESTPatchAPIGuildRoleResult, - RESTPatchAPIGuildScheduledEventJSONBody, - RESTPatchAPIGuildScheduledEventResult, - RESTPatchAPIGuildStickerJSONBody, - RESTPatchAPIGuildStickerResult, - RESTPatchAPIGuildTemplateJSONBody, - RESTPatchAPIGuildTemplateResult, - RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody, - RESTPatchAPIGuildVoiceStateCurrentMemberResult, - RESTPatchAPIGuildVoiceStateUserJSONBody, - RESTPatchAPIGuildVoiceStateUserResult, - RESTPatchAPIGuildWelcomeScreenJSONBody, - RESTPatchAPIGuildWelcomeScreenResult, - RESTPatchAPIGuildWidgetSettingsJSONBody, - RESTPatchAPIGuildWidgetSettingsResult, - RESTPostAPIAutoModerationRuleJSONBody, - RESTPostAPIAutoModerationRuleResult, - RESTPostAPIGuildChannelJSONBody, - RESTPostAPIGuildChannelResult, - RESTPostAPIGuildEmojiJSONBody, - RESTPostAPIGuildEmojiResult, - RESTPostAPIGuildPruneJSONBody, - RESTPostAPIGuildPruneResult, - RESTPostAPIGuildRoleJSONBody, - RESTPostAPIGuildRoleResult, - RESTPostAPIGuildScheduledEventJSONBody, - RESTPostAPIGuildScheduledEventResult, - RESTPostAPIGuildStickerFormDataBody, - RESTPostAPIGuildStickerResult, - RESTPostAPIGuildTemplatesJSONBody, - RESTPostAPIGuildTemplatesResult, - RESTPostAPIGuildsJSONBody, - RESTPostAPIGuildsMFAJSONBody, - RESTPostAPIGuildsMFAResult, - RESTPostAPIGuildsResult, - RESTPostAPITemplateCreateGuildJSONBody, - RESTPostAPITemplateCreateGuildResult, - RESTPutAPIGuildBanJSONBody, - RESTPutAPIGuildBanResult, - RESTPutAPIGuildMemberJSONBody, - RESTPutAPIGuildMemberResult, - RESTPutAPIGuildMemberRoleResult, - RESTPutAPIGuildTemplateSyncResult -} from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface GuildRoutes { - guilds: { - //. - post(args: RestArguments): Promise; - templates(code: string): { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - }; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - webhooks: { - //. - get(args?: RestArguments): Promise; - }; - preview: { - //. - get(args?: RestArguments): Promise; - }; - 'audit-logs': { - //. - get(args?: RestArguments): Promise; - }; - 'auto-moderation': { - rules: { - //. - get(args?: RestArguments): Promise; - //. - post( - args: RestArguments - ): Promise; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - patch( - args: RestArguments - ): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - }; - channels: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - //. - patch( - args: RestArguments - ): Promise; - }; - members: { - //. - get(args?: RestArguments): Promise; - search: { - //. - get(args: RestArguments): Promise; - }; - '@me': { - //. - patch(args: RestArguments): Promise; - }; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - put(args: RestArguments): Promise; - //. - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - roles(id: string): { - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - }; - threads: { - active: { - //. - get( - args?: RestArguments - ): Promise }>>; - }; - }; - roles: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - //. - patch( - args: RestArguments - ): Promise; - (id: string): { - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - bans: { - //. - get(args: RestArguments): Promise; - (userId: string): { - //. - get(args?: RestArguments): Promise; - //. - put(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - mfa: { - //. - post(args: RestArguments): Promise; - }; - prune: { - //. - get(args: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - }; - regions: { - //. - get(args?: RestArguments): Promise; - }; - invites: { - //. - get(args?: RestArguments): Promise; - }; - widget: { - //. - get(args?: RestArguments): Promise; - //. - patch( - args: RestArguments - ): Promise; - }; - 'widget.json': { - //. - get(args?: RestArguments): Promise; - }; - 'widget.png': { - //. - get(args?: RestArguments): Promise; - }; - integrations: { - //. - get(args?: RestArguments): Promise; - (id: string): { - //. - delete(args?: RestArguments): Promise; - }; - }; - 'vanity-url': { - //. - get(args?: RestArguments): Promise; - }; - 'welcome-screen': { - //. - get(args?: RestArguments): Promise; - //. - patch( - args: RestArguments - ): Promise; - }; - // onboarding: { - // get(args:RestArguments); - // } - emojis: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - 'voice-states': { - '@me': { - //. - patch( - args: RestArguments - ): Promise; - }; - (id: string): { - //. - patch( - args: RestArguments - ): Promise; - }; - }; - stickers: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - 'scheduled-events': { - //. - get(args?: RestArguments): Promise; - //. - post( - args: RestArguments - ): Promise; - (id: string): { - //. - get(args?: RestArguments): Promise; - //. - patch( - args: RestArguments - ): Promise; - //. - delete(args?: RestArguments): Promise; - users: { - //. - get( - args?: RestArguments - ): Promise; - }; - }; - }; - templates: { - //. - get(args?: RestArguments): Promise; - //. - post(args: RestArguments): Promise; - (code: string): { - //. - put(args: RestArguments): Promise; - //. - patch(args: RestArguments): Promise; - //. - delete(args?: RestArguments): Promise; - }; - }; - }; - }; -} diff --git a/packages/rest/src/Routes/index.ts b/packages/rest/src/Routes/index.ts deleted file mode 100644 index 260da9b..0000000 --- a/packages/rest/src/Routes/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { ApplicationRoutes } from './applications'; -import { ChannelRoutes } from './channels'; -import { GatewayRoutes } from './gateway'; -import { GuildRoutes } from './guilds'; -import { InteractionRoutes } from './interactions'; -import { InviteRoutes } from './invites'; -import { StageInstanceRoutes } from './stage-instances'; -import { StickerRoutes } from './stickers'; -import { UserRoutes } from './users'; -import { VoiceRoutes } from './voice'; -import { WebhookRoutes } from './webhooks'; - -export type Routes = ApplicationRoutes & - ChannelRoutes & - GatewayRoutes & - GuildRoutes & - InteractionRoutes & - InviteRoutes & - StageInstanceRoutes & - StickerRoutes & - UserRoutes & - VoiceRoutes & - WebhookRoutes; diff --git a/packages/rest/src/Routes/interactions.ts b/packages/rest/src/Routes/interactions.ts deleted file mode 100644 index 58ed063..0000000 --- a/packages/rest/src/Routes/interactions.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { RESTPostAPIInteractionCallbackJSONBody } from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface InteractionRoutes { - interactions: { - (id: string): { - (token: string): { - callback: { - post(args: RestArguments): Promise; - }; - }; - }; - }; -} diff --git a/packages/rest/src/Routes/invites.ts b/packages/rest/src/Routes/invites.ts deleted file mode 100644 index f8edea7..0000000 --- a/packages/rest/src/Routes/invites.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { RESTDeleteAPIInviteResult, RESTGetAPIInviteQuery, RESTGetAPIInviteResult } from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface InviteRoutes { - invites(id: string): { - get(args?: RestArguments): Promise; - delete(args?: RestArguments): Promise; - }; -} diff --git a/packages/rest/src/Routes/stage-instances.ts b/packages/rest/src/Routes/stage-instances.ts deleted file mode 100644 index 77b5281..0000000 --- a/packages/rest/src/Routes/stage-instances.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { - RESTDeleteAPIStageInstanceResult, - RESTGetAPIStageInstanceResult, - RESTPatchAPIStageInstanceJSONBody, - RESTPatchAPIStageInstanceResult, - RESTPostAPIStageInstanceJSONBody, - RESTPostAPIStageInstanceResult -} from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface StageInstanceRoutes { - 'stage-instances': { - post(args: RestArguments): Promise; - (id: string): { - get(args?: RestArguments): Promise; - patch(args: RestArguments): Promise; - delete(args?: RestArguments): Promise; - }; - }; -} diff --git a/packages/rest/src/Routes/stickers.ts b/packages/rest/src/Routes/stickers.ts deleted file mode 100644 index 9c0b980..0000000 --- a/packages/rest/src/Routes/stickers.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RESTGetAPIStickerResult, RESTGetNitroStickerPacksResult } from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface StickerRoutes { - stickers(id: string): { - get(args?: RestArguments): Promise; - }; - 'sticker-packs': { - get(args?: RestArguments): Promise; - }; -} diff --git a/packages/rest/src/Routes/users.ts b/packages/rest/src/Routes/users.ts deleted file mode 100644 index b21780a..0000000 --- a/packages/rest/src/Routes/users.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - APIDMChannel, - RESTDeleteAPIGuildResult, - RESTGetAPICurrentUserApplicationRoleConnectionResult, - RESTGetAPICurrentUserConnectionsResult, - RESTGetAPICurrentUserGuildsQuery, - RESTGetAPICurrentUserGuildsResult, - RESTGetAPICurrentUserResult, - RESTGetAPIUserResult, - RESTGetCurrentUserGuildMemberResult, - RESTPatchAPICurrentUserJSONBody, - RESTPatchAPICurrentUserResult, - RESTPostAPICurrentUserCreateDMChannelJSONBody, - RESTPutAPICurrentUserApplicationRoleConnectionJSONBody, - RESTPutAPICurrentUserApplicationRoleConnectionResult -} from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface UserRoutes { - users: { - (id: string): { - get(args?: RestArguments): Promise; - }; - (id: '@me'): { - get(args?: RestArguments): Promise; - patch(args: RestArguments): Promise; - guilds: { - get(args?: RestArguments): Promise; - (id: string): { - member: { - get(args?: RestArguments): Promise; - }; - delete(args?: RestArguments): Promise; - }; - }; - channels: { - post(args: RestArguments): Promise; - }; - connections: { - get(args?: RestArguments): Promise; - }; - applications(applicationId: string): { - 'role-connection': { - get(args?: RestArguments): Promise; - put( - args: RestArguments - ): Promise; - }; - }; - }; - }; -} diff --git a/packages/rest/src/Routes/voice.ts b/packages/rest/src/Routes/voice.ts deleted file mode 100644 index adb4817..0000000 --- a/packages/rest/src/Routes/voice.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { RESTGetAPIVoiceRegionsResult } from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface VoiceRoutes { - voice: { - region: { - get(args?: RestArguments): Promise; - }; - }; -} diff --git a/packages/rest/src/Routes/webhooks.ts b/packages/rest/src/Routes/webhooks.ts deleted file mode 100644 index d82bc2f..0000000 --- a/packages/rest/src/Routes/webhooks.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { - RESTDeleteAPIWebhookResult, - RESTDeleteAPIWebhookWithTokenMessageResult, - RESTDeleteAPIWebhookWithTokenResult, - RESTGetAPIWebhookResult, - RESTGetAPIWebhookWithTokenMessageResult, - RESTGetAPIWebhookWithTokenResult, - RESTPatchAPIWebhookJSONBody, - RESTPatchAPIWebhookResult, - RESTPatchAPIWebhookWithTokenJSONBody, - RESTPatchAPIWebhookWithTokenMessageJSONBody, - RESTPatchAPIWebhookWithTokenMessageResult, - RESTPatchAPIWebhookWithTokenResult, - RESTPostAPIWebhookWithTokenGitHubQuery, - RESTPostAPIWebhookWithTokenGitHubResult, - RESTPostAPIWebhookWithTokenGitHubWaitResult, - RESTPostAPIWebhookWithTokenJSONBody, - RESTPostAPIWebhookWithTokenQuery, - RESTPostAPIWebhookWithTokenResult, - RESTPostAPIWebhookWithTokenSlackQuery, - RESTPostAPIWebhookWithTokenSlackResult, - RESTPostAPIWebhookWithTokenSlackWaitResult, - RESTPostAPIWebhookWithTokenWaitResult -} from '@biscuitland/common'; -import { RestArguments } from '../REST'; -import { RequestMethod } from '../Router'; - -export interface WebhookRoutes { - webhooks(id: string): { - get(args?: RestArguments): Promise; - patch(args: RestArguments): Promise; - delete(args?: RestArguments): Promise; - (token: string): { - get(args?: RestArguments): Promise; - patch(args: RestArguments): Promise; - delete(args?: RestArguments): Promise; - post( - args: RestArguments - ): Promise; - slack: { - post( - args: RestArguments - ): Promise; - }; - github: { - post( - args: RestArguments - ): Promise; - }; - messages: { - (id: string | '@original'): { - get(args?: RestArguments): Promise; - patch( - args: RestArguments - ): Promise; - delete(args?: RestArguments): Promise; - }; - }; - }; - }; -} diff --git a/packages/rest/src/index.ts b/packages/rest/src/index.ts deleted file mode 100644 index d39c3b6..0000000 --- a/packages/rest/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export { REST, type RawFile } from '@discordjs/rest'; -export * from './CDN'; -export * from './REST'; -export * from './Router'; -export * from './Routes'; diff --git a/packages/rest/tsconfig.json b/packages/rest/tsconfig.json deleted file mode 100644 index 9b4f197..0000000 --- a/packages/rest/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "include": ["src/**/*"] -} diff --git a/packages/rest/tsup.config.ts b/packages/rest/tsup.config.ts deleted file mode 100644 index dfbea63..0000000 --- a/packages/rest/tsup.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'tsup'; - -const isProduction = process.env.NODE_ENV === 'production'; - -export default defineConfig({ - clean: true, - dts: true, - entry: ['src/index.ts'], - format: ['cjs', 'esm'], - minify: isProduction, - sourcemap: false -}); diff --git a/packages/ws/CHANGELOG.md b/packages/ws/CHANGELOG.md deleted file mode 100644 index e35b6ad..0000000 --- a/packages/ws/CHANGELOG.md +++ /dev/null @@ -1,149 +0,0 @@ -# @biscuitland/ws - -## 3.0.12 - -### Patch Changes - -- new changes -- new changes - -## 3.0.9 - -### Patch Changes - -- silly bug on options - -## 3.0.8 - -### Patch Changes - -- Updated dependencies - - @biscuitland/common@0.0.8 - -## 3.0.7 - -### Patch Changes - -- Updated dependencies - - @biscuitland/common@0.0.7 - -## 3.0.6 - -### Patch Changes - -- I meessed up -- Updated dependencies - - @biscuitland/common@0.0.6 - - @biscuitland/rest@3.0.6 - -## 3.0.5 - -### Patch Changes - -- fix: logger on every module -- Updated dependencies - - @biscuitland/common@0.0.5 - - @biscuitland/rest@3.0.5 - -## 3.0.4 - -### Patch Changes - -- first 3.0.\* without bugs -- Updated dependencies - - @biscuitland/common@0.0.4 - - @biscuitland/rest@3.0.4 - -## 2.3.0 - -### Minor Changes - -- fix TODO - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.3.0 - -## 2.2.3 - -### Patch Changes - -- bug fixes -- Updated dependencies - - @biscuitland/api-types@2.2.3 - -## 2.2.2 - -### Patch Changes - -- rename guildLocales to guildLocale in interactions -- Updated dependencies - - @biscuitland/api-types@2.2.2 - -## 2.2.1 - -### Patch Changes - -- select menu options now can be empty since the latest Discord API update -- Updated dependencies - - @biscuitland/api-types@2.2.1 - -## 2.2.0 - -### Minor Changes - -- Functionality to delete ephemeral messages added, select menus were updated - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.2.0 - -## 2.1.2 - -### Patch Changes - -- minor changes -- Updated dependencies - - @biscuitland/api-types@2.1.2 - -## 2.1.1 - -### Patch Changes - -- dumb hotfix that LH asked for (blame Yuzu) -- Updated dependencies - - @biscuitland/api-types@2.1.1 - -## 2.1.0 - -### Minor Changes - -- Changes to cache and forum channels ✨ -- Forum channels and updates to @biscuitland/cache ✨ - -### Patch Changes - -- Updated dependencies -- Updated dependencies - - @biscuitland/api-types@2.1.0 - -## 2.0.6 - -### Patch Changes - -- Minor fixes -- Updated dependencies - - @biscuitland/api-types@2.0.6 - -## 2.0.5 - -### Major Changes - -- publish - -### Patch Changes - -- Updated dependencies - - @biscuitland/api-types@2.0.5 diff --git a/packages/ws/README.md b/packages/ws/README.md deleted file mode 100644 index 959df29..0000000 --- a/packages/ws/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# @biscuitland/ws - -## Advice - -This version of @biscuitland/ws is a **fork** of @discordeno/gateway, all credits go to them. However it has been heavily modified for proper use within biscuit. - -## Most importantly, biscuit's ws is: - -A standalone gateway to interface Discord, it is meant to be used with a rest manager to send fetch requests to Discord - -[](https://github.com/oasisjs/biscuit) -[](https://discord.gg/XNw2RZFzaP) - -biscuit - -## Install (for [node18](https://nodejs.org/en/download/)) - -```sh-session -npm install @biscuitland/ws -yarn add @biscuitland/ws -``` - -## Example - -```ts -import { ShardManager } from "@biscuitland/ws"; -import { BiscuitREST, Router } from "@biscuitland/rest"; -import { GatewayIntentBits } from "@biscuitland/common"; - -const intents = GatewayIntentBits.Guilds; -const token = "your token goes here"; -const rest = new BiscuitREST({ token }); -const api = new Router(rest).createProxy(); - -(async () => { - const connection = await api.gateway.bot.get(); - - // gateway bot code ↓ - const ws = new ShardManager({ - token, - intents, - connection, - async handlePayload(shardId, payload) { - console.log("Received payload on shard #%s", shardId, payload); - }, - }); - - await ws.spawnShards(); -})(); -``` - -## Links -* [Website](https://biscuitjs.com/) -* [Documentation](https://docs.biscuitjs.com/) -* [Discord](https://discord.gg/XNw2RZFzaP) -* [rest](https://www.npmjs.com/package/@biscuitland/rest) | [core](https://www.npmjs.com/package/@biscuitland/core) | [helpers](https://www.npmjs.com/package/@biscuitland/helpers) diff --git a/packages/ws/package.json b/packages/ws/package.json deleted file mode 100644 index 83d9fe2..0000000 --- a/packages/ws/package.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "name": "@biscuitland/ws", - "version": "3.0.12", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", - "files": [ - "dist/**" - ], - "scripts": { - "build": "tsup", - "clean": "rm -rf dist && rm -rf .turbo", - "dev": "tsup --watch", - "test": "vitest run" - }, - "exports": { - "./package.json": "./package.json", - ".": { - "import": { - "types": "./dist/index.d.ts", - "default": "./dist/index.mjs" - }, - "require": "./dist/index.js" - } - }, - "dependencies": { - "@biscuitland/common": "^0.0.10", - "@biscuitland/rest": "^3.0.7", - "ws": "^8.13.0" - }, - "devDependencies": { - "@types/node": "^20.0.0", - "@types/ws": "^8.5.4", - "tsup": "^7.0.0" - }, - "directories": { - "lib": "src" - }, - "license": "Apache-2.0", - "author": "Yuzuru ", - "contributors": [ - { - "name": "Yuzuru", - "url": "https://github.com/yuzudev" - }, - { - "name": "miia", - "url": "https://github.com/dragurimu" - }, - { - "name": "n128", - "url": "https://github.com/nicolito128" - }, - { - "name": "socram03", - "url": "https://github.com/socram03", - "author": true - }, - { - "name": "Drylozu", - "url": "https://github.com/Drylozu" - } - ], - "homepage": "https://biscuitjs.com", - "repository": { - "type": "git", - "url": "git+https://github.com/oasisjs/biscuit.git" - }, - "bugs": { - "url": "https://github.com/oasisjs/biscuit" - }, - "keywords": [ - "api", - "discord", - "bots", - "typescript", - "botdev" - ], - "publishConfig": { - "access": "public" - } -} diff --git a/packages/ws/src/SharedTypes.ts b/packages/ws/src/SharedTypes.ts deleted file mode 100644 index 4742283..0000000 --- a/packages/ws/src/SharedTypes.ts +++ /dev/null @@ -1,204 +0,0 @@ -import type { - APIAuditLogEntry, - APIAutoModerationRule, - APIChannel, - APIGuild, - APIGuildMember, - APIGuildScheduledEvent, - APIStageInstance, - APIUser, - GatewayActivity, - GatewayAutoModerationActionExecutionDispatchData, - GatewayChannelPinsUpdateDispatchData, - GatewayChannelUpdateDispatchData, - GatewayDispatchEvents, - GatewayGuildBanAddDispatchData, - GatewayGuildBanRemoveDispatchData, - GatewayGuildCreateDispatchData, - GatewayGuildDeleteDispatchData, - GatewayGuildEmojisUpdateDispatchData, - GatewayGuildIntegrationsUpdateDispatchData, - GatewayGuildMemberAddDispatchData, - GatewayGuildMemberRemoveDispatchData, - GatewayGuildMemberUpdateDispatchData, - GatewayGuildMembersChunkDispatchData, - GatewayGuildRoleCreateDispatchData, - GatewayGuildRoleDeleteDispatchData, - GatewayGuildRoleUpdateDispatchData, - GatewayGuildScheduledEventUserRemoveDispatchData, - GatewayGuildStickersUpdateDispatchData, - GatewayIntegrationCreateDispatchData, - GatewayIntegrationDeleteDispatchData, - GatewayInteractionCreateDispatchData, - GatewayInviteCreateDispatchData, - GatewayInviteDeleteDispatchData, - GatewayMessageCreateDispatchData, - GatewayMessageDeleteBulkDispatchData, - GatewayMessageDeleteDispatchData, - GatewayMessageReactionAddDispatchData, - GatewayMessageReactionRemoveAllDispatchData, - GatewayMessageReactionRemoveDispatchData, - GatewayMessageReactionRemoveEmojiDispatchData, - GatewayMessageUpdateDispatchData, - GatewayPresenceUpdateData, - GatewayPresenceUpdateDispatchData, - GatewayReadyDispatchData, - GatewayRequestGuildMembersDataWithQuery, - GatewayRequestGuildMembersDataWithUserIds, - GatewayThreadCreateDispatchData, - GatewayThreadDeleteDispatchData, - GatewayThreadListSyncDispatchData, - GatewayThreadMemberUpdateDispatchData, - GatewayThreadMembersUpdateDispatchData, - GatewayTypingStartDispatchData, - GatewayUserUpdateDispatchData, - GatewayVoiceServerUpdateDispatchData, - GatewayVoiceStateUpdateData, - GatewayWebhooksUpdateDispatchData, - PresenceUpdateStatus, - RestToKeys -} from '@biscuitland/common'; - -/** https://discord.com/developers/docs/topics/gateway-events#update-presence */ -export interface StatusUpdate { - /** The user's activities */ - activities?: Omit[]; - /** The user's new status */ - status: PresenceUpdateStatus; -} - -/** https://discord.com/developers/docs/topics/gateway#update-voice-state */ -export interface UpdateVoiceState { - /** id of the guild */ - guild_id: string; - /** id of the voice channel client wants to join (null if disconnecting) */ - channel_id: string | null; - /** Is the client muted */ - self_mute: boolean; - /** Is the client deafened */ - self_deaf: boolean; -} - -export type ShardStatusUpdate = Pick; - -export interface RequestGuildMembersOptions extends GatewayRequestGuildMembersDataWithQuery, GatewayRequestGuildMembersDataWithUserIds {} - -export interface GatewayMemberRequest { - /** The unique nonce for this request. */ - nonce: string; - /** The resolver handler to run when all members arrive. */ - resolve: (value: APIGuildMember[] | PromiseLike) => void; - /** The members that have already arrived for this request. */ - members: APIGuildMember[]; -} - -export type AtLeastOne< - T, - U = { - [K in keyof T]: Pick; - } -> = Partial & U[keyof U]; - -export type ClientUser = { bot: true } & APIUser; - -export interface Events { - [GatewayDispatchEvents.Ready]: GatewayReadyDispatchData & { - user: ClientUser; - }; - [GatewayDispatchEvents.ChannelUpdate]: GatewayChannelUpdateDispatchData; - [GatewayDispatchEvents.AutoModerationActionExecution]: GatewayAutoModerationActionExecutionDispatchData; - [GatewayDispatchEvents.ThreadCreate]: GatewayThreadCreateDispatchData; - [GatewayDispatchEvents.ThreadDelete]: GatewayThreadDeleteDispatchData; - [GatewayDispatchEvents.ThreadUpdate]: GatewayThreadDeleteDispatchData; - [GatewayDispatchEvents.ThreadListSync]: GatewayThreadListSyncDispatchData; - [GatewayDispatchEvents.ThreadMemberUpdate]: GatewayThreadMemberUpdateDispatchData; - [GatewayDispatchEvents.ThreadMembersUpdate]: GatewayThreadMembersUpdateDispatchData; - [GatewayDispatchEvents.ChannelPinsUpdate]: GatewayChannelPinsUpdateDispatchData; - [GatewayDispatchEvents.GuildCreate]: GatewayGuildCreateDispatchData; - [GatewayDispatchEvents.GuildUpdate]: APIGuild; - [GatewayDispatchEvents.GuildDelete]: GatewayGuildDeleteDispatchData; - [GatewayDispatchEvents.GuildAuditLogEntryCreate]: APIAuditLogEntry; - [GatewayDispatchEvents.GuildBanAdd]: GatewayGuildBanAddDispatchData; - [GatewayDispatchEvents.GuildBanRemove]: GatewayGuildBanRemoveDispatchData; - [GatewayDispatchEvents.GuildEmojisUpdate]: GatewayGuildEmojisUpdateDispatchData; - [GatewayDispatchEvents.GuildStickersUpdate]: GatewayGuildStickersUpdateDispatchData; - [GatewayDispatchEvents.GuildIntegrationsUpdate]: GatewayGuildIntegrationsUpdateDispatchData; - [GatewayDispatchEvents.GuildMemberAdd]: GatewayGuildMemberAddDispatchData; - [GatewayDispatchEvents.GuildMemberRemove]: GatewayGuildMemberRemoveDispatchData; - [GatewayDispatchEvents.GuildMemberUpdate]: GatewayGuildMemberUpdateDispatchData; - [GatewayDispatchEvents.GuildMembersChunk]: GatewayGuildMembersChunkDispatchData; - [GatewayDispatchEvents.GuildRoleCreate]: GatewayGuildRoleCreateDispatchData; - [GatewayDispatchEvents.GuildRoleUpdate]: GatewayGuildRoleUpdateDispatchData; - [GatewayDispatchEvents.GuildRoleDelete]: GatewayGuildRoleDeleteDispatchData; - [GatewayDispatchEvents.IntegrationDelete]: GatewayIntegrationDeleteDispatchData; - [GatewayDispatchEvents.InviteCreate]: GatewayInviteCreateDispatchData; - [GatewayDispatchEvents.InviteDelete]: GatewayInviteDeleteDispatchData; - [GatewayDispatchEvents.MessageCreate]: GatewayMessageCreateDispatchData; - [GatewayDispatchEvents.MessageUpdate]: GatewayMessageUpdateDispatchData; - [GatewayDispatchEvents.MessageDelete]: GatewayMessageDeleteDispatchData; - [GatewayDispatchEvents.MessageDeleteBulk]: GatewayMessageDeleteBulkDispatchData; - [GatewayDispatchEvents.MessageReactionAdd]: GatewayMessageReactionAddDispatchData; - [GatewayDispatchEvents.MessageReactionRemove]: GatewayMessageReactionRemoveDispatchData; - [GatewayDispatchEvents.MessageReactionRemoveAll]: GatewayMessageReactionRemoveAllDispatchData; - [GatewayDispatchEvents.MessageReactionRemoveEmoji]: GatewayMessageReactionRemoveEmojiDispatchData; - [GatewayDispatchEvents.PresenceUpdate]: GatewayPresenceUpdateDispatchData; - [GatewayDispatchEvents.TypingStart]: GatewayTypingStartDispatchData; - [GatewayDispatchEvents.UserUpdate]: GatewayUserUpdateDispatchData; - [GatewayDispatchEvents.VoiceStateUpdate]: GatewayVoiceStateUpdateData; - [GatewayDispatchEvents.VoiceServerUpdate]: GatewayVoiceServerUpdateDispatchData; - [GatewayDispatchEvents.WebhooksUpdate]: GatewayWebhooksUpdateDispatchData; - [GatewayDispatchEvents.InteractionCreate]: GatewayInteractionCreateDispatchData; -} - -export type StageSameEvents = RestToKeys< - [ - APIStageInstance, - GatewayDispatchEvents.StageInstanceCreate, - GatewayDispatchEvents.StageInstanceUpdate, - GatewayDispatchEvents.StageInstanceDelete - ] ->; - -export type IntegrationSameEvents = RestToKeys< - [GatewayIntegrationCreateDispatchData, GatewayDispatchEvents.IntegrationCreate, GatewayDispatchEvents.IntegrationUpdate] ->; - -export type GuildScheduledUserSameEvents = RestToKeys< - [ - GatewayGuildScheduledEventUserRemoveDispatchData, - GatewayDispatchEvents.GuildScheduledEventUserRemove, - GatewayDispatchEvents.GuildScheduledEventUserAdd - ] ->; - -export type GuildScheduledSameEvents = RestToKeys< - [ - APIGuildScheduledEvent, - GatewayDispatchEvents.GuildScheduledEventCreate, - GatewayDispatchEvents.GuildScheduledEventDelete, - GatewayDispatchEvents.GuildScheduledEventUpdate - ] ->; - -export type ChannelSameEvents = RestToKeys< - [APIChannel, GatewayDispatchEvents.ChannelCreate, GatewayDispatchEvents.ChannelDelete, GatewayDispatchEvents.ChannelUpdate] ->; - -export type AutoModetaractionRuleEvents = RestToKeys< - [ - APIAutoModerationRule, - GatewayDispatchEvents.AutoModerationRuleCreate, - GatewayDispatchEvents.AutoModerationRuleDelete, - GatewayDispatchEvents.AutoModerationRuleUpdate - ] ->; - -export type NormalizeEvents = Events & - AutoModetaractionRuleEvents & - ChannelSameEvents & - GuildScheduledSameEvents & - GuildScheduledUserSameEvents & - IntegrationSameEvents & - StageSameEvents & { RAW: GatewayDispatchEvents }; - -export type GatewayEvents = { [x in keyof NormalizeEvents]: NormalizeEvents[x] }; diff --git a/packages/ws/src/constants/index.ts b/packages/ws/src/constants/index.ts deleted file mode 100644 index 761dc25..0000000 --- a/packages/ws/src/constants/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { GatewayDispatchPayload } from '@biscuitland/common'; -import { ShardManagerOptions } from '../discord'; - -const COMPRESS = false; - -const properties = { - os: process.platform, - browser: 'Biscuit', - device: 'Biscuit' -}; - -const ShardManagerDefaults: Partial = { - totalShards: 1, - spawnShardDelay: 5300, - debug: false, - intents: 0, - properties: properties, - version: 10, - handlePayload: (shardId: number, packet: GatewayDispatchPayload): void => { - console.info(`Packet ${packet.t} on shard ${shardId}`); - } -}; - -export interface IdentifyProperties { - /** - * Operating system the shard runs on. - * @default "darwin" | "linux" | "windows" - */ - os: string; - /** - * The "browser" where this shard is running on. - */ - browser: string; - /** - * The device on which the shard is running. - */ - device: string; -} - -export { COMPRESS, ShardManagerDefaults, properties }; diff --git a/packages/ws/src/discord/shard.ts b/packages/ws/src/discord/shard.ts deleted file mode 100644 index bc33af3..0000000 --- a/packages/ws/src/discord/shard.ts +++ /dev/null @@ -1,302 +0,0 @@ -import { inflateSync } from 'node:zlib'; -import type { GatewayReceivePayload, GatewaySendPayload, Logger } from '@biscuitland/common'; -import { GatewayCloseCodes, GatewayDispatchEvents, GatewayOpcodes } from '@biscuitland/common'; -import type WS from 'ws'; -import { type CloseEvent, WebSocket } from 'ws'; -import { properties } from '../constants'; -import { ConnectTimeout, DynamicBucket, PriorityQueue } from '../structures'; -import type { ShardData, ShardOptions } from './shared'; -import { ShardSocketCloseCodes } from './shared'; - -export class Shard { - logger: Logger; - data: Partial | ShardData = { - resumeSeq: null - }; - - websocket: WebSocket | null = null; - connectTimeout = new ConnectTimeout(); - heart: { - interval: number; - nodeInterval?: NodeJS.Timeout; - lastAck?: number; - lastBeat?: number; - ack: boolean; - } = { - interval: 30e3, - ack: true - }; - - bucket: DynamicBucket; - offlineSendQueue = new PriorityQueue<(_?: unknown) => void>(); - - constructor(public id: number, protected options: ShardOptions) { - this.options.ratelimitOptions ??= { - rateLimitResetInterval: 60_000, - maxRequestsPerRateLimitTick: 120 - }; - this.logger = options.logger; - - const safe = this.calculateSafeRequests(); - this.bucket = new DynamicBucket({ - limit: safe, - refillAmount: safe, - refillInterval: 6e4, - logger: this.logger - }); - } - - get latency() { - return this.heart.lastAck && this.heart.lastBeat ? this.heart.lastAck - this.heart.lastBeat : Infinity; - } - - get isOpen() { - return this.websocket?.readyState === WebSocket.OPEN; - } - - get gatewayURL() { - return this.options.info.url; - } - - get resumeGatewayURL() { - return this.data.resume_gateway_url; - } - - get currentGatewayURL() { - return this.resumeGatewayURL ?? this.options.info.url; - } - - async connect() { - await this.connectTimeout.wait(); - - this.logger.debug(`[Shard #${this.id}] Connecting to ${this.currentGatewayURL}`); - - this.websocket = new WebSocket(this.currentGatewayURL); - - this.websocket!.onmessage = (event) => this.handleMessage(event); - - this.websocket!.onclose = (event) => this.handleClosed(event); - - this.websocket!.onerror = (event) => this.logger.error(event); - - this.websocket!.onopen = () => { - this.heart.ack = true; - }; - } - - async send(priority: number, message: T) { - this.logger.info(`[Shard #${this.id}] Sending: ${GatewayOpcodes[message.op]} ${JSON.stringify(message.d, null, 1)}`); - await this.checkOffline(priority); - await this.bucket.acquire(priority); - await this.checkOffline(priority); - this.websocket?.send(JSON.stringify(message)); - } - - async identify() { - await this.send(0, { - op: GatewayOpcodes.Identify, - d: { - token: `Bot ${this.options.token}`, - compress: this.options.compress, - properties, - shard: [this.id, this.options.info.shards], - intents: this.options.intents, - presence: this.options.presence - } - }); - } - - get resumable() { - return !!(this.data.resume_gateway_url && this.data.session_id && this.data.resumeSeq !== null); - } - - async resume() { - await this.send(0, { - op: GatewayOpcodes.Resume, - d: { - seq: this.data.resumeSeq!, - session_id: this.data.session_id!, - token: `Bot ${this.options.token}` - } - }); - } - - async heartbeat(requested: boolean) { - this.logger.debug(`[Shard #${this.id}] Sending ${requested ? '' : 'un'}requested heartbeat (Ack=${this.heart.ack})`); - if (!requested) { - if (!this.heart.ack) { - await this.close(ShardSocketCloseCodes.ZombiedConnection, 'Zombied connection'); - return; - } - this.heart.ack = false; - } - - this.heart.lastBeat = Date.now(); - - this.websocket!.send( - JSON.stringify({ - op: GatewayOpcodes.Heartbeat, - d: this.data.resumeSeq ?? null - }) - ); - } - - async disconnect() { - this.logger.info(`[Shard #${this.id}] Disconnecting`); - await this.close(ShardSocketCloseCodes.Shutdown, 'Shard down request'); - } - - async reconnect() { - this.logger.info(`[Shard #${this.id}] Reconnecting`); - await this.disconnect(); - await this.connect(); - } - - async onpacket(packet: GatewayReceivePayload) { - if (packet.s !== null) { - this.data.resumeSeq = packet.s; - } - - this.logger.debug(`[Shard #${this.id}]`, packet.t ? packet.t : GatewayOpcodes[packet.op], this.data.resumeSeq); - - switch (packet.op) { - case GatewayOpcodes.Hello: - clearInterval(this.heart.nodeInterval); - - this.heart.interval = packet.d.heartbeat_interval; - - // await delay(Math.ceil(this.heart.interval * (Math.random() || 0.5))); - await this.heartbeat(false); - this.heart.nodeInterval = setInterval(() => this.heartbeat(false), this.heart.interval); - - if (this.resumable) { - return this.resume(); - } - await this.identify(); - break; - case GatewayOpcodes.HeartbeatAck: - this.heart.ack = true; - this.heart.lastAck = Date.now(); - break; - case GatewayOpcodes.Heartbeat: - this.heartbeat(true); - break; - case GatewayOpcodes.Reconnect: - await this.reconnect(); - break; - case GatewayOpcodes.InvalidSession: - if (packet.d) { - if (!this.resumable) { - return this.logger.fatal(`[Shard #${this.id}] This is a completely unexpected error message.`); - } - await this.resume(); - } else { - this.data.resumeSeq = 0; - this.data.session_id = undefined; - await this.identify(); - } - break; - case GatewayOpcodes.Dispatch: - switch (packet.t) { - case GatewayDispatchEvents.Resumed: - this.offlineSendQueue.toArray().map((resolve: () => any) => resolve()); - break; - case GatewayDispatchEvents.Ready: - this.data.resume_gateway_url = packet.d.resume_gateway_url; - this.data.session_id = packet.d.session_id; - this.offlineSendQueue.toArray().map((resolve: () => any) => resolve()); - this.options.handlePayload(this.id, packet); - break; - default: - this.options.handlePayload(this.id, packet); - break; - } - break; - } - } - - protected async handleClosed(close: CloseEvent) { - clearInterval(this.heart.nodeInterval); - this.logger.warn(`[Shard #${this.id}] ${GatewayCloseCodes[close.code] ?? close.code}`); - - switch (close.code) { - case ShardSocketCloseCodes.Shutdown: - break; - case 1000: - case 1001: - case 1006: - case ShardSocketCloseCodes.ZombiedConnection: - case GatewayCloseCodes.UnknownError: - case GatewayCloseCodes.UnknownOpcode: - case GatewayCloseCodes.DecodeError: - case GatewayCloseCodes.NotAuthenticated: - case GatewayCloseCodes.AlreadyAuthenticated: - case GatewayCloseCodes.InvalidSeq: - case GatewayCloseCodes.RateLimited: - case GatewayCloseCodes.SessionTimedOut: - this.logger.info(`[Shard #${this.id}] Trying to reconnect`); - await this.reconnect(); - break; - - case GatewayCloseCodes.AuthenticationFailed: - case GatewayCloseCodes.DisallowedIntents: - case GatewayCloseCodes.InvalidAPIVersion: - case GatewayCloseCodes.InvalidIntents: - case GatewayCloseCodes.InvalidShard: - case GatewayCloseCodes.ShardingRequired: - this.logger.fatal(`[Shard #${this.id}] cannot reconnect`); - break; - - default: - this.logger.warn(`[Shard #${this.id}] Unknown close code, trying to reconnect anyways`); - await this.reconnect(); - break; - } - } - - async close(code: number, reason: string) { - if (this.websocket?.readyState !== WebSocket.OPEN) { - return this.logger.warn(`${new Error('418').stack} [Shard #${this.id}] Is not open`); - } - this.logger.warn(`${new Error('418').stack} [Shard #${this.id}] Called close`); - this.websocket?.close(code, reason); - } - - protected async handleMessage({ data }: WS.MessageEvent) { - if (data instanceof Buffer) { - data = inflateSync(data); - } - /** - * Idk why, but Bun sends this event when websocket connects. - * MessageEvent { - * type: "message", - * data: "Already authenticated." - * } - */ - if ((data as string).startsWith('{')) { - data = JSON.parse(data as string); - } - - const packet = data as unknown as GatewayReceivePayload; - - return this.onpacket(packet); - } - - checkOffline(priority: number) { - if (!this.isOpen) { - return new Promise((resolve) => this.offlineSendQueue.push(resolve, priority)); - } - return Promise.resolve(); - } - - calculateSafeRequests(): number { - const safeRequests = - this.options.ratelimitOptions!.maxRequestsPerRateLimitTick - - Math.ceil(this.options.ratelimitOptions!.rateLimitResetInterval / this.heart.interval) * 2; - - if (safeRequests < 0) { - return 0; - } - return safeRequests; - } -} diff --git a/packages/ws/src/discord/sharder.ts b/packages/ws/src/discord/sharder.ts deleted file mode 100644 index 029655f..0000000 --- a/packages/ws/src/discord/sharder.ts +++ /dev/null @@ -1,161 +0,0 @@ -import type { - APIGatewayBotInfo, - GatewayUpdatePresence, - GatewayVoiceStateUpdate, - // Logger, - ObjectToLower -} from '@biscuitland/common'; -import { Collection, GatewayOpcodes, LogLevels, Logger, Options, toSnakeCase } from '@biscuitland/common'; -import { ShardManagerDefaults } from '../constants'; -import { SequentialBucket } from '../structures'; -import { Shard } from './shard.js'; -import type { ShardManagerOptions } from './shared'; - -export class ShardManager extends Collection { - connectQueue: SequentialBucket; - options: ShardManagerOptions; - logger: Logger; - - constructor(options: ShardManagerOptions) { - super(); - this.options = Options>(ShardManagerDefaults, options, { info: { shards: options.totalShards } }); - this.connectQueue = new SequentialBucket(this.concurrency); - - this.logger = new Logger({ - active: this.options.debug, - name: '[ShardManager]', - logLevel: LogLevels.Debug - }); - } - - get remaining(): number { - return this.options.info.session_start_limit.remaining; - } - - get concurrency(): number { - return this.options.info.session_start_limit.max_concurrency; - } - - calculeShardId(guildId: string) { - return Number((BigInt(guildId) >> 22n) % BigInt(this.options.totalShards ?? 1)); - } - - spawn(shardId: number) { - this.logger.info(`Spawn shard ${shardId}`); - let shard = this.get(shardId); - - shard ??= new Shard(shardId, { - token: this.options.token, - intents: this.options.intents, - info: Options(this.options.info, { shards: this.options.totalShards }), - handlePayload: this.options.handlePayload, - properties: this.options.properties, - logger: this.logger, - compress: false, - presence: this.options.presence - }); - - this.set(shardId, shard); - - return shard; - } - - async spawnShards(): Promise { - const buckets = this.spawnBuckets(); - - this.logger.info('Spawn shards'); - for (const bucket of buckets) { - for (const shard of bucket) { - if (!shard) { - break; - } - this.logger.info(`${shard.id} add to connect queue`); - await this.connectQueue.push(shard.connect.bind(shard)); - } - } - } - - /* - * spawns buckets in order - * https://discord.com/developers/docs/topics/gateway#sharding-max-concurrency - */ - spawnBuckets(): Shard[][] { - this.logger.info('#0 Preparing buckets'); - const chunks = SequentialBucket.chunk(new Array(this.options.totalShards), this.concurrency); - // biome-ignore lint/complexity/noForEach: in maps its okay - chunks.forEach((arr: any[], index: number) => { - for (let i = 0; i < arr.length; i++) { - const id = i + (index > 0 ? index * this.concurrency : 0); - chunks[index][i] = this.spawn(id); - } - }); - this.logger.info(`${chunks.length} buckets created`); - return chunks; - } - - forceIdentify(shardId: number) { - this.logger.info(`Shard #${shardId} force identify`); - return this.spawn(shardId).identify(); - } - - disconnect(shardId: number) { - this.logger.info(`Force disconnect shard ${shardId}`); - return this.get(shardId)?.disconnect(); - } - - disconnectAll() { - this.logger.info('Disconnect all shards'); - return new Promise((_resolve) => { - // biome-ignore lint/complexity/noForEach: in maps its okay - this.forEach((shard) => shard.disconnect()); - _resolve(null); - }); - } - - setShardPresence(shardId: number, payload: GatewayUpdatePresence['d']) { - this.logger.info(`Shard #${shardId} update presence`); - return this.get(shardId)?.send(1, { - op: GatewayOpcodes.PresenceUpdate, - d: payload - }); - } - - setPresence(payload: GatewayUpdatePresence['d']): Promise | undefined { - return new Promise((_resolve) => { - // biome-ignore lint/complexity/noForEach: in maps its okay - this.forEach((_shard) => { - this.setShardPresence(_shard.id, payload); - }, this); - _resolve(); - }); - } - - joinVoice(guild_id: string, channel_id: string, options: ObjectToLower>) { - const shardId = this.calculeShardId(guild_id); - this.logger.info(`Shard #${shardId} join voice ${channel_id} in ${guild_id}`); - - return this.get(shardId)?.send(1, { - op: GatewayOpcodes.VoiceStateUpdate, - d: { - guild_id, - channel_id, - ...toSnakeCase(options) - } - }); - } - - leaveVoice(guild_id: string) { - const shardId = this.calculeShardId(guild_id); - this.logger.info(`Shard #${shardId} leave voice in ${guild_id}`); - - return this.get(shardId)?.send(1, { - op: GatewayOpcodes.VoiceStateUpdate, - d: { - guild_id, - channel_id: null, - self_mute: false, - self_deaf: false - } - }); - } -} diff --git a/packages/ws/src/discord/shared.ts b/packages/ws/src/discord/shared.ts deleted file mode 100644 index bd846ee..0000000 --- a/packages/ws/src/discord/shared.ts +++ /dev/null @@ -1,83 +0,0 @@ -import type { APIGatewayBotInfo, GatewayDispatchPayload, GatewayIntentBits, GatewayPresenceUpdateData, Logger } from '@biscuitland/common'; -import type { IdentifyProperties } from '../constants'; - -export interface ShardManagerOptions extends ShardDetails { - /** Important data which is used by the manager to connect shards to the gateway. */ - info: APIGatewayBotInfo; - /** - * Delay in milliseconds to wait before spawning next shard. OPTIMAL IS ABOVE 5100. YOU DON'T WANT TO HIT THE RATE LIMIT!!! - * @default 5300 - */ - spawnShardDelay?: number; - /** - * Total amount of shards your bot uses. Useful for zero-downtime updates or resharding. - * @default 1 - */ - totalShards?: number; - /** - * The payload handlers for messages on the shard. - */ - handlePayload(shardId: number, packet: GatewayDispatchPayload): unknown; - /** - * wheter to send debug information to the console - */ - debug?: boolean; - presence?: GatewayPresenceUpdateData; -} - -export interface ShardData { - /** resume seq to resume connections */ - resumeSeq: number | null; - - /** - * resume_gateway_url is the url to resume the connection - * @link https://discord.com/developers/docs/topics/gateway#ready-event - */ - resume_gateway_url?: string; - - /** - * session_id is the unique session id of the gateway - * do not mistake with the biscuit client which is named Session - */ - session_id?: string; -} - -export interface ShardDetails { - /** Bot token which is used to connect to Discord */ - token: string; - /** - * The URL of the gateway which should be connected to. - * @default "wss://gateway.discord.gg" - */ - url?: string; - /** - * The gateway version which should be used. - * @default 10 - */ - version?: number; - /** - * The calculated intent value of the events which the shard should receive. - */ - intents: GatewayIntentBits | number; - /** - * Identify properties to use - */ - properties?: IdentifyProperties; -} - -export interface ShardOptions extends ShardDetails { - info: APIGatewayBotInfo; - handlePayload(shardId: number, packet: GatewayDispatchPayload): unknown; - ratelimitOptions?: { - maxRequestsPerRateLimitTick: number; - rateLimitResetInterval: number; - }; - logger: Logger; - compress: boolean; - presence?: GatewayPresenceUpdateData; -} - -export enum ShardSocketCloseCodes { - Shutdown = 3000, - ZombiedConnection = 3010 -} diff --git a/packages/ws/src/structures/index.ts b/packages/ws/src/structures/index.ts deleted file mode 100644 index bd0413b..0000000 --- a/packages/ws/src/structures/index.ts +++ /dev/null @@ -1,343 +0,0 @@ -import type { Logger } from '@biscuitland/common'; -import { delay } from '@biscuitland/common'; - -export * from './timeout'; - -/** - * just any kind of request to queue and resolve later - */ -export type QueuedRequest = (value: void | Promise) => Promise | any; - -/** - * options of the dynamic bucket - */ -export interface DynamicBucketOptions { - limit: number; - refillInterval: number; - refillAmount: number; - logger: Logger; -} - -/** - * generally useless for interaction based bots - * ideally this would only be triggered on certain paths - * example: a huge amount of messages being spammed - * - * a dynamic bucket is just a priority queue implemented using linked lists - * we create an empty bucket for every path - * dynamically allocating memory improves the final memory footprint - */ -export class DynamicBucket { - limit: number; - refillInterval: number; - refillAmount: number; - - /** The queue of requests to acquire an available request. Mapped by */ - queue = new PriorityQueue(); - - /** The amount of requests that have been used up already. */ - used = 0; - - /** Whether or not the queue is already processing. */ - processing = false; - - /** The timeout id for the timer to reduce the used amount by the refill amount. */ - timeoutId?: NodeJS.Timeout; - - /** The timestamp in milliseconds when the next refill is scheduled. */ - refillsAt?: number; - - logger: Logger; - - constructor(options: DynamicBucketOptions) { - this.limit = options.limit; - this.refillInterval = options.refillInterval; - this.refillAmount = options.refillAmount; - this.logger = options.logger; - } - - get remaining(): number { - if (this.limit < this.used) { - return 0; - } - return this.limit - this.used; - } - - refill(): void { - // Lower the used amount by the refill amount - this.used = this.refillAmount > this.used ? 0 : this.used - this.refillAmount; - - // Reset the refillsAt timestamp since it just got refilled - this.refillsAt = undefined; - - if (this.used > 0) { - if (this.timeoutId) { - clearTimeout(this.timeoutId); - } - this.timeoutId = setTimeout(() => { - this.refill(); - }, this.refillInterval); - this.refillsAt = Date.now() + this.refillInterval; - } - } - - /** Begin processing the queue. */ - async processQueue(): Promise { - // There is already a queue that is processing - if (this.processing) { - return; - } - - // Begin going through the queue. - while (!this.queue.isEmpty()) { - if (this.remaining) { - this.logger.debug(`Processing queue. Remaining: ${this.remaining} Length: ${this.queue.size()}`); - // Resolves the promise allowing the paused execution of this request to resolve and continue. - this.queue.peek()(); - this.queue.pop(); - - // A request can be made - this.used++; - - // Create a new timeout for this request if none exists. - if (!this.timeoutId) { - this.timeoutId = setTimeout(() => { - this.refill(); - }, this.refillInterval); - - // Set the time for when this refill will occur. - this.refillsAt = Date.now() + this.refillInterval; - } - // Check if a refill is scheduled, since we have used up all available requests - } else if (this.refillsAt) { - const now = Date.now(); - // If there is time left until next refill, just delay execution. - if (this.refillsAt > now) { - await delay(this.refillsAt - now); - } - } - } - - // Loop has ended mark false so it can restart later when needed - this.processing = false; - } - - /** Pauses the execution until the request is available to be made. */ - async acquire(priority: number): Promise { - return await new Promise((_resolve) => { - this.queue.push(_resolve, priority); - // biome-ignore lint/complexity/noVoid: - void this.processQueue(); - }); - } - - toString() { - return [...this.queue].toString(); - } -} - -/** - * abstract node lol - */ -export interface AbstractNode { - data: T; - next: this | null; -} - -export interface QueuePusher { - push(data: T): NonNullable>; -} - -export interface QueuePusherWithPriority { - push(data: T, priority: number): NonNullable>; -} - -export class TNode implements AbstractNode { - data: T; - next: this | null; - - constructor(data: T) { - this.data = data; - this.next = null; - } - - static null(list: AbstractNode | null): list is null { - return !list; - } -} - -export class PNode extends TNode { - priority: number; - - constructor(data: T, priority: number) { - super(data); - this.priority = priority; - } -} - -export abstract class Queue { - protected abstract head: AbstractNode | null; - - /** - * O(1) - */ - public pop() { - if (TNode.null(this.head)) { - throw new Error('cannot pop a list without elements'); - } - - return (this.head = this.head.next); - } - - /** - * O(1) - */ - public peek(): T { - if (TNode.null(this.head)) { - throw new Error('cannot peek an empty list'); - } - - return this.head.data; - } - - /** - * O(n) - */ - public size(): number { - let aux = this.head; - - if (TNode.null(aux)) { - return 0; - } - - let count = 1; - - while (aux.next !== null) { - count++; - aux = aux.next; - } - - return count; - } - - /** - * O(1) - */ - public isEmpty() { - return TNode.null(this.head); - } - - *[Symbol.iterator](): IterableIterator { - let temp = this.head; - while (temp !== null) { - yield temp.data; - temp = temp.next; - } - } - - public toArray(): T[] { - return Array.from(this); - } - - public toString() { - return this.head?.toString() || ''; - } -} - -export class LinkedList extends Queue implements QueuePusher { - protected head: TNode | null = null; - - /** - * O(1) - */ - public push(data: T): NonNullable> { - const temp = new TNode(data); - temp.next = this.head; - this.head = temp; - - return this.head; - } -} - -export class PriorityQueue extends Queue implements QueuePusherWithPriority { - protected head: PNode | null = null; - - /** - * O(#priorities) - */ - public push(data: T, priority: number): NonNullable> { - let start = this.head; - const temp = new PNode(data, priority); - - if (TNode.null(this.head) || TNode.null(start)) { - this.head = temp; - return this.head; - } - - if (this.head.priority > priority) { - temp.next = this.head; - this.head = temp; - return this.head; - } - - while (start.next !== null && start.next.priority < priority) { - start = start.next; - } - - temp.next = start.next as PNode; - start.next = temp; - - return this.head; - } -} - -export class SequentialBucket { - private connections: LinkedList; - private capacity: number; // max_concurrency - private spawnTimeout: number; - - constructor(maxCapacity: number) { - this.connections = new LinkedList(); - this.capacity = maxCapacity; - this.spawnTimeout = 5000; - } - - public async destroy() { - this.connections = new LinkedList(); - } - - public async push(promise: QueuedRequest) { - this.connections.push(promise); - - if (this.capacity <= this.connections.size()) { - await this.acquire(); - await delay(this.spawnTimeout); - } - return; - } - - public async acquire(promises = this.connections) { - while (!promises.isEmpty()) { - const item = promises.peek(); - item().catch((...args: any[]) => { - Promise.reject(...args); - }); - promises.pop(); - } - - return Promise.resolve(true); - } - - public static chunk(array: T[], chunks: number): T[][] { - let index = 0; - let resIndex = 0; - const result = Array(Math.ceil(array.length / chunks)); - - while (index < array.length) { - result[resIndex] = array.slice(index, (index += chunks)); - resIndex++; - } - - return result; - } -} diff --git a/packages/ws/src/structures/timeout.ts b/packages/ws/src/structures/timeout.ts deleted file mode 100644 index 384060b..0000000 --- a/packages/ws/src/structures/timeout.ts +++ /dev/null @@ -1,28 +0,0 @@ -export class ConnectTimeout { - promises: { promise: Promise; resolve: (x: boolean) => any }[] = []; - interval?: NodeJS.Timeout = undefined; - // biome-ignore lint/nursery/noEmptyBlockStatements: - constructor(readonly intervalTime = 5000) {} - - wait() { - let resolve = (_x: boolean) => { - // - }; - const promise = new Promise((r) => (resolve = r)); - if (!this.promises.length) { - this.interval = setInterval(() => { - this.shift(); - }, this.intervalTime); - } - this.promises.push({ resolve, promise }); - return promise; - } - - shift() { - this.promises.shift()?.resolve(true); - if (!this.promises.length) { - clearInterval(this.interval); - this.interval = undefined; - } - } -} diff --git a/packages/ws/tsconfig.json b/packages/ws/tsconfig.json deleted file mode 100644 index 03bf775..0000000 --- a/packages/ws/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "./dist" - }, - "include": [ - "src/**/*" - ] -} \ No newline at end of file diff --git a/packages/ws/tsup.config.ts b/packages/ws/tsup.config.ts deleted file mode 100644 index dfbea63..0000000 --- a/packages/ws/tsup.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from 'tsup'; - -const isProduction = process.env.NODE_ENV === 'production'; - -export default defineConfig({ - clean: true, - dts: true, - entry: ['src/index.ts'], - format: ['cjs', 'esm'], - minify: isProduction, - sourcemap: false -}); diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 39a2b6e..0000000 --- a/renovate.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base" - ] -} diff --git a/src/api/CDN.ts b/src/api/CDN.ts new file mode 100644 index 0000000..af5b2ea --- /dev/null +++ b/src/api/CDN.ts @@ -0,0 +1,328 @@ +/* eslint-disable jsdoc/check-param-names */ +import { CDN_URL } from '../common/index.js'; +import { + ALLOWED_EXTENSIONS, + ALLOWED_SIZES, + ALLOWED_STICKER_EXTENSIONS, + type ImageExtension, + type ImageSize, + type StickerExtension, +} from './utils/constants.js'; + +/** + * The options used for image URLs + */ +export interface BaseImageURLOptions { + /** + * The extension to use for the image URL + * + * @defaultValue `'webp'` + */ + extension?: ImageExtension; + /** + * The size specified in the image URL + */ + size?: ImageSize; +} + +/** + * The options used for image URLs with animated content + */ +export interface ImageURLOptions extends BaseImageURLOptions { + /** + * Whether or not to prefer the static version of an image asset. + */ + forceStatic?: boolean; +} + +/** + * The options to use when making a CDN URL + */ +export interface MakeURLOptions { + /** + * The allowed extensions that can be used + */ + allowedExtensions?: readonly string[]; + /** + * The extension to use for the image URL + * + * @defaultValue `'webp'` + */ + extension?: string | undefined; + /** + * The size specified in the image URL + */ + size?: ImageSize; +} + +/** + * The CDN link builder + */ +export class CDN { + public constructor(private readonly base: string = CDN_URL) {} + + /** + * Generates an app asset URL for a client's asset. + * + * @param clientId - The client id that has the asset + * @param assetHash - The hash provided by Discord for this asset + * @param options - Optional options for the asset + */ + public appAsset(clientId: string, assetHash: string, options?: Readonly): string { + return this.makeURL(`/app-assets/${clientId}/${assetHash}`, options); + } + + /** + * Generates an app icon URL for a client's icon. + * + * @param clientId - The client id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + public appIcon(clientId: string, iconHash: string, options?: Readonly): string { + return this.makeURL(`/app-icons/${clientId}/${iconHash}`, options); + } + + /** + * Generates an avatar URL, e.g. for a user or a webhook. + * + * @param id - The id that has the icon + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + public avatar(id: string, avatarHash: string, options?: Readonly): string { + return this.dynamicMakeURL(`/avatars/${id}/${avatarHash}`, avatarHash, options); + } + + /** + * Generates a user avatar decoration URL. + * + * @param userId - The id of the user + * @param userAvatarDecoration - The hash provided by Discord for this avatar decoration + * @param options - Optional options for the avatar decoration + */ + public avatarDecoration( + userId: string, + userAvatarDecoration: string, + options?: Readonly, + ): string { + return this.makeURL(`/avatar-decorations/${userId}/${userAvatarDecoration}`, options); + } + + /** + * Generates a banner URL, e.g. for a user or a guild. + * + * @param id - The id that has the banner splash + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + public banner(id: string, bannerHash: string, options?: Readonly): string { + return this.dynamicMakeURL(`/banners/${id}/${bannerHash}`, bannerHash, options); + } + + /** + * Generates an icon URL for a channel, e.g. a group DM. + * + * @param channelId - The channel id that has the icon + * @param iconHash - The hash provided by Discord for this channel + * @param options - Optional options for the icon + */ + public channelIcon(channelId: string, iconHash: string, options?: Readonly): string { + return this.makeURL(`/channel-icons/${channelId}/${iconHash}`, options); + } + + /** + * Generates a default avatar URL + * + * @param index - The default avatar index + * @remarks + * To calculate the index for a user do `(userId >> 22) % 6`, + * or `discriminator % 5` if they're using the legacy username system. + */ + public defaultAvatar(index: number): string { + return this.makeURL(`/embed/avatars/${index}`, { extension: 'png' }); + } + + /** + * Generates a discovery splash URL for a guild's discovery splash. + * + * @param guildId - The guild id that has the discovery splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + public discoverySplash(guildId: string, splashHash: string, options?: Readonly): string { + return this.makeURL(`/discovery-splashes/${guildId}/${splashHash}`, options); + } + + /** + * Generates an emoji's URL for an emoji. + * + * @param emojiId - The emoji id + * @param options - Optional options for the emoji + */ + public emoji(emojiId: string, options?: Readonly): string { + const resolvedOptions = options; + + return this.makeURL(`/emojis/${emojiId}`, resolvedOptions); + } + + /** + * Generates a guild member avatar URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param avatarHash - The hash provided by Discord for this avatar + * @param options - Optional options for the avatar + */ + public guildMemberAvatar( + guildId: string, + userId: string, + avatarHash: string, + options?: Readonly, + ): string { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/avatars/${avatarHash}`, avatarHash, options); + } + + /** + * Generates a guild member banner URL. + * + * @param guildId - The id of the guild + * @param userId - The id of the user + * @param bannerHash - The hash provided by Discord for this banner + * @param options - Optional options for the banner + */ + public guildMemberBanner( + guildId: string, + userId: string, + bannerHash: string, + options?: Readonly, + ): string { + return this.dynamicMakeURL(`/guilds/${guildId}/users/${userId}/banner`, bannerHash, options); + } + + /** + * Generates an icon URL, e.g. for a guild. + * + * @param id - The id that has the icon splash + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + public icon(id: string, iconHash: string, options?: Readonly): string { + return this.dynamicMakeURL(`/icons/${id}/${iconHash}`, iconHash, options); + } + + /** + * Generates a URL for the icon of a role + * + * @param roleId - The id of the role that has the icon + * @param roleIconHash - The hash provided by Discord for this role icon + * @param options - Optional options for the role icon + */ + public roleIcon(roleId: string, roleIconHash: string, options?: Readonly): string { + return this.makeURL(`/role-icons/${roleId}/${roleIconHash}`, options); + } + + /** + * Generates a guild invite splash URL for a guild's invite splash. + * + * @param guildId - The guild id that has the invite splash + * @param splashHash - The hash provided by Discord for this splash + * @param options - Optional options for the splash + */ + public splash(guildId: string, splashHash: string, options?: Readonly): string { + return this.makeURL(`/splashes/${guildId}/${splashHash}`, options); + } + + /** + * Generates a sticker URL. + * + * @param stickerId - The sticker id + * @param extension - The extension of the sticker + * @privateRemarks + * Stickers cannot have a `.webp` extension, so we default to a `.png` + */ + public sticker(stickerId: string, extension: StickerExtension = 'png'): string { + return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension }); + } + + /** + * Generates a sticker pack banner URL. + * + * @param bannerId - The banner id + * @param options - Optional options for the banner + */ + public stickerPackBanner(bannerId: string, options?: Readonly): string { + return this.makeURL(`/app-assets/710982414301790216/store/${bannerId}`, options); + } + + /** + * Generates a team icon URL for a team's icon. + * + * @param teamId - The team id that has the icon + * @param iconHash - The hash provided by Discord for this icon + * @param options - Optional options for the icon + */ + public teamIcon(teamId: string, iconHash: string, options?: Readonly): string { + return this.makeURL(`/team-icons/${teamId}/${iconHash}`, options); + } + + /** + * Generates a cover image for a guild scheduled event. + * + * @param scheduledEventId - The scheduled event id + * @param coverHash - The hash provided by discord for this cover image + * @param options - Optional options for the cover image + */ + public guildScheduledEventCover( + scheduledEventId: string, + coverHash: string, + options?: Readonly, + ): string { + return this.makeURL(`/guild-events/${scheduledEventId}/${coverHash}`, options); + } + + /** + * Constructs the URL for the resource, checking whether or not `hash` starts with `a_` if `dynamic` is set to `true`. + * + * @param route - The base cdn route + * @param hash - The hash provided by Discord for this icon + * @param options - Optional options for the link + */ + private dynamicMakeURL( + route: string, + hash: string, + { forceStatic = false, ...options }: Readonly = {}, + ): string { + return this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options); + } + + /** + * Constructs the URL for the resource + * + * @param route - The base cdn route + * @param options - The extension/size options for the link + */ + private makeURL( + route: string, + { allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly = {}, + ): string { + // eslint-disable-next-line no-param-reassign + extension = String(extension).toLowerCase(); + + if (!allowedExtensions.includes(extension)) { + throw new RangeError(`Invalid extension provided: ${extension}\nMust be one of: ${allowedExtensions.join(', ')}`); + } + + if (size && !ALLOWED_SIZES.includes(size)) { + throw new RangeError(`Invalid size provided: ${size}\nMust be one of: ${ALLOWED_SIZES.join(', ')}`); + } + + const url = new URL(`${this.base}${route}.${extension}`); + + if (size) { + url.searchParams.set('size', String(size)); + } + + return url.toString(); + } +} diff --git a/src/api/README.md b/src/api/README.md new file mode 100644 index 0000000..c01cd44 --- /dev/null +++ b/src/api/README.md @@ -0,0 +1,13 @@ +
+ + # **Seyfert** + + seyfert + + **A brand new bleeding edge non bloated Discord framework** + + [![License](https://img.shields.io/npm/l/seyfert?style=flat-square&logo=apache&color=white)](https://github.com/tiramisulabs/biscuit/blob/main/LICENSE) + [![Version](https://img.shields.io/npm/v/seyfert?color=%23ff0000&logo=npm&style=flat-square)](https://www.npmjs.com/package/seyfert) + [![Discord](https://img.shields.io/discord/1003825077969764412?color=%23406da2&label=support&logo=discord&style=flat-square)](https://discord.com/invite/XNw2RZFzaP) + +
diff --git a/src/api/Router.ts b/src/api/Router.ts new file mode 100644 index 0000000..ffd6f30 --- /dev/null +++ b/src/api/Router.ts @@ -0,0 +1,64 @@ +import { CDN_URL } from '../common'; +import type { APIRoutes, ApiHandler, CDNRoute } from './index'; +import type { HttpMethods } from './shared'; + +export enum ProxyRequestMethod { + Delete = 'delete', + Get = 'get', + Patch = 'patch', + Post = 'post', + Put = 'put', +} + +const ArrRequestsMethods = Object.freeze(Object.values(ProxyRequestMethod)) as string[]; + +export class Router { + noop = () => { + return; + }; + + constructor(private rest: ApiHandler) {} + + createProxy(route = [] as string[]): APIRoutes { + return new Proxy(this.noop, { + get: (_, key: string) => { + if (ArrRequestsMethods.includes(key)) { + return (...options: any[]) => + this.rest.request(key.toUpperCase() as HttpMethods, `/${route.join('/')}`, ...options); + } + return this.createProxy([...route, key]); + }, + apply: (...[, _, args]) => { + return this.createProxy([...route, ...args.filter(x => x != null)]); + }, + }) as unknown as APIRoutes; + } +} + +export const CDNRouter = { + createProxy(route = [] as string[]): CDNRoute { + const noop = () => { + return; + }; + return new Proxy(noop, { + get: (_, key: string) => { + if (key === 'get') { + return (value?: string) => { + const lastRoute = `${CDN_URL}/${route.join('/')}`; + if (value) { + if (typeof value !== 'string') { + value = String(value); + } + return `${lastRoute}/${value}`; + } + return lastRoute; + }; + } + return this.createProxy([...route, key]); + }, + apply: (...[, _, args]) => { + return this.createProxy([...route, ...args.filter(x => x != null)]); + }, + }) as unknown as CDNRoute; + }, +}; diff --git a/src/api/Routes/applications.ts b/src/api/Routes/applications.ts new file mode 100644 index 0000000..eb9cf05 --- /dev/null +++ b/src/api/Routes/applications.ts @@ -0,0 +1,105 @@ +import type { + RESTGetAPIApplicationCommandResult, + RESTGetAPIApplicationCommandsQuery, + RESTGetAPIApplicationCommandsResult, + RESTGetAPIApplicationGuildCommandResult, + RESTGetAPIApplicationGuildCommandsQuery, + RESTGetAPIApplicationGuildCommandsResult, + RESTGetAPIApplicationRoleConnectionMetadataResult, + RESTGetAPIGuildApplicationCommandsPermissionsResult, + RESTPatchAPIApplicationCommandJSONBody, + RESTPatchAPIApplicationCommandResult, + RESTPatchAPIApplicationGuildCommandJSONBody, + RESTPatchAPIApplicationGuildCommandResult, + RESTPostAPIApplicationCommandsJSONBody, + RESTPostAPIApplicationCommandsResult, + RESTPostAPIApplicationGuildCommandsJSONBody, + RESTPostAPIApplicationGuildCommandsResult, + RESTPutAPIApplicationCommandPermissionsJSONBody, + RESTPutAPIApplicationCommandsJSONBody, + RESTPutAPIApplicationCommandsResult, + RESTPutAPIApplicationGuildCommandsJSONBody, + RESTPutAPIApplicationGuildCommandsResult, + RESTPutAPIApplicationRoleConnectionMetadataJSONBody, + RESTPutAPIApplicationRoleConnectionMetadataResult, + RESTPutAPIGuildApplicationCommandsPermissionsResult, +} from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface ApplicationRoutes { + applications: { + ( + id: string, + ): { + guilds: { + ( + id: string, + ): { + commands: { + get( + args?: RestArguments, + ): Promise; + post( + args: RestArguments, + ): Promise; + put( + args?: RestArguments, + ): Promise; + permissions: { + get( + args?: RestArguments, + ): Promise; + // put(args?: RestArguments): Promise + }; + ( + id: string, + ): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; + permissions: { + get( + args?: RestArguments, + ): Promise; + put( + args?: RestArguments, + ): Promise; + }; + }; + }; + }; + }; + commands: { + get( + args?: RestArguments, + ): Promise; + post( + args: RestArguments, + ): Promise; + put( + args?: RestArguments, + ): Promise; + ( + id: string, + ): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; + }; + }; + 'role-connections': { + metadata: { + get(args?: RestArguments): Promise; + put( + args: RestArguments, + ): Promise; + }; + }; + }; + }; +} diff --git a/src/api/Routes/cdn.ts b/src/api/Routes/cdn.ts new file mode 100644 index 0000000..7092954 --- /dev/null +++ b/src/api/Routes/cdn.ts @@ -0,0 +1,68 @@ +export interface CDNRoute { + embed: { + avatars: { + get(embed: UserAvatarDefault): string; + }; + }; + avatars(id: string): { + get(hash: string): string; + }; + icons(guildId: string): { + get(hash: string): string; + }; + splashes(guildId: string): { + get(hash: string): string; + }; + 'discovery-splashes'(guidId: string): { + get(hash: string): string; + }; + banners(id: string): { + get(hash: string): string; + }; + guilds(id: string): { + users(id: string): { + avatars(hash: string): { + get(): string; + }; + banners(hash: string): { + get(): string; + }; + }; + }; + emojis(id: string): { + get(): string; + }; + appIcons(appId: string): { + get(iconOrCover: string): string; + }; + 'app-assets'(appId: string): { + get(asset: string): string; + achievements(id: string): { + icons(hash: string): { + get(): string; + }; + }; + }; + 'team-icons'(teamId: string): { + get(hash: string): string; + }; + stickers(id: string): { + get(): string; + }; + 'role-icons'(roleId: string): { + get(icon: string): string; + }; + 'guild-events'(id: string): { + get(cover: string): string; + }; +} + +export interface CDNRoute { + 'app-assets'(id: '710982414301790216'): { + store(packBannerId: string): { + get(): string; + }; + }; +} + +export type UserAvatarDefault = 1 | 2 | 3 | 4 | 5 | number; diff --git a/src/api/Routes/channels.ts b/src/api/Routes/channels.ts new file mode 100644 index 0000000..7c14c7e --- /dev/null +++ b/src/api/Routes/channels.ts @@ -0,0 +1,269 @@ +import type { + RESTDeleteAPIChannelAllMessageReactionsResult, + RESTDeleteAPIChannelMessageReactionResult, + RESTDeleteAPIChannelMessageResult, + RESTDeleteAPIChannelPermissionResult, + RESTDeleteAPIChannelPinResult, + RESTDeleteAPIChannelRecipientResult, + RESTDeleteAPIChannelResult, + RESTDeleteAPIChannelThreadMembersResult, + RESTGetAPIChannelInvitesResult, + RESTGetAPIChannelMessageReactionUsersQuery, + RESTGetAPIChannelMessageReactionUsersResult, + RESTGetAPIChannelMessageResult, + RESTGetAPIChannelMessagesQuery, + RESTGetAPIChannelMessagesResult, + RESTGetAPIChannelPinsResult, + RESTGetAPIChannelResult, + RESTGetAPIChannelThreadMemberQuery, + RESTGetAPIChannelThreadMemberResult, + RESTGetAPIChannelThreadMembersQuery, + RESTGetAPIChannelThreadMembersResult, + RESTGetAPIChannelThreadsArchivedPrivateResult, + RESTGetAPIChannelThreadsArchivedPublicResult, + RESTGetAPIChannelThreadsArchivedQuery, + RESTGetAPIChannelUsersThreadsArchivedResult, + RESTGetAPIGuildWebhooksResult, + RESTPatchAPIChannelJSONBody, + RESTPatchAPIChannelMessageJSONBody, + RESTPatchAPIChannelMessageResult, + RESTPatchAPIChannelResult, + RESTPostAPIChannelFollowersJSONBody, + RESTPostAPIChannelFollowersResult, + RESTPostAPIChannelInviteJSONBody, + RESTPostAPIChannelInviteResult, + RESTPostAPIChannelMessageCrosspostResult, + RESTPostAPIChannelMessageJSONBody, + RESTPostAPIChannelMessageResult, + RESTPostAPIChannelMessagesBulkDeleteJSONBody, + RESTPostAPIChannelMessagesBulkDeleteResult, + RESTPostAPIChannelMessagesThreadsJSONBody, + RESTPostAPIChannelMessagesThreadsResult, + RESTPostAPIChannelThreadsJSONBody, + RESTPostAPIChannelThreadsResult, + RESTPostAPIChannelTypingResult, + RESTPostAPIChannelWebhookJSONBody, + RESTPostAPIChannelWebhookResult, + RESTPostAPIGuildForumThreadsJSONBody, + RESTPutAPIChannelMessageReactionResult, + RESTPutAPIChannelPermissionJSONBody, + RESTPutAPIChannelPermissionResult, + RESTPutAPIChannelPinResult, + RESTPutAPIChannelRecipientJSONBody, + RESTPutAPIChannelRecipientResult, + RESTPutAPIChannelThreadMembersResult, +} from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface ChannelRoutes { + channels(id: string): { + //. + get(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + users: { + ( + id: '@me', + ): { + threads: { + archived: { + private: { + //. + get( + args?: RestArguments, + ): Promise; + }; + }; + }; + }; + }; + 'thread-members': { + //. + get( + args?: RestArguments, + ): Promise; + ( + id: '@me', + ): { + //. + put(args?: RestArguments): Promise; + //. + delete(args?: RestArguments): Promise; + }; + ( + id: string, + ): { + //. + get( + args?: RestArguments, + ): Promise; + //. + put(args?: RestArguments): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + threads: { + //. + post( + args: RestArguments< + ProxyRequestMethod.Post, + RESTPostAPIChannelThreadsJSONBody | RESTPostAPIGuildForumThreadsJSONBody + >, + ): Promise; + archived: { + public: { + //. + get( + args?: RestArguments, + ): Promise; + }; + private: { + //. + get( + args?: RestArguments, + ): Promise; + }; + }; + }; + recipients: { + ( + id: string, + ): { + //. + put( + args?: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + pins: { + //. + get(args?: RestArguments): Promise; + ( + id: string, + ): { + //. + put(args?: RestArguments): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + followers: { + //. + post( + args: RestArguments, + ): Promise; + }; + permissions: { + ( + id: string, + ): { + //. + put( + args?: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + invites: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + }; + messages: { + //. + get( + args?: RestArguments, + ): Promise; + //. + post( + args: RestArguments, + ): Promise; + 'bulk-delete': { + //. + post( + args: RestArguments, + ): Promise; + }; + ( + id: string, + ): { + //. + get(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + threads: { + //. + post( + args: RestArguments, + ): Promise; + }; + crosspost: { + //. + post(args: RestArguments): Promise; + }; + reactions: { + //. + delete( + args?: RestArguments, + ): Promise; + ( + emoji: string, + ): { + //. + get( + args?: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + ( + id: '@me', + ): { + //. + put(args?: RestArguments): Promise; + //. + delete( + args?: RestArguments, + ): Promise; + }; + ( + id: string, + ): { + //. + delete( + args?: RestArguments, + ): Promise; + }; + }; + }; + }; + }; + typing: { + //. + post(args?: RestArguments): Promise; + }; + webhooks: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + }; + }; +} diff --git a/src/api/Routes/gateway.ts b/src/api/Routes/gateway.ts new file mode 100644 index 0000000..d680436 --- /dev/null +++ b/src/api/Routes/gateway.ts @@ -0,0 +1,12 @@ +import type { RESTGetAPIGatewayBotResult, RESTGetAPIGatewayResult } from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface GatewayRoutes { + gateway: { + get(args?: RestArguments): Promise; + bot: { + get(args?: RestArguments): Promise; + }; + }; +} diff --git a/src/api/Routes/guilds.ts b/src/api/Routes/guilds.ts new file mode 100644 index 0000000..ef93ae6 --- /dev/null +++ b/src/api/Routes/guilds.ts @@ -0,0 +1,454 @@ +import type { + APIThreadChannel, + Identify, + OmitInsert, + RESTDeleteAPIAutoModerationRuleResult, + RESTDeleteAPIGuildBanResult, + RESTDeleteAPIGuildEmojiResult, + RESTDeleteAPIGuildIntegrationResult, + RESTDeleteAPIGuildMemberResult, + RESTDeleteAPIGuildMemberRoleResult, + RESTDeleteAPIGuildResult, + RESTDeleteAPIGuildRoleResult, + RESTDeleteAPIGuildScheduledEventResult, + RESTDeleteAPIGuildStickerResult, + RESTDeleteAPIGuildTemplateResult, + RESTGetAPIAuditLogQuery, + RESTGetAPIAuditLogResult, + RESTGetAPIAutoModerationRuleResult, + RESTGetAPIAutoModerationRulesResult, + RESTGetAPIGuildBanResult, + RESTGetAPIGuildBansQuery, + RESTGetAPIGuildBansResult, + RESTGetAPIGuildChannelsResult, + RESTGetAPIGuildEmojiResult, + RESTGetAPIGuildEmojisResult, + RESTGetAPIGuildIntegrationsResult, + RESTGetAPIGuildInvitesResult, + RESTGetAPIGuildMemberResult, + RESTGetAPIGuildMembersQuery, + RESTGetAPIGuildMembersResult, + RESTGetAPIGuildMembersSearchQuery, + RESTGetAPIGuildMembersSearchResult, + RESTGetAPIGuildPreviewResult, + RESTGetAPIGuildPruneCountQuery, + RESTGetAPIGuildPruneCountResult, + RESTGetAPIGuildQuery, + RESTGetAPIGuildResult, + RESTGetAPIGuildRolesResult, + RESTGetAPIGuildScheduledEventQuery, + RESTGetAPIGuildScheduledEventResult, + RESTGetAPIGuildScheduledEventUsersQuery, + RESTGetAPIGuildScheduledEventUsersResult, + RESTGetAPIGuildScheduledEventsQuery, + RESTGetAPIGuildScheduledEventsResult, + RESTGetAPIGuildStickerResult, + RESTGetAPIGuildStickersResult, + RESTGetAPIGuildTemplatesResult, + RESTGetAPIGuildThreadsResult, + RESTGetAPIGuildVanityUrlResult, + RESTGetAPIGuildVoiceRegionsResult, + RESTGetAPIGuildWebhooksResult, + RESTGetAPIGuildWelcomeScreenResult, + RESTGetAPIGuildWidgetImageQuery, + RESTGetAPIGuildWidgetImageResult, + RESTGetAPIGuildWidgetJSONResult, + RESTGetAPIGuildWidgetSettingsResult, + RESTGetAPITemplateResult, + RESTPatchAPIAutoModerationRuleJSONBody, + RESTPatchAPIAutoModerationRuleResult, + RESTPatchAPICurrentGuildMemberJSONBody, + RESTPatchAPIGuildChannelPositionsJSONBody, + RESTPatchAPIGuildChannelPositionsResult, + RESTPatchAPIGuildEmojiJSONBody, + RESTPatchAPIGuildEmojiResult, + RESTPatchAPIGuildJSONBody, + RESTPatchAPIGuildMemberJSONBody, + RESTPatchAPIGuildMemberResult, + RESTPatchAPIGuildResult, + RESTPatchAPIGuildRoleJSONBody, + RESTPatchAPIGuildRolePositionsJSONBody, + RESTPatchAPIGuildRolePositionsResult, + RESTPatchAPIGuildRoleResult, + RESTPatchAPIGuildScheduledEventJSONBody, + RESTPatchAPIGuildScheduledEventResult, + RESTPatchAPIGuildStickerJSONBody, + RESTPatchAPIGuildStickerResult, + RESTPatchAPIGuildTemplateJSONBody, + RESTPatchAPIGuildTemplateResult, + RESTPatchAPIGuildVoiceStateCurrentMemberJSONBody, + RESTPatchAPIGuildVoiceStateCurrentMemberResult, + RESTPatchAPIGuildVoiceStateUserJSONBody, + RESTPatchAPIGuildVoiceStateUserResult, + RESTPatchAPIGuildWelcomeScreenJSONBody, + RESTPatchAPIGuildWelcomeScreenResult, + RESTPatchAPIGuildWidgetSettingsJSONBody, + RESTPatchAPIGuildWidgetSettingsResult, + RESTPostAPIAutoModerationRuleJSONBody, + RESTPostAPIAutoModerationRuleResult, + RESTPostAPIGuildChannelJSONBody, + RESTPostAPIGuildChannelResult, + RESTPostAPIGuildEmojiJSONBody, + RESTPostAPIGuildEmojiResult, + RESTPostAPIGuildPruneJSONBody, + RESTPostAPIGuildPruneResult, + RESTPostAPIGuildRoleJSONBody, + RESTPostAPIGuildRoleResult, + RESTPostAPIGuildScheduledEventJSONBody, + RESTPostAPIGuildScheduledEventResult, + RESTPostAPIGuildStickerFormDataBody, + RESTPostAPIGuildStickerResult, + RESTPostAPIGuildTemplatesJSONBody, + RESTPostAPIGuildTemplatesResult, + RESTPostAPIGuildsJSONBody, + RESTPostAPIGuildsMFAJSONBody, + RESTPostAPIGuildsMFAResult, + RESTPostAPIGuildsResult, + RESTPostAPITemplateCreateGuildJSONBody, + RESTPostAPITemplateCreateGuildResult, + RESTPutAPIGuildBanJSONBody, + RESTPutAPIGuildBanResult, + RESTPutAPIGuildMemberJSONBody, + RESTPutAPIGuildMemberResult, + RESTPutAPIGuildMemberRoleResult, + RESTPutAPIGuildTemplateSyncResult, +} from '../../common'; +import type { ProxyRequestMethod } from '../Router'; +import type { RestArguments } from '../api'; +import type { RawFile } from '../shared'; + +export interface GuildRoutes { + guilds: { + //. + post(args: RestArguments): Promise; + templates(code: string): { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + }; + ( + id: string, + ): { + //. + get(args?: RestArguments): Promise; + //. + patch(args: RestArguments): Promise; + //. + delete(args?: RestArguments): Promise; + webhooks: { + //. + get(args?: RestArguments): Promise; + }; + preview: { + //. + get(args?: RestArguments): Promise; + }; + 'audit-logs': { + //. + get(args?: RestArguments): Promise; + }; + 'auto-moderation': { + rules: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + ( + id: string, + ): { + //. + get(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + }; + channels: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + //. + patch( + args: RestArguments, + ): Promise; + }; + members: { + //. + get( + args?: RestArguments, + ): Promise; + search: { + //. + get( + args: RestArguments, + ): Promise; + }; + '@me': { + //. + patch( + args: RestArguments, + ): Promise; + }; + ( + id: string, + ): { + //. + get(args?: RestArguments): Promise; + //. + put( + args?: RestArguments, + ): Promise; + //. + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + roles(id: string): { + //. + put(args?: RestArguments): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + }; + threads: { + active: { + //. + get( + args?: RestArguments, + ): Promise }>>; + }; + }; + roles: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + //. + patch( + args: RestArguments, + ): Promise; + ( + id: string, + ): { + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + bans: { + //. + get(args?: RestArguments): Promise; + ( + userId: string, + ): { + //. + get(args?: RestArguments): Promise; + //. + put( + args?: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + mfa: { + //. + post( + args: RestArguments, + ): Promise; + }; + prune: { + //. + get( + args: RestArguments, + ): Promise; + //. + post( + args: RestArguments, + ): Promise; + }; + regions: { + //. + get(args?: RestArguments): Promise; + }; + invites: { + //. + get(args?: RestArguments): Promise; + }; + widget: { + //. + get(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + }; + 'widget.json': { + //. + get(args?: RestArguments): Promise; + }; + 'widget.png': { + //. + get( + args?: RestArguments, + ): Promise; + }; + integrations: { + //. + get(args?: RestArguments): Promise; + ( + id: string, + ): { + //. + delete(args?: RestArguments): Promise; + }; + }; + 'vanity-url': { + //. + get(args?: RestArguments): Promise; + }; + 'welcome-screen': { + //. + get(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + }; + // onboarding: { + // get(args:RestArguments); + // } + emojis: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + ( + id: string, + ): { + //. + get(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + 'voice-states': { + '@me': { + //. + patch( + args: RestArguments, + ): Promise; + }; + ( + id: string, + ): { + //. + patch( + args: RestArguments, + ): Promise; + }; + }; + stickers: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments< + ProxyRequestMethod.Post, + Omit, + {}, + OmitInsert[] + >, + ): Promise; + ( + id: string, + ): { + //. + get(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + 'scheduled-events': { + //. + get( + args?: RestArguments, + ): Promise; + //. + post( + args: RestArguments, + ): Promise; + ( + id: string, + ): { + //. + get( + args?: RestArguments, + ): Promise; + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + users: { + //. + get( + args?: RestArguments, + ): Promise; + }; + }; + }; + templates: { + //. + get(args?: RestArguments): Promise; + //. + post( + args: RestArguments, + ): Promise; + ( + code: string, + ): { + //. + put(args?: RestArguments): Promise; + //. + patch( + args: RestArguments, + ): Promise; + //. + delete(args?: RestArguments): Promise; + }; + }; + }; + }; +} diff --git a/src/api/Routes/index.ts b/src/api/Routes/index.ts new file mode 100644 index 0000000..469f2e2 --- /dev/null +++ b/src/api/Routes/index.ts @@ -0,0 +1,25 @@ +import type { ApplicationRoutes } from './applications'; +import type { ChannelRoutes } from './channels'; +import type { GatewayRoutes } from './gateway'; +import type { GuildRoutes } from './guilds'; +import type { InteractionRoutes } from './interactions'; +import type { InviteRoutes } from './invites'; +import type { StageInstanceRoutes } from './stage-instances'; +import type { StickerRoutes } from './stickers'; +import type { UserRoutes } from './users'; +import type { VoiceRoutes } from './voice'; +import type { WebhookRoutes } from './webhooks'; + +export * from './cdn'; + +export type APIRoutes = ApplicationRoutes & + ChannelRoutes & + GatewayRoutes & + GuildRoutes & + InteractionRoutes & + InviteRoutes & + StageInstanceRoutes & + StickerRoutes & + UserRoutes & + VoiceRoutes & + WebhookRoutes; diff --git a/src/api/Routes/interactions.ts b/src/api/Routes/interactions.ts new file mode 100644 index 0000000..026aa38 --- /dev/null +++ b/src/api/Routes/interactions.ts @@ -0,0 +1,19 @@ +import type { RESTPostAPIInteractionCallbackJSONBody } from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface InteractionRoutes { + interactions: { + ( + id: string, + ): { + ( + token: string, + ): { + callback: { + post(args: RestArguments): Promise; + }; + }; + }; + }; +} diff --git a/src/api/Routes/invites.ts b/src/api/Routes/invites.ts new file mode 100644 index 0000000..68c7951 --- /dev/null +++ b/src/api/Routes/invites.ts @@ -0,0 +1,10 @@ +import type { RESTDeleteAPIInviteResult, RESTGetAPIInviteQuery, RESTGetAPIInviteResult } from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface InviteRoutes { + invites(id: string): { + get(args?: RestArguments): Promise; + delete(args?: RestArguments): Promise; + }; +} diff --git a/src/api/Routes/stage-instances.ts b/src/api/Routes/stage-instances.ts new file mode 100644 index 0000000..dc0220a --- /dev/null +++ b/src/api/Routes/stage-instances.ts @@ -0,0 +1,27 @@ +import type { + RESTDeleteAPIStageInstanceResult, + RESTGetAPIStageInstanceResult, + RESTPatchAPIStageInstanceJSONBody, + RESTPatchAPIStageInstanceResult, + RESTPostAPIStageInstanceJSONBody, + RESTPostAPIStageInstanceResult, +} from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface StageInstanceRoutes { + 'stage-instances': { + post( + args: RestArguments, + ): Promise; + ( + id: string, + ): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; + }; + }; +} diff --git a/src/api/Routes/stickers.ts b/src/api/Routes/stickers.ts new file mode 100644 index 0000000..133e194 --- /dev/null +++ b/src/api/Routes/stickers.ts @@ -0,0 +1,12 @@ +import type { RESTGetAPIStickerResult, RESTGetNitroStickerPacksResult } from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface StickerRoutes { + stickers(id: string): { + get(args?: RestArguments): Promise; + }; + 'sticker-packs': { + get(args?: RestArguments): Promise; + }; +} diff --git a/src/api/Routes/users.ts b/src/api/Routes/users.ts new file mode 100644 index 0000000..ea9cd25 --- /dev/null +++ b/src/api/Routes/users.ts @@ -0,0 +1,67 @@ +import type { + APIDMChannel, + RESTDeleteAPIGuildResult, + RESTGetAPICurrentUserApplicationRoleConnectionResult, + RESTGetAPICurrentUserConnectionsResult, + RESTGetAPICurrentUserGuildsQuery, + RESTGetAPICurrentUserGuildsResult, + RESTGetAPICurrentUserResult, + RESTGetAPIUserResult, + RESTGetCurrentUserGuildMemberResult, + RESTPatchAPICurrentUserJSONBody, + RESTPatchAPICurrentUserResult, + RESTPostAPICurrentUserCreateDMChannelJSONBody, + RESTPutAPICurrentUserApplicationRoleConnectionJSONBody, + RESTPutAPICurrentUserApplicationRoleConnectionResult, +} from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface UserRoutes { + users: { + ( + id: string, + ): { + get(args?: RestArguments): Promise; + }; + ( + id: '@me', + ): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + guilds: { + get( + args?: RestArguments, + ): Promise; + ( + id: string, + ): { + member: { + get(args?: RestArguments): Promise; + }; + delete(args?: RestArguments): Promise; + }; + }; + channels: { + post( + args: RestArguments, + ): Promise; + }; + connections: { + get(args?: RestArguments): Promise; + }; + applications(applicationId: string): { + 'role-connection': { + get( + args?: RestArguments, + ): Promise; + put( + args: RestArguments, + ): Promise; + }; + }; + }; + }; +} diff --git a/src/api/Routes/voice.ts b/src/api/Routes/voice.ts new file mode 100644 index 0000000..48a4f7e --- /dev/null +++ b/src/api/Routes/voice.ts @@ -0,0 +1,11 @@ +import type { RESTGetAPIVoiceRegionsResult } from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface VoiceRoutes { + voice: { + region: { + get(args?: RestArguments): Promise; + }; + }; +} diff --git a/src/api/Routes/webhooks.ts b/src/api/Routes/webhooks.ts new file mode 100644 index 0000000..91746cd --- /dev/null +++ b/src/api/Routes/webhooks.ts @@ -0,0 +1,81 @@ +import type { + RESTDeleteAPIWebhookResult, + RESTDeleteAPIWebhookWithTokenMessageResult, + RESTDeleteAPIWebhookWithTokenResult, + RESTGetAPIWebhookResult, + RESTGetAPIWebhookWithTokenMessageResult, + RESTGetAPIWebhookWithTokenResult, + RESTPatchAPIWebhookJSONBody, + RESTPatchAPIWebhookResult, + RESTPatchAPIWebhookWithTokenJSONBody, + RESTPatchAPIWebhookWithTokenMessageJSONBody, + RESTPatchAPIWebhookWithTokenMessageResult, + RESTPatchAPIWebhookWithTokenResult, + RESTPostAPIWebhookWithTokenGitHubQuery, + RESTPostAPIWebhookWithTokenGitHubResult, + RESTPostAPIWebhookWithTokenGitHubWaitResult, + RESTPostAPIWebhookWithTokenJSONBody, + RESTPostAPIWebhookWithTokenQuery, + RESTPostAPIWebhookWithTokenResult, + RESTPostAPIWebhookWithTokenSlackQuery, + RESTPostAPIWebhookWithTokenSlackResult, + RESTPostAPIWebhookWithTokenSlackWaitResult, + RESTPostAPIWebhookWithTokenWaitResult, +} from '../../common'; +import type { RestArguments } from '../api'; +import type { ProxyRequestMethod } from '../Router'; + +export interface WebhookRoutes { + webhooks(id: string): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; + ( + token: string, + ): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; + post( + args: RestArguments< + ProxyRequestMethod.Post, + RESTPostAPIWebhookWithTokenJSONBody, + RESTPostAPIWebhookWithTokenQuery + >, + ): Promise; + slack: { + post( + args: RestArguments< + ProxyRequestMethod.Post, + RESTPostAPIWebhookWithTokenJSONBody, + RESTPostAPIWebhookWithTokenSlackQuery + >, + ): Promise; + }; + github: { + post( + args: RestArguments< + ProxyRequestMethod.Post, + RESTPostAPIWebhookWithTokenJSONBody, + RESTPostAPIWebhookWithTokenGitHubQuery + >, + ): Promise; + }; + messages: { + ( + id: string | '@original', + ): { + get(args?: RestArguments): Promise; + patch( + args: RestArguments, + ): Promise; + delete(args?: RestArguments): Promise; + }; + }; + }; + }; +} diff --git a/src/api/api.ts b/src/api/api.ts new file mode 100644 index 0000000..4de2c40 --- /dev/null +++ b/src/api/api.ts @@ -0,0 +1,405 @@ +import { filetypeinfo } from 'magic-bytes.js'; +import { setTimeout as delay } from 'node:timers/promises'; +import { Logger } from '../common'; +import { snowflakeToTimestamp } from '../structures/extra/functions'; +import { CDN } from './CDN'; +import type { ProxyRequestMethod } from './Router'; +import { Bucket } from './bucket'; +import { + DefaultUserAgent, + OverwrittenMimeTypes, + type ApiHandlerInternalOptions, + type ApiHandlerOptions, + type ApiRequestOptions, + type HttpMethods, + type RawFile, + type RequestHeaders, +} from './shared'; +import { isBufferLike } from './utils/utils'; + +export class ApiHandler { + options: ApiHandlerInternalOptions; + globalBlock = false; + ratelimits = new Map(); + readyQueue: (() => void)[] = []; + cdn = new CDN(); + debugger?: Logger; + + constructor(options: ApiHandlerOptions) { + this.options = { + ...options, + userAgent: DefaultUserAgent, + }; + if (options.debug) { + this.debugger = new Logger({ + name: '[API]', + }); + } + } + + globalUnblock() { + this.globalBlock = false; + let cb; + while ((cb = this.readyQueue.shift())) { + cb(); + } + } + + async request( + method: HttpMethods, + url: `/${string}`, + { auth = true, ...request }: ApiRequestOptions = {}, + ): Promise { + const route = request.route || this.routefy(url, method); + let attempts = 0; + + const callback = async (next: () => void, resolve: (data: any) => void, reject: (err: unknown) => void) => { + const headers = { + 'User-Agent': this.options.userAgent, + } satisfies RequestHeaders; + + const { data, finalUrl } = this.parseRequest({ + url, + headers, + request: { ...request, auth }, + }); + + let response; + + try { + const url = `${this.options.domain}/${this.options.baseUrl}${finalUrl}`; + this.debugger?.debug(`Sending, Method: ${method} | Url: [${finalUrl}](${route}) | Auth: ${auth}`); + response = await fetch(url, { + method, + headers, + body: data, + }); + this.debugger?.debug(`Received response: ${response.statusText}(${response.status})`); + } catch (err) { + this.debugger?.debug('Fetch error', err); + next(); + reject(err); + return; + } + + const now = Date.now(); + const headerNow = Date.parse(response.headers.get('date') ?? ''); + + this.setRatelimitsBucket(route, response); + this.setResetBucket(route, response, now, headerNow); + + let result: string | Record = await response.text(); + + if (response.status >= 300) { + if (response.status === 429) { + const result429 = await this.handle429(route, method, url, request, response, result, next, reject, now); + if (result429 !== false) return resolve(result429); + return this.clearResetInterval(route); + } + if ([502, 503].includes(response.status) && ++attempts < 4) { + this.clearResetInterval(route); + return this.handle50X(method, url, request, next); + } + this.clearResetInterval(route); + next(); + if (result.length > 0) { + if (response.headers.get('content-type') === 'application/json') { + try { + result = JSON.parse(result); + } catch (err) { + this.debugger?.warn('Error parsing result error (', result, ')', err); + reject(err); + return; + } + } + } + const parsedError = this.parseError(response, result); + this.debugger?.warn(parsedError); + reject(parsedError); + return; + } + + if (result.length > 0) { + if (response.headers.get('content-type') === 'application/json') { + try { + result = JSON.parse(result); + } catch (err) { + this.debugger?.warn('Error parsing result (', result, ')', err); + next(); + reject(err); + return; + } + } + } + + next(); + return resolve((result || undefined) as T); + }; + + return new Promise((resolve, reject) => { + if (this.globalBlock && auth) { + this.readyQueue.push(() => { + if (!this.ratelimits.has(route)) { + this.ratelimits.set(route, new Bucket(1)); + } + this.ratelimits.get(route)!.push({ next: callback, resolve, reject }, request.unshift); + }); + } else { + if (!this.ratelimits.has(route)) { + this.ratelimits.set(route, new Bucket(1)); + } + this.ratelimits.get(route)!.push({ next: callback, resolve, reject }, request.unshift); + } + }); + } + + parseError(response: Response, result: unknown) { + let errMessage = ''; + if (typeof result === 'object' && result) { + if ('message' in result) { + errMessage += `${result.message}${'code' in result ? ` ${result.code}` : ''}\n`; + } + + if ('errors' in result && result) { + errMessage += `${JSON.stringify(result.errors, null, 2)}\n`; + } + } + if (response.status) { + return new Error(errMessage ?? response.statusText); + } + return new Error('Unknown error'); + } + + async handle50X(method: HttpMethods, url: `/${string}`, request: ApiRequestOptions, next: () => void) { + const wait = Math.floor(Math.random() * 1900 + 100); + this.debugger?.warn(`Handling a 50X status, retrying in ${wait}ms`); + next(); + await delay(wait); + return this.request(method, url, { + body: request.body, + auth: request.auth, + reason: request.reason, + route: request.route, + unshift: true, + }); + } + + async handle429( + route: string, + method: HttpMethods, + url: `/${string}`, + request: ApiRequestOptions, + response: Response, + result: any, + next: () => void, + reject: (err: unknown) => void, + now: number, + ) { + const content = typeof request === 'object' ? `${JSON.stringify(request)} ` : ''; + let retryAfter; + + try { + retryAfter = JSON.parse(result).retry_after * 1000; + } catch (err) { + this.debugger?.warn(`Unexpected error: ${err}`); + reject(err); + return false; + } + + this.debugger?.info( + `${ + response.headers.get('x-ratelimit-global') ? 'Global' : 'Unexpected' + } 429: ${result}\n${content} ${now} ${route} ${response.status}: ${this.ratelimits.get(route)!.remaining}/${ + this.ratelimits.get(route)!.limit + } left | Reset ${retryAfter} (${this.ratelimits.get(route)!.reset - now}ms left) | Scope ${response.headers.get( + 'x-ratelimit-scope', + )}`, + ); + if (retryAfter) { + await delay(retryAfter); + next(); + return this.request(method, url, { + body: request.body, + auth: request.auth, + reason: request.reason, + route: request.route, + unshift: true, + }); + } + next(); + return this.request(method, url, { + body: request.body, + auth: request.auth, + reason: request.reason, + route: request.route, + unshift: true, + }); + } + + clearResetInterval(route: string) { + clearInterval(this.ratelimits.get(route)!.processingResetAfter as NodeJS.Timeout); + this.ratelimits.get(route)!.processingResetAfter = undefined; + this.ratelimits.get(route)!.resetAfter = 0; + } + + setResetBucket(route: string, resp: Response, now: number, headerNow: number) { + const retryAfter = Number(resp.headers.get('x-ratelimit-reset-after') || resp.headers.get('retry-after')) * 1000; + + if (retryAfter >= 0) { + if (resp.headers.get('x-ratelimit-global')) { + this.globalBlock = true; + setTimeout(() => this.globalUnblock(), retryAfter || 1); + } else { + this.ratelimits.get(route)!.reset = (retryAfter || 1) + now; + } + } else if (resp.headers.get('x-ratelimit-reset')) { + let resetTime = +resp.headers.get('x-ratelimit-reset')! * 1000; + if (route.endsWith('/reactions/:id') && +resp.headers.get('x-ratelimit-reset')! * 1000 - headerNow === 1000) { + resetTime = now + 250; + } + this.ratelimits.get(route)!.reset = Math.max(resetTime, now); + } else { + this.ratelimits.get(route)!.reset = now; + } + } + + setRatelimitsBucket(route: string, resp: Response) { + if (resp.headers.get('x-ratelimit-limit')) { + this.ratelimits.get(route)!.limit = +resp.headers.get('x-ratelimit-limit')!; + } + + this.ratelimits.get(route)!.remaining = + resp.headers.get('x-ratelimit-remaining') === undefined ? 1 : +resp.headers.get('x-ratelimit-remaining')!; + + if (this.options.smartBucket) { + if ( + resp.headers.get('x-ratelimit-reset-after') && + !this.ratelimits.get(route)!.resetAfter && + Number(resp.headers.get('x-ratelimit-limit')) === Number(resp.headers.get('x-ratelimit-remaining')) + 1 + ) { + this.ratelimits.get(route)!.resetAfter = +resp.headers.get('x-ratelimit-reset-after')! * 1000; + } + + if (this.ratelimits.get(route)!.resetAfter && !this.ratelimits.get(route)!.remaining) { + this.ratelimits.get(route)!.triggerResetAfter(); + } + } + } + + parseRequest(options: { + url: string; + headers: RequestHeaders; + request: ApiRequestOptions; + }) { + let finalUrl = options.url; + let data: string | FormData | undefined; + if (options.request.auth) { + options.headers.Authorization = `Bot ${this.options.token}`; + } + if (options.request.query) { + finalUrl += `?${new URLSearchParams(options.request.query)}`; + } + if (options.request.files) { + const formData = new FormData(); + + for (const [index, file] of options.request.files.entries()) { + const fileKey = file.key ?? `files[${index}]`; + + if (isBufferLike(file.data)) { + let contentType = file.contentType; + + if (!contentType) { + const [parsedType] = filetypeinfo(file.data); + + if (parsedType) { + contentType = + OverwrittenMimeTypes[parsedType.mime as keyof typeof OverwrittenMimeTypes] ?? + parsedType.mime ?? + 'application/octet-stream'; + } + } + + formData.append(fileKey, new Blob([file.data], { type: contentType }), file.name); + } else { + formData.append(fileKey, new Blob([`${file.data}`], { type: file.contentType }), file.name); + } + } + + if (options.request.body) { + if (options.request.appendToFormData) { + for (const [key, value] of Object.entries(options.request.body)) { + formData.append(key, value); + } + } else { + formData.append('payload_json', JSON.stringify(options.request.body)); + } + } + data = formData; + } else if (options.request.body) { + options.headers['Content-Type'] = 'application/json'; + data = JSON.stringify(options.request.body); + } + if (options.request.reason) { + options.headers['X-Audit-Log-Reason'] = encodeURIComponent(options.request.reason); + } + + return { data, finalUrl } as { data: typeof data; finalUrl: `/${string}` }; + } + + routefy(url: string, method: HttpMethods): `/${string}` { + let route = url + .replace(/\/([a-z-]+)\/(?:[0-9]{17,19})/g, (match, p) => + p === 'channels' || p === 'guilds' || p === 'webhooks' ? match : `/${p}/:id`, + ) + .replace(/\/reactions\/[^/]+/g, '/reactions/:id') + .replace(/\/reactions\/:id\/[^/]+/g, '/reactions/:id/:userID') + .replace(/^\/webhooks\/(\d+)\/[A-Za-z0-9-_]{64,}/, '/webhooks/$1/:token'); + + if (method === 'DELETE' && route.endsWith('/messages/:id')) { + const messageID = url.slice(url.lastIndexOf('/') + 1); + const createdAt = Number(snowflakeToTimestamp(messageID)); + if (Date.now() - createdAt >= 1000 * 60 * 60 * 24 * 14) { + method += '_OLD'; + } else if (Date.now() - createdAt <= 1000 * 10) { + method += '_NEW'; + } + route = method + route; + } else if (method === 'GET' && /\/guilds\/[0-9]+\/channels$/.test(route)) { + route = '/guilds/:id/channels'; + } + if (method === 'PUT' || method === 'DELETE') { + const index = route.indexOf('/reactions'); + if (index !== -1) { + route = `MODIFY${route.slice(0, index + 10)}`; + } + } + return route as `/${string}`; + } +} + +export type RequestOptions = Pick; +export type RequestObject< + M extends ProxyRequestMethod, + B = Record, + Q = Record, + F extends RawFile[] = RawFile[], +> = { + query?: Q; +} & RequestOptions & + (M extends `${ProxyRequestMethod.Get}` + ? unknown + : { + body?: B; + files?: F; + }); + +export type RestArguments< + M extends ProxyRequestMethod, + B = any, + Q extends never | Record = any, + F extends RawFile[] = RawFile[], +> = M extends ProxyRequestMethod.Get + ? Q extends never + ? RequestObject + : never + : RequestObject; diff --git a/src/api/bucket.ts b/src/api/bucket.ts new file mode 100644 index 0000000..fc7c142 --- /dev/null +++ b/src/api/bucket.ts @@ -0,0 +1,78 @@ +export class Bucket { + remaining: number; + reset = 0; + resetAfter = 0; + queue: { + next: (cb: () => void, resolve: (data: any) => void, reject: (err: unknown) => void) => any; + resolve: (data: any) => void; + reject: (err: unknown) => void; + }[] = []; + processing?: NodeJS.Timeout | boolean; + processingResetAfter?: NodeJS.Timeout | boolean; + last?: number; + constructor(public limit: number) { + this.remaining = this.limit; + } + + process(override = false) { + if (!this.queue.length) { + if (this.processing) { + clearTimeout(this.processing as NodeJS.Timeout); + this.processing = false; + } + return; + } + if (this.processing && !override) { + return; + } + const now = Date.now(); + if (!this.reset || this.reset < now) { + this.reset = now; + this.remaining = this.limit; + } + this.last = now; + if (this.remaining <= 0) { + this.processing = setTimeout( + () => { + this.processing = false; + this.process(true); + }, + this.resetAfter ? 0.5 : Math.max(0, (this.reset || 0) - now) + 1, + ); + return; + } + --this.remaining; + this.processing = true; + + const shift = this.queue.shift()!; + shift.next( + () => { + if (this.queue.length > 0) { + this.process(true); + } else { + this.processing = false; + } + }, + shift.resolve, + shift.reject, + ); + } + + push(func: this['queue'][number], unshift?: boolean) { + if (unshift) { + this.queue.unshift(func); + } else { + this.queue.push(func); + } + this.process(); + } + + triggerResetAfter() { + if (!this.processingResetAfter && this.resetAfter) { + this.processingResetAfter = setTimeout(() => { + this.remaining++; + this.processingResetAfter = undefined; + }, this.resetAfter * 1.5); + } + } +} diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..40f8800 --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,5 @@ +export * from './CDN'; +export * from './Router'; +export * from './Routes'; +export * from './api'; +export * from './shared'; diff --git a/src/api/shared.ts b/src/api/shared.ts new file mode 100644 index 0000000..9c70cfe --- /dev/null +++ b/src/api/shared.ts @@ -0,0 +1,37 @@ +export * from './api'; +export * from './utils/constants'; +export * from './utils/types'; +export { calculateUserDefaultAvatarIndex } from './utils/utils'; + +export interface ApiHandlerOptions { + baseUrl: string; + domain: string; + token: string; + debug?: boolean; + agent?: string; + smartBucket?: boolean; +} + +export interface ApiHandlerInternalOptions extends ApiHandlerOptions { + userAgent: string; +} + +export interface RawFile { + contentType?: string; + data: Buffer | Uint8Array | boolean | number | string; + key?: string; + name: string; +} + +export interface ApiRequestOptions { + body?: Record; + query?: Record; + files?: RawFile[]; + auth?: boolean; + reason?: string; + route?: `/${string}`; + unshift?: boolean; + appendToFormData?: boolean; +} + +export type HttpMethods = 'GET' | 'DELETE' | 'PUT' | 'POST' | 'PATCH'; diff --git a/src/api/utils/constants.ts b/src/api/utils/constants.ts new file mode 100644 index 0000000..3a68e3a --- /dev/null +++ b/src/api/utils/constants.ts @@ -0,0 +1,13 @@ +export const DefaultUserAgent = 'DiscordBot (https://seyfert.dev)'; +export const ALLOWED_EXTENSIONS = ['webp', 'png', 'jpg', 'jpeg', 'gif'] as const satisfies readonly string[]; +export const ALLOWED_STICKER_EXTENSIONS = ['png', 'json', 'gif'] as const satisfies readonly string[]; +export const ALLOWED_SIZES = [16, 32, 64, 128, 256, 512, 1_024, 2_048, 4_096] as const satisfies readonly number[]; + +export type ImageExtension = (typeof ALLOWED_EXTENSIONS)[number]; +export type StickerExtension = (typeof ALLOWED_STICKER_EXTENSIONS)[number]; +export type ImageSize = (typeof ALLOWED_SIZES)[number]; + +export const OverwrittenMimeTypes = { + // https://github.com/discordjs/discord.js/issues/8557 + 'image/apng': 'image/png', +} as const satisfies Readonly>; diff --git a/src/api/utils/types.ts b/src/api/utils/types.ts new file mode 100644 index 0000000..35f5669 --- /dev/null +++ b/src/api/utils/types.ts @@ -0,0 +1,17 @@ +export interface RequestHeaders { + Authorization?: string; + 'User-Agent': string; + 'X-Audit-Log-Reason'?: string; + 'Content-Type'?: string; +} + +/** + * Possible API methods to be used when doing requests + */ +export enum RequestMethod { + Delete = 'DELETE', + Get = 'GET', + Patch = 'PATCH', + Post = 'POST', + Put = 'PUT', +} diff --git a/src/api/utils/utils.ts b/src/api/utils/utils.ts new file mode 100644 index 0000000..1d9beb2 --- /dev/null +++ b/src/api/utils/utils.ts @@ -0,0 +1,19 @@ +import type { Snowflake } from 'discord-api-types/v10'; + +/** + * Calculates the default avatar index for a given user id. + * + * @param userId - The user id to calculate the default avatar index for + */ +export function calculateUserDefaultAvatarIndex(userId: Snowflake) { + return Number(BigInt(userId) >> 22n) % 6; +} + +/** + * Verifies that a value is a buffer-like object. + * + * @param value - The value to check + */ +export function isBufferLike(value: unknown): value is ArrayBuffer | Buffer | Uint8Array | Uint8ClampedArray { + return value instanceof ArrayBuffer || value instanceof Uint8Array || value instanceof Uint8ClampedArray; +} diff --git a/src/builders/ActionRow.ts b/src/builders/ActionRow.ts new file mode 100644 index 0000000..29308cc --- /dev/null +++ b/src/builders/ActionRow.ts @@ -0,0 +1,68 @@ +import { + ComponentType, + type APIActionRowComponent, + type APIActionRowComponentTypes, + type APIMessageActionRowComponent, + type RestOrArray, +} from '../common'; +import { BaseComponentBuilder } from './Base'; +import { fromComponent } from './index'; +import type { BuilderComponents, FixedComponents } from './types'; + +/** + * Represents an Action Row component in a message. + * @template T - The type of components in the Action Row. + */ +export class ActionRow extends BaseComponentBuilder< + APIActionRowComponent +> { + /** + * Creates a new instance of the ActionRow class. + * @param data - Optional data to initialize the Action Row. + * @example + * const actionRow = new ActionRow