diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..46cbed7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +services: + postgresql: + image: bitnami/postgresql + ports: + - 5432:5432 + environment: + - POSTGRESQL_USERNAME=postgres + - POSTGRESQL_PASSWORD=postgres + - POSTGRESQL_DATABASE=codify diff --git a/eslint.config.mjs b/eslint.config.mjs index f1da2a8..182d34b 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,20 +2,33 @@ import eslint from '@eslint/js' import tseslint from 'typescript-eslint' import prettier from 'eslint-plugin-prettier' import simpleImportSort from 'eslint-plugin-simple-import-sort' +import unusedImports from 'eslint-plugin-unused-imports' +import eslintImport from 'eslint-plugin-import' + +import globals from 'globals' export default tseslint.config( { ignores: ['node_modules', 'dist', 'generated'] }, { - extends: [eslint.configs.recommended, ...tseslint.configs.recommended], + extends: [...tseslint.configs.recommendedTypeChecked, eslint.configs.recommended], files: ['**/*.ts'], plugins: { 'simple-import-sort': simpleImportSort, 'prettier': prettier, + 'unused-imports': unusedImports, + 'eslint-plugin-import': eslintImport, }, languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, parser: tseslint.parser, ecmaVersion: 2020, sourceType: 'module', + globals: { + ...globals.node + } }, rules: { 'prettier/prettier': [ @@ -29,6 +42,38 @@ export default tseslint.config( semi: false, }, ], - } + 'unused-imports/no-unused-imports': 'error', + 'unused-imports/no-unused-vars': [ + 'warn', + { + vars: 'all', + varsIgnorePattern: '^_', + args: 'after-used', + argsIgnorePattern: '^_', + }, + ], + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', + 'no-duplicate-imports': ["error", { "includeExports": true }], + 'eslint-plugin-import/no-duplicates': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + vars: 'all', + varsIgnorePattern: '^_', + args: 'after-used', + argsIgnorePattern: '^_', + }, + ], + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/no-misused-promises': 'off', + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/no-require-imports': 'off' + }, } ) diff --git a/package.json b/package.json index 776c860..199c0c0 100644 --- a/package.json +++ b/package.json @@ -2,15 +2,15 @@ "name": "codify-bot", "version": "1.0.0", "description": "The new Official Codify Bot Discord", - "main": "src/bot.ts", + "main": "src/index.ts", "scripts": { - "start:dev": "tsx --watch src/bot.ts", - "start": "node dist/bot.js", + "start": "node dist/index.js", + "start:dev": "tsx --watch src/index.ts", "build": "tsup src --out-dir dist", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\"", "lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", - "db_gui": "npx prisma studio", - "db_apply": "npx prisma migrate deploy" + "db:gui": "pnpm dlx prisma studio", + "db:apply": "pnpm dlx prisma migrate deploy" }, "keywords": [], "author": "Dev Curumin", @@ -28,8 +28,11 @@ "@eslint/js": "9.26.0", "@types/node": "22.15.15", "eslint": "9.26.0", + "eslint-plugin-import": "2.31.0", "eslint-plugin-prettier": "5.4.0", "eslint-plugin-simple-import-sort": "12.1.1", + "eslint-plugin-unused-imports": "4.1.4", + "globals": "16.1.0", "ts-node": "10.9.2", "tsconfig-paths": "4.2.0", "tsup": "8.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b25a7d2..77efc34 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,12 +39,21 @@ importers: eslint: specifier: 9.26.0 version: 9.26.0 + eslint-plugin-import: + specifier: 2.31.0 + version: 2.31.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0) eslint-plugin-prettier: specifier: 5.4.0 version: 5.4.0(eslint@9.26.0)(prettier@3.5.3) eslint-plugin-simple-import-sort: specifier: 12.1.1 version: 12.1.1(eslint@9.26.0) + eslint-plugin-unused-imports: + specifier: 4.1.4 + version: 4.1.4(@typescript-eslint/eslint-plugin@8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0) + globals: + specifier: 16.1.0 + version: 16.1.0 ts-node: specifier: 10.9.2 version: 10.9.2(@types/node@22.15.15)(typescript@5.8.3) @@ -493,6 +502,9 @@ packages: cpu: [x64] os: [win32] + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + '@sapphire/async-queue@1.5.5': resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -523,6 +535,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/node@22.15.15': resolution: {integrity: sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==} @@ -626,6 +641,38 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -661,6 +708,10 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} @@ -722,6 +773,26 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -734,6 +805,14 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -749,6 +828,10 @@ packages: resolution: {integrity: sha512-lncTRk0k+8Q5D3nThnODBR8fR8x2fM798o8Vsr40Krx0DjPwpZCuxxTcFMrXMQVOqM1QB9wqWgaXPg3TbmlHqA==} engines: {node: '>=18'} + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dotenv@16.5.0: resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} engines: {node: '>=12'} @@ -773,6 +856,10 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + es-abstract@1.23.9: + resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + engines: {node: '>= 0.4'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -785,6 +872,18 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + esbuild-register@3.6.0: resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} peerDependencies: @@ -802,6 +901,40 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.12.0: + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.31.0: + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint-plugin-prettier@5.4.0: resolution: {integrity: sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -821,6 +954,15 @@ packages: peerDependencies: eslint: '>=5.0.0' + eslint-plugin-unused-imports@4.1.4: + resolution: {integrity: sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0 + eslint: ^9.0.0 || ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + eslint-scope@8.3.0: resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -935,6 +1077,10 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + foreground-child@3.3.1: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} @@ -955,6 +1101,13 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -963,6 +1116,10 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + get-tsconfig@4.10.0: resolution: {integrity: sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==} @@ -982,6 +1139,14 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} + globals@16.1.0: + resolution: {integrity: sha512-aibexHNbb/jiUSObBgpHLj+sIuUmJnYcgXBlrfsiDZ9rt4aF2TFRbyLgZ2iFQuVZ1K5Mx3FVkbKRSgKrbK3K2g==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -989,14 +1154,29 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -1024,22 +1204,74 @@ packages: inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -1047,6 +1279,45 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1070,6 +1341,10 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -1181,6 +1456,26 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -1192,6 +1487,10 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} @@ -1219,6 +1518,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -1280,6 +1582,10 @@ packages: resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} engines: {node: '>=16.20.0'} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + postcss-load-config@6.0.1: resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} @@ -1368,6 +1674,14 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1379,6 +1693,11 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -1395,12 +1714,28 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + semver@7.7.1: resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} engines: {node: '>=10'} @@ -1414,6 +1749,18 @@ packages: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -1465,6 +1812,18 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -1490,6 +1849,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + synckit@0.11.4: resolution: {integrity: sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -1549,6 +1912,9 @@ packages: '@swc/wasm': optional: true + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tsconfig-paths@4.2.0: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} @@ -1588,6 +1954,22 @@ packages: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + typescript-eslint@8.32.0: resolution: {integrity: sha512-UMq2kxdXCzinFFPsXc9o2ozIpYCCOiEC46MG3yEh5Vipq6BO27otTtEBZA1fQ66DulEUgE97ucQ/3YY66CPg0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1600,6 +1982,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -1627,6 +2013,22 @@ packages: whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2030,6 +2432,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.40.2': optional: true + '@rtsao/scc@1.1.0': {} + '@sapphire/async-queue@1.5.5': {} '@sapphire/shapeshift@4.0.0': @@ -2051,6 +2455,8 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/json5@0.0.29': {} + '@types/node@22.15.15': dependencies: undici-types: 6.21.0 @@ -2176,6 +2582,60 @@ snapshots: argparse@2.0.1: {} + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + balanced-match@1.0.2: {} body-parser@2.2.0: @@ -2219,6 +2679,13 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2270,12 +2737,46 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + debug@4.4.0: dependencies: ms: 2.1.3 deep-is@0.1.4: {} + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + depd@2.0.0: {} diff@4.0.2: {} @@ -2301,6 +2802,10 @@ snapshots: - bufferutil - utf-8-validate + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + dotenv@16.5.0: {} dunder-proto@1.0.1: @@ -2319,6 +2824,60 @@ snapshots: encodeurl@2.0.0: {} + es-abstract@1.23.9: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-regex: 1.2.1 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -2327,6 +2886,23 @@ snapshots: dependencies: es-errors: 1.3.0 + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + esbuild-register@3.6.0(esbuild@0.25.4): dependencies: debug: 4.4.0 @@ -2366,6 +2942,53 @@ snapshots: escape-string-regexp@4.0.0: {} + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.26.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.32.0(eslint@9.26.0)(typescript@5.8.3) + eslint: 9.26.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.26.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.26.0) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.32.0(eslint@9.26.0)(typescript@5.8.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-prettier@5.4.0(eslint@9.26.0)(prettier@3.5.3): dependencies: eslint: 9.26.0 @@ -2377,6 +3000,12 @@ snapshots: dependencies: eslint: 9.26.0 + eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0): + dependencies: + eslint: 9.26.0 + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3) + eslint-scope@8.3.0: dependencies: esrecurse: 4.3.0 @@ -2545,6 +3174,10 @@ snapshots: flatted@3.3.3: {} + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + foreground-child@3.3.1: dependencies: cross-spawn: 7.0.6 @@ -2559,6 +3192,17 @@ snapshots: function-bind@1.1.2: {} + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2577,6 +3221,12 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + get-tsconfig@4.10.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -2600,14 +3250,35 @@ snapshots: globals@14.0.0: {} + globals@16.1.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + gopd@1.2.0: {} graphemer@1.4.0: {} + has-bigints@1.1.0: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + has-symbols@1.1.0: {} + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -2635,20 +3306,125 @@ snapshots: inherits@2.0.4: {} + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + ipaddr.js@1.9.1: {} + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-extglob@2.1.1: {} + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + is-fullwidth-code-point@3.0.0: {} + is-generator-function@1.1.0: + dependencies: + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-map@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-number@7.0.0: {} is-promise@4.0.0: {} + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + isexe@2.0.0: {} jackspeak@3.4.3: @@ -2669,6 +3445,10 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + json5@1.0.2: + dependencies: + minimist: 1.2.8 + json5@2.2.3: {} keyv@4.5.4: @@ -2751,6 +3531,37 @@ snapshots: object-inspect@1.13.4: {} + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -2768,6 +3579,12 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 @@ -2788,6 +3605,8 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -2840,6 +3659,8 @@ snapshots: pkce-challenge@5.0.0: {} + possible-typed-array-names@1.1.0: {} + postcss-load-config@6.0.1(tsx@4.19.4): dependencies: lilconfig: 3.1.3 @@ -2900,12 +3721,38 @@ snapshots: readdirp@4.1.2: {} + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + resolve-from@4.0.0: {} resolve-from@5.0.0: {} resolve-pkg-maps@1.0.0: {} + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + reusify@1.1.0: {} rollup@4.40.2: @@ -2948,10 +3795,31 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + safe-buffer@5.2.1: {} + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + safer-buffer@2.1.2: {} + semver@6.3.1: {} + semver@7.7.1: {} send@1.2.0: @@ -2979,6 +3847,28 @@ snapshots: transitivePeerDependencies: - supports-color + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + setprototypeof@1.2.0: {} shebang-command@2.0.0: @@ -3037,6 +3927,29 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.23.9 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -3063,6 +3976,8 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + synckit@0.11.4: dependencies: '@pkgr/core': 0.2.4 @@ -3121,6 +4036,13 @@ snapshots: v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + tsconfig-paths@4.2.0: dependencies: json5: 2.2.3 @@ -3172,6 +4094,39 @@ snapshots: media-typer: 1.1.0 mime-types: 3.0.1 + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + typescript-eslint@8.32.0(eslint@9.26.0)(typescript@5.8.3): dependencies: '@typescript-eslint/eslint-plugin': 8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0)(typescript@5.8.3))(eslint@9.26.0)(typescript@5.8.3) @@ -3184,6 +4139,13 @@ snapshots: typescript@5.8.3: {} + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + undici-types@6.21.0: {} undici@6.21.1: {} @@ -3206,6 +4168,47 @@ snapshots: tr46: 1.0.1 webidl-conversions: 4.0.2 + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@2.0.2: dependencies: isexe: 2.0.0 diff --git a/src/attach.json b/src/attach.json index ceb170c..47353eb 100755 --- a/src/attach.json +++ b/src/attach.json @@ -3,6 +3,6 @@ "ping": "https://i.ibb.co/2g1CTst/ping.gif", "love": "https://i.ibb.co/NgYxJW1Q/love.gif", "noted": "https://i.ibb.co/n2ZyjCZ/anotado.gif", - "pc_destroyed": "https://i.ibb.co/BK67qMNg/pc-destroy.gif" + "pcDestroyed": "https://i.ibb.co/BK67qMNg/pc-destroy.gif" } } \ No newline at end of file diff --git a/src/bot.ts b/src/bot.ts deleted file mode 100644 index 2224786..0000000 --- a/src/bot.ts +++ /dev/null @@ -1,162 +0,0 @@ -import { execSync } from 'node:child_process' -import fs from 'node:fs' -import path from 'node:path' - -import { - ChatInputCommandInteraction, - Client, - Events, - GatewayIntentBits, - REST, - Routes, - SlashCommandBuilder, -} from 'discord.js' -import { pathToFileURL } from 'url' - -import { env } from './env' -import db from './lib/db' -import { Log } from './utils/log' - -const client = new Client({ intents: [GatewayIntentBits.Guilds] }) - -type Command = { - data: SlashCommandBuilder - execute: (interaction: ChatInputCommandInteraction) => Promise -} - -const commands = new Map() - -/** - * Recursively retrieves all .ts command files from the given directory and its subdirectories. - * Useful for loading slash commands organized in nested folders like /commands/admin/. or /commands/whatever/*.ts - */ -function getAllCommandFiles(dir: string, files: string[] = []): string[] { - const entries = fs.readdirSync(dir, { withFileTypes: true }) - - for (const entry of entries) { - const fullPath = path.join(dir, entry.name) - if (entry.isDirectory()) { - getAllCommandFiles(fullPath, files) - } else if (entry.isFile() && entry.name.endsWith('.ts')) { - files.push(fullPath) - } - } - - return files -} - -async function createBotDatabase() { - const guild = client.guilds.cache.get(env.DISCORD_GUILD_ID) - - if (!guild) { - Log.error( - `❌ Guild com ID ${env.DISCORD_GUILD_ID} não encontrada no cache.`, - ) - return - } - - Log.info(`⚙️ Criando database do servidor ${guild.name}`) - - try { - await db.discordGuild.upsert({ - where: { id: guild.id }, - update: { - name: guild.name, - icon: guild.iconURL() ?? undefined, - }, - - create: { - id: guild.id, - name: guild.name, - icon: guild.iconURL() ?? undefined, - env: { - create: { - initialMoneyValue: 301.0, - }, - }, - }, - }) - - Log.database(`✅ Servidor sincronizado: ${guild.name}`) - } catch (err) { - Log.error(`❌ Erro ao sincronizar servidor ${guild.name}: ${err}`) - } -} - -function applyBotMigrations() { - try { - execSync('npx prisma migrate deploy', { stdio: 'inherit' }) - Log.database('Migrations aplicadas com sucesso.') - } catch (err) { - Log.error(`Erro ao aplicar migrations: ${err}`) - } -} - -async function setupBotDatabase() { - const guildId = env.DISCORD_GUILD_ID - - const exists = await db.discordGuild.findUnique({ - where: { id: guildId }, - }) - - if (exists) { - Log.info('🔁 Servidor já registrado. Aplicando migrations...') - applyBotMigrations() - } else { - Log.info('🆕 Servidor ainda não está no banco. Criando estrutura...') - await createBotDatabase() - } -} - -client.once(Events.ClientReady, async (c) => { - Log.success(`✅ Bot logado como ${c.user.tag}`) - - await setupBotDatabase() - - // loading all commmands in src/commands/ - const commandsPath = path.join(__dirname, 'commands') - const commandFiles = getAllCommandFiles(commandsPath) - - const restCommands = [] - - Log.info('👁️ Lendo todos os slash commands...') - for (const file of commandFiles) { - Log.info(` > ➕ adicionando ${file} à lista de slash commands`) - const filePath = file - const command: Command = (await import(pathToFileURL(filePath).href)) - .default - commands.set(command.data.name, command) - restCommands.push(command.data.toJSON()) - } - - // register these commands - const rest = new REST().setToken(env.DISCORD_TOKEN) - try { - Log.info( - `🔄 Registrando a lista de slash commands ao bot ${c.user.tag}...`, - ) - await rest.put( - Routes.applicationGuildCommands( - env.DISCORD_CLIENT_ID, - env.DISCORD_GUILD_ID, - ), - { body: restCommands }, - ) - Log.success( - `✅ slash commands registrados ao bot ${c.user.tag} com sucesso!`, - ) - } catch (error) { - Log.error(`❌ Erro ao registrar slash commands: ${error}`) - } - - Log.success(`⚙️ ${c.user.tag} iniciado com sucesso!`) -}) - -client.on(Events.InteractionCreate, async (interaction) => { - if (!interaction.isChatInputCommand()) return - - const command = commands.get(interaction.commandName) - if (command) await command.execute(interaction) -}) - -client.login(env.DISCORD_TOKEN) diff --git a/src/commands/discordAdmin/ban.ts b/src/commands/discordAdmin/ban.ts deleted file mode 100644 index a414d3f..0000000 --- a/src/commands/discordAdmin/ban.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { - ChatInputCommandInteraction, - SlashCommandBuilder, - PermissionFlagsBits, - MessageFlags, - EmbedBuilder, -} from 'discord.js' - -export default { - data: new SlashCommandBuilder() - .setName('ban') - .setDescription('Comando para banir alguém') - .addUserOption((option) => - option - .setName('usuario') - .setDescription('Informe o usuário a ser banido') - .setRequired(true), - ) - .addStringOption((option) => - option - .setName('motivo') - .setDescription( - 'Razão pelo qual o usuário foi banido (opcional)', - ) - .setRequired(false), - ) - .setDefaultMemberPermissions(PermissionFlagsBits.BanMembers), - - async execute(interaction: ChatInputCommandInteraction) { - if ( - !interaction.memberPermissions?.has(PermissionFlagsBits.BanMembers) - ) { - return interaction.reply({ - content: 'Você não tem permissão para usar esse comando', - flags: MessageFlags.Ephemeral, - }) - } - - const user = interaction.options.getUser('usuario')! - const reason = - interaction.options.getString('motivo') || 'Motivo não especificado' - - try { - await interaction.guild?.members.ban(user, { reason }) - - await interaction.reply({ - embeds: [ - new EmbedBuilder() - .setTitle('Usuário banido') - .setFields([ - { - name: `👤 Usuário`, - value: `${user.tag}`, - inline: true, - }, - { - name: `🛡️ Moderador`, - value: `${interaction.member?.user.id}`, - inline: true, - }, - { - name: `📜 Motivo`, - value: reason, - inline: false, - }, - ]) - .setDescription(`O usuário ${user.tag} foi banido!`), - ], - }) - } catch (err) { - console.log( - `Náo foi possível banir o usuario ${user}\n Motivo: ${err}`, - ) - await interaction.reply({ - content: 'Erro interno ocorreu, contate o suporte da Codify', - flags: MessageFlags.Ephemeral, - }) - } - }, -} diff --git a/src/commands/discordAdmin/server.ts b/src/commands/discordAdmin/server.ts deleted file mode 100644 index 27d9b52..0000000 --- a/src/commands/discordAdmin/server.ts +++ /dev/null @@ -1,97 +0,0 @@ -// src/commands/server.ts -import { - ChatInputCommandInteraction, - MessageFlags, - PermissionFlagsBits, - SlashCommandBuilder, -} from 'discord.js' - -import db from '@/lib/db' -import { BotColors, createEmbed } from '@/utils/embeds/embedMessages' - -export default { - data: new SlashCommandBuilder() - .setName('server') - .setDescription('Comandos para administrar o servidor.') - .addSubcommand((subcommand) => - subcommand - .setName('env') - .setDescription('Configura variáveis de ambiente do servidor.') - .addStringOption((option) => - option - .setName('key') - .setDescription('Nome da variável') - .setRequired(true), - ) - .addStringOption((option) => - option - .setName('value') - .setDescription('Valor a ser definido') - .setRequired(true), - ), - ), - - async execute(interaction: ChatInputCommandInteraction) { - const sub = interaction.options.getSubcommand() - const guild = interaction.guild - - if (!guild) { - return interaction.reply({ - content: - 'Este comando só pode ser usado dentro de um servidor.', - flags: MessageFlags.Ephemeral, - }) - } - - // /server env key value - if (sub === 'env') { - if ( - !interaction.memberPermissions?.has( - PermissionFlagsBits.ManageMessages, - ) - ) { - return interaction.reply({ - content: - 'Você precisa ser moderador para usar esse comando.', - flags: MessageFlags.Ephemeral, - }) - } - - const key = interaction.options.getString('key', true) - const value = interaction.options.getString('value', true) - - if (key !== 'initialMoneyValue') { - return interaction.reply({ - content: 'Chave de ambiente inválida.', - flags: MessageFlags.Ephemeral, - }) - } else { - try { - const decimal = parseFloat(value) - - await db.discordGuildEnvironment.upsert({ - where: { guildId: guild.id }, - update: { initialMoneyValue: decimal }, - create: { - guildId: guild.id, - initialMoneyValue: decimal, - }, - }) - - const embed = createEmbed({ - title: 'Ambiente Atualizado', - description: `A variável **${key}** foi definida como **${value}** com sucesso!`, - color: BotColors.success, - }) - - await interaction.reply({ embeds: [embed] }) - } catch { - return interaction.reply({ - content: 'Erro ao atualizar variável de ambiente.', - flags: MessageFlags.Ephemeral, - }) - } - } - } - }, -} diff --git a/src/commands/discordUser/register.ts b/src/commands/discordUser/register.ts deleted file mode 100644 index 26497db..0000000 --- a/src/commands/discordUser/register.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - ChatInputCommandInteraction, - MessageFlags, - SlashCommandBuilder, -} from 'discord.js' - -import attach from '@/attach.json' -import db from '@/lib/db' -import { BotColors, createEmbed } from '@/utils/embeds/embedMessages' -import { Log } from '@/utils/log' -import { logCommandUsage } from '@/utils/logCommands' - -export default { - data: new SlashCommandBuilder() - .setName('register') - .setDescription('Register in Codify Bot!'), - - async execute(interaction: ChatInputCommandInteraction) { - logCommandUsage(interaction) - - const { user } = interaction - - try { - const guildId = interaction.guild?.id - if (!guildId) throw new Error('Seu server não foi não encontrado.') - - const env = await db.discordGuildEnvironment.findUnique({ - where: { guildId }, - }) - - if (!env) - throw new Error( - 'Configuracoes do seu server não foram encontradas', - ) - - await db.discordUser.create({ - data: { - id: user.id, - username: user.username, - discriminator: user.discriminator, - avatar: user.avatar, - wallet: env.initialMoneyValue, - }, - }) - - const embed = createEmbed({ - title: '✅ Registrado!', - description: - 'Você foi registrado com sucesso!\nUse seu saldo em carteira como quiser!', - color: BotColors.success, - image: user.displayAvatarURL(), - fields: [ - { - name: '💰 Saldo Inicial', - value: `R$ ${env.initialMoneyValue.toFixed(4)}`, - inline: false, - }, - ], - }) - - await interaction - .reply({ embeds: [embed] }) - .then(() => - Log.info('Mensagem enviada para o comando /register'), - ) - .catch(Log.error) - } catch (err) { - const embed = createEmbed({ - title: 'Deu ruim!', - description: 'você NÃO foi registrado com sucesso!', - color: BotColors.danger, - image: attach.gifs.pc_destroyed, - }) - - Log.error(`Erro ao registrar usuário: ${err}`) - await interaction - .reply({ embeds: [embed], flags: MessageFlags.Ephemeral }) - .then(() => - Log.info( - 'Mensagem de erro enviada para o comando /register', - ), - ) - .catch(Log.error) - } finally { - await db.$disconnect() - } - }, -} diff --git a/src/commands/ping.ts b/src/commands/ping.ts deleted file mode 100644 index 77448b7..0000000 --- a/src/commands/ping.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js' - -import attach from '@/attach.json' -import { BotColors, createEmbed } from '@/utils/embeds/embedMessages' -import { logCommandUsage } from '@/utils/logCommands' - -export default { - data: new SlashCommandBuilder().setName('ping').setDescription('Pong!'), - async execute(interaction: ChatInputCommandInteraction) { - logCommandUsage(interaction) - const embed = createEmbed({ - title: '🏓 Pong!', - description: 'Toma a bolinha de volta ~~(la ele)~~.', - color: BotColors.success, - image: attach.gifs.ping, - }) - - await interaction.reply({ embeds: [embed] }) - }, -} diff --git a/src/commands/recado.ts b/src/commands/recado.ts deleted file mode 100644 index 136d434..0000000 --- a/src/commands/recado.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ChatInputCommandInteraction, SlashCommandBuilder } from 'discord.js' - -import { createEmbed } from '@/utils/embeds/embedMessages' -import { logCommandUsage } from '@/utils/logCommands' - -const respostas = [ - 'vai trabalhar @! v4g4bund0', - 'só atrapalha a vida dos outros ein @', - '@, nem o adm te aguenta mais', - '@, fedido, vá se banhar', - '@, vai te arr0mb4r pra lá doido', - '@, que tal ficar na tua ein?', - '@ vai dar 10zão no pix pro primeiro que marcar o adm e dizer que o ~~m~~ama', -] - -export default { - data: new SlashCommandBuilder() - .setName('recado') - .setDescription('Manda uma mensagem carinhosa pra alguém 😈') - .addUserOption((option) => - option - .setName('user') - .setDescription("Quem vai ser 'carinhosamente tratado bem'?") - .setRequired(true), - ), - - async execute(interaction: ChatInputCommandInteraction) { - logCommandUsage(interaction) - - const targetUser = interaction.options.getUser('user', true) - const frase = respostas[Math.floor(Math.random() * respostas.length)] - - const embed = createEmbed({ - title: 'Recado Secreto ❤️', - description: frase.replace('@', `<@${targetUser.id}>`), - timestamp: true, - }) - - await interaction.reply({ embeds: [embed] }) - }, -} diff --git a/src/env/index.ts b/src/env/index.ts index 3479e24..f9e5863 100644 --- a/src/env/index.ts +++ b/src/env/index.ts @@ -1,8 +1,8 @@ import 'dotenv/config' -import { z } from 'zod' +import z from 'zod' -import { Log } from '@/utils/log' +import { logger } from '@/utils/logger' const envSchema = z.object({ DISCORD_TOKEN: z.string(), @@ -13,8 +13,8 @@ const envSchema = z.object({ const _env = envSchema.safeParse(process.env) if (!_env.success) { - Log.error(`❌ Invalid environment variables: ${_env.error.format()}`) - throw new Error('Invalid environment variables') + logger.error('Invalid environment variables', _env.error.format()) + throw new Error('Invalid environment variables.') } export const env = _env.data diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..cd0e6bb --- /dev/null +++ b/src/index.ts @@ -0,0 +1,6 @@ +import { bootstrap } from './structs/client' + +bootstrap({ + workdir: '../modules', + intents: ['Guilds', 'GuildMessages', 'MessageContent'], +}) diff --git a/src/lib/db.ts b/src/lib/prisma.ts similarity index 50% rename from src/lib/db.ts rename to src/lib/prisma.ts index 87852e9..12af1dd 100644 --- a/src/lib/db.ts +++ b/src/lib/prisma.ts @@ -1,7 +1,7 @@ -import { Log } from '@/utils/log' +import { logger } from '@/utils/logger' import { PrismaClient } from '$/generated/prisma' -const db = new PrismaClient({ +export const prisma = new PrismaClient({ log: [ { emit: 'event', @@ -11,24 +11,15 @@ const db = new PrismaClient({ emit: 'stdout', level: 'error', }, - { - emit: 'stdout', - level: 'info', - }, { emit: 'stdout', level: 'warn', }, ], - errorFormat: 'pretty', }) -db.$on('query', (e) => { - console.log('') - Log.database('Query: ' + e.query + ' in ' + e.duration + 'ms') - Log.database('Params: ' + e.params) - console.log('') +prisma.$on('query', (event) => { + logger.log(`'Query: ${event.query} in ${event.duration}ms'`) + logger.log(`Params: ${event.params}`) }) - -export default db diff --git a/src/modules/events/ready.ts b/src/modules/events/ready.ts new file mode 100644 index 0000000..0876e88 --- /dev/null +++ b/src/modules/events/ready.ts @@ -0,0 +1,11 @@ +import { createEvent } from '@/structs/event' +import { setupDatabase } from '@/utils/database' + +createEvent({ + event: 'ready', + name: 'startupDatabase', + once: true, + async execute(client) { + await setupDatabase(client) + }, +}) diff --git a/src/structs/client.ts b/src/structs/client.ts new file mode 100644 index 0000000..3159118 --- /dev/null +++ b/src/structs/client.ts @@ -0,0 +1,169 @@ +import chalk from 'chalk' +import { + AutocompleteInteraction, + Client, + ClientOptions, + GatewayIntentBits, +} from 'discord.js' +import fs, { PathLike } from 'fs' +import path from 'path' + +import { env } from '@/env' +import { isMessageCommand } from '@/utils/isMessageCommand' +import { logger } from '@/utils/logger' + +import { registerEventHandlers } from './event' +import { handleMessageCommand } from './messageCommand' +import { handleSlashCommand } from './slashCommand' +import { storage } from './storage' + +interface BootstrapOptions extends Partial { + workdir: PathLike +} + +/** + * @description This function bootstraps a Discord client with the specified options. + * @param {BootstrapOptions} options - The options for bootstrapping the client. + * @returns {{ client: Client }} - The created Discord client. + */ +export function bootstrap(options: BootstrapOptions): { client: Client } { + const client = createClient(env.DISCORD_TOKEN, options) + + loadModules(options.workdir) + registerEventHandlers(client) + + client.login() + + return { client } +} + +/** + * @description This function creates a Discord client with the specified token and options. + * @param {string} token - The Discord bot token. + * @param {BootstrapOptions} options - The options for creating the client. + * @returns {Client} - The created Discord client. + */ +function createClient(token: string, options: BootstrapOptions): Client { + const client = new Client({ + intents: options.intents ?? [GatewayIntentBits.Guilds], + partials: options.partials ?? [], + }) + client.token = token + + client.once('ready', async (client) => { + logger.success(`Logged in as ${client.user?.tag}`) + await registerSlashCommands(client) + }) + + client.on('interactionCreate', async (interaction) => { + switch (true) { + case interaction.isCommand(): + await handleSlashCommand(interaction) + return + case interaction.isAutocomplete(): + await handleAutocomplete(interaction) + return + } + }) + + client.on('messageCreate', async (message) => { + if (!isMessageCommand(message)) return + await handleMessageCommand(message) + }) + + return client +} + +/** + * @description This function handles autocomplete interactions. + * @param {AutocompleteInteraction} interaction - The interaction object. + */ +async function handleAutocomplete(interaction: AutocompleteInteraction) { + const autocompleteCommand = storage.slashCommands.get( + interaction.commandName, + ) + if (autocompleteCommand && autocompleteCommand.autocomplete) { + const choices = await autocompleteCommand.autocomplete(interaction) + if (choices && Array.isArray(choices)) { + interaction.respond(choices.slice(0, 25)) + } + } +} + +/** + * @description This function loads modules from the specified directory. + * @param {PathLike} workdir - The directory to load modules from. + */ +function loadModules(workdir: PathLike) { + const modulesPath = path.resolve(__dirname, workdir.toString()) + + function readAllFilesRecursively(dir: string): string[] { + const entries = fs.readdirSync(dir, { withFileTypes: true }) + + return entries.flatMap((entry) => { + const fullPath = path.join(dir, entry.name) + if (entry.isDirectory()) { + return readAllFilesRecursively(fullPath) + } else if (entry.isFile() && /\.(t|j)s$/.test(entry.name)) { + return [fullPath] + } else { + return [] + } + }) + } + + const files = readAllFilesRecursively(modulesPath) + logger.log(`Loading ${files.length} modules...`) + + files.forEach((file, index) => { + const shortPath = file.replace(modulesPath, '').replace(/^[\\/]/, '') + try { + require(file) + logger.success( + `[${index + 1}/${files.length}] Module loaded: ${chalk.blue(shortPath)}`, + ) + } catch (error) { + logger.error( + `[${index + 1}/${files.length}] Failed to load module: ${chalk.red(shortPath)}`, + error, + ) + } + }) +} + +/** + * @description This function registers slash commands in the specified guild. + * @param {Client} client - The Discord client. + */ +async function registerSlashCommands(client: Client) { + function plural(size: number) { + return size === 1 ? '' : 's' + } + + const guild = client.guilds.cache.get(env.DISCORD_GUILD_ID) + if (!guild) return logger.error('Guild not found') + + logger.log(`Registering slash commands in ${guild.name} guild:`) + const guildCommands = storage.slashCommands.map( + (slashCommand) => slashCommand, + ) + + if (guildCommands.length === 0) { + logger.warn('No slash commands to register') + return + } + + await guild.commands + .set(guildCommands) + .then((commands) => { + logger.success( + `└ {/} [${commands.size}] command${plural(commands.size)} registered in ${guild.name} guild successfully!`, + ) + }) + .catch((error) => { + logger.error( + `Failed to register {/} commands in ${guild.name} guild`, + error, + ) + }) +} diff --git a/src/structs/event.ts b/src/structs/event.ts new file mode 100644 index 0000000..4b84a92 --- /dev/null +++ b/src/structs/event.ts @@ -0,0 +1,64 @@ +import chalk from 'chalk' +import { Client, ClientEvents, Collection } from 'discord.js' + +import { logger } from '@/utils/logger' + +import { storage } from './storage' + +export interface EventData { + name: string + event: EventName + once?: boolean + execute(...args: ClientEvents[EventName]): Promise +} + +type GenericEventData = EventData +export type EventsCollection = Collection + +type GenericEventHandler = { + execute: (...args: any[]) => Promise +} + +/** + * @description This function registers event handlers for the client. + * @param {Client} client - The Discord client. + */ +export function registerEventHandlers(client: Client) { + const eventHandlers = storage.events.map((collection, event) => ({ + event, + handlers: collection.map((e) => ({ execute: e.execute, once: e.once })), + })) + + for (const { event, handlers } of eventHandlers) { + const onEventHandlers = handlers.filter((e) => !e.once) + const onceEventHandlers = handlers.filter((e) => e.once) + + const registerHandlers = (handlers: GenericEventHandler[]) => { + return async (...args: ClientEvents[typeof event]) => { + for (const handler of handlers) { + await handler.execute(...args) + } + } + } + + client.on(event, registerHandlers(onEventHandlers)) + client.once(event, registerHandlers(onceEventHandlers)) + } +} + +/** + * @description This function creates an event. + * @param {EventData} data - The event data. + */ +export function createEvent( + data: EventData, +) { + const eventCollection = storage.events.get(data.event) ?? new Collection() + + eventCollection.set(data.name, data) + storage.events.set(data.event, eventCollection) + + logger.log( + `{⋆} ${data.name} event registered ${chalk.blue(`(${data.event})`)}`, + ) +} diff --git a/src/structs/messageCommand.ts b/src/structs/messageCommand.ts new file mode 100644 index 0000000..c8390c9 --- /dev/null +++ b/src/structs/messageCommand.ts @@ -0,0 +1,44 @@ +import { Message, OmitPartialGroupDMChannel } from 'discord.js' + +import { getMessageCommandName } from '@/utils/getMessageCommandName' +import { logger } from '@/utils/logger' + +import { storage } from './storage' + +type CommandName = N + +export type MessageCommandData = { + name: CommandName + execute(message: OmitPartialGroupDMChannel): Promise +} + +/** + * @description This function registers a message command. + * @param {MessageCommandData} data - The message command data. + */ +export function createMessageCommand(data: MessageCommandData) { + storage.messageCommands.set(data.name, data) + logger.log(`{#} ${data.name} command registered`) +} + +/** + * @description This function handles message commands. + * @param {OmitPartialGroupDMChannel>} message - The message object. + */ +export async function handleMessageCommand( + message: OmitPartialGroupDMChannel>, +) { + const messageCommandName = getMessageCommandName(message) + const messageCommand = storage.messageCommands.get(messageCommandName) + if (!messageCommand) return await message.reply('Command not found') + + try { + await messageCommand.execute(message) + } catch (error) { + logger.error( + `Error executing message command: ${message.content}`, + error, + ) + await message.reply('An error occurred while executing the command.') + } +} diff --git a/src/structs/slashCommand.ts b/src/structs/slashCommand.ts new file mode 100644 index 0000000..447bb50 --- /dev/null +++ b/src/structs/slashCommand.ts @@ -0,0 +1,92 @@ +import { + ApplicationCommandOptionChoiceData, + ApplicationCommandType, + AutocompleteInteraction, + CacheType, + ChatInputApplicationCommandData, + ChatInputCommandInteraction, + CommandInteraction, + MessageFlags, +} from 'discord.js' + +import { logger } from '@/utils/logger' + +import { storage } from './storage' + +type AutocompleteReturn = Promise< + void | undefined | readonly ApplicationCommandOptionChoiceData[] +> + +export type CommandType = ApplicationCommandType.ChatInput +type Cache = D extends false ? 'cached' : CacheType + +type SlashName = N + +type ApplicationCommandData< + N extends string, + D extends boolean, + T extends CommandType, +> = T extends ApplicationCommandType.ChatInput + ? ChatInputApplicationCommandData & { + name: SlashName + execute( + interaction: ChatInputCommandInteraction>, + ): Promise + autocomplete?( + interaction: AutocompleteInteraction>, + ): AutocompleteReturn + } + : never + +export type SlashCommandData< + Name extends string, + DmPermission extends boolean, + Type extends CommandType, +> = ApplicationCommandData & { + type?: Type + dmPermission?: DmPermission +} + +export type GenericSlashCommandData = SlashCommandData + +/** + * @description This function registers a slash command. + * @param {SlashCommandData} data - The slash command data. + */ +export function createSlashCommand< + Name extends string = string, + DmPermission extends boolean = false, + Type extends CommandType = ApplicationCommandType.ChatInput, +>(data: SlashCommandData) { + data.type ??= ApplicationCommandType.ChatInput as Type + data.dmPermission ??= false as DmPermission + + storage.slashCommands.set(data.name, data) + logger.log(`{/} ${data.name} command registered`) +} + +/** + * @description This function handles slash commands. + * @param {CommandInteraction} interaction - The interaction object. + */ +export async function handleSlashCommand(interaction: CommandInteraction) { + const slashCommand = storage.slashCommands.get(interaction.commandName) + if (!slashCommand) + return await interaction.reply({ + content: 'Command not found', + flags: MessageFlags.Ephemeral, + }) + + try { + await slashCommand.execute(interaction as ChatInputCommandInteraction) + } catch (error) { + logger.error( + `Error executing command: ${interaction.commandName}`, + error, + ) + await interaction.reply({ + content: 'An error occurred while executing the command.', + flags: MessageFlags.Ephemeral, + }) + } +} diff --git a/src/structs/storage.ts b/src/structs/storage.ts new file mode 100644 index 0000000..1ddd147 --- /dev/null +++ b/src/structs/storage.ts @@ -0,0 +1,19 @@ +import { ClientEvents, Collection } from 'discord.js' + +import { EventsCollection } from './event' +import { MessageCommandData } from './messageCommand' +import { GenericSlashCommandData } from './slashCommand' + +/** + * @description This object stores collections of commands and events. + * It contains: + * - commands: A collection of slash commands. + * - messageCommands: A collection of message commands. + * - events: A collection of events. + */ +export const storage = { + slashCommands: new Collection(), + messageCommands: new Collection(), + events: new Collection(), + prefix: '!', +} diff --git a/src/utils/database.ts b/src/utils/database.ts new file mode 100644 index 0000000..811c8d4 --- /dev/null +++ b/src/utils/database.ts @@ -0,0 +1,70 @@ +import { execSync } from 'node:child_process' + +import { Client } from 'discord.js' + +import { env } from '@/env' +import { prisma } from '@/lib/prisma' + +import { logger } from './logger' + +async function createDatabase(client: Client) { + const guild = client.guilds.cache.get(env.DISCORD_GUILD_ID) + if (!guild) { + logger.error( + `Guild with ID ${env.DISCORD_GUILD_ID} not found in cache.`, + ) + return + } + + logger.log(`⚙️ Creating database for guild ${guild.name}`) + try { + await prisma.discordGuild.upsert({ + where: { id: guild.id }, + update: { + name: guild.name, + icon: guild.iconURL() ?? undefined, + }, + + create: { + id: guild.id, + name: guild.name, + icon: guild.iconURL() ?? undefined, + env: { + create: { + initialMoneyValue: 301.0, + }, + }, + }, + }) + + logger.success(`Guild successfully synced: ${guild.name}`) + } catch (err) { + logger.error(`Failed to sync guild ${guild.name}:`, err) + } +} + +function applyMigrations() { + try { + execSync('npx prisma migrate deploy', { stdio: 'inherit' }) + logger.success('Migrations applied successfully.') + } catch (err) { + logger.error('Error while applying migrations:', err) + } +} + +export async function setupDatabase(client: Client) { + const guildId = env.DISCORD_GUILD_ID + + const exists = await prisma.discordGuild.findUnique({ + where: { id: guildId }, + }) + + if (exists) { + logger.log('Guild already registered. Applying migrations...') + applyMigrations() + return + } + + logger.log('Guild not found in the database. Creating structure...') + await createDatabase(client) +} diff --git a/src/utils/embed.ts b/src/utils/embed.ts new file mode 100644 index 0000000..794059b --- /dev/null +++ b/src/utils/embed.ts @@ -0,0 +1,33 @@ +import { Colors, EmbedBuilder } from 'discord.js' + +import { EmbedOptions } from './utils.types' + +export const BotColors = { + primary: Colors.Blurple, + success: Colors.Green, + warning: Colors.Yellow, + danger: Colors.Red, + info: Colors.Blue, + codify: '#9146FF' as const, +} + +export function createEmbed(options: EmbedOptions): EmbedBuilder { + const embed = new EmbedBuilder() + + if (options.author) embed.setAuthor(options.author) + if (options.title) embed.setTitle(options.title) + if (options.url) embed.setURL(options.url) + if (options.description) embed.setDescription(options.description) + if (options.fields) embed.addFields(options.fields) + if (options.image) embed.setImage(options.image) + if (options.thumbnail) embed.setThumbnail(options.thumbnail) + if (options.timestamp) embed.setTimestamp() + + embed.setColor(options.color || BotColors.codify) + embed.setFooter({ + text: options.footer?.text || 'by Codify', + iconURL: options.footer?.iconURL, + }) + + return embed +} diff --git a/src/utils/embeds/embedMessages.ts b/src/utils/embeds/embedMessages.ts deleted file mode 100644 index ff433e3..0000000 --- a/src/utils/embeds/embedMessages.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Colors, EmbedBuilder } from 'discord.js' - -import { EmbedOptions } from './embed.types' - -export const BotColors = { - primary: Colors.Blurple, - success: Colors.Green, - warning: Colors.Yellow, - danger: Colors.Red, - info: Colors.Blue, - codify: '#9146FF' as const, -} - -export function createEmbed(options: EmbedOptions): EmbedBuilder { - const embed = new EmbedBuilder() - - if (options.author) { - embed.setAuthor(options.author) - } - - if (options.title) { - embed.setTitle(options.title) - } - - if (options.url) { - embed.setURL(options.url) - } - - if (options.description) { - embed.setDescription(options.description) - } - - if (options.fields) { - embed.addFields(options.fields) - } - - if (options.image) { - embed.setImage(options.image) - } - - if (options.thumbnail) { - embed.setThumbnail(options.thumbnail) - } - - embed.setColor(options.color || BotColors.codify) - - embed.setFooter({ - text: options.footer?.text || 'by Codify', - iconURL: options.footer?.iconURL, - }) - - if (options.timestamp) { - embed.setTimestamp() - } - - return embed -} diff --git a/src/utils/getMessageCommandName.ts b/src/utils/getMessageCommandName.ts new file mode 100644 index 0000000..f8cb490 --- /dev/null +++ b/src/utils/getMessageCommandName.ts @@ -0,0 +1,15 @@ +import { Message, OmitPartialGroupDMChannel } from 'discord.js' + +import { storage } from '@/structs/storage' + +/** + * @description This function checks if a message is a command. + * @param {OmitPartialGroupDMChannel>} message - The message object. + * @returns {boolean} - Returns true if the message is a command, false otherwise. + */ +export function getMessageCommandName( + message: OmitPartialGroupDMChannel>, +): string { + const commandNameWithPrefix = message.content.split(' ')[0] + return commandNameWithPrefix.replace(storage.prefix, '') +} diff --git a/src/utils/isMessageCommand.ts b/src/utils/isMessageCommand.ts new file mode 100644 index 0000000..da389e5 --- /dev/null +++ b/src/utils/isMessageCommand.ts @@ -0,0 +1,19 @@ +import { Message, OmitPartialGroupDMChannel } from 'discord.js' + +import { storage } from '@/structs/storage' + +/** + * @description This function checks if a message is a command. + * @param {OmitPartialGroupDMChannel>} message - The message object. + * @returns {boolean} - Returns true if the message is a command, false otherwise. + */ +export function isMessageCommand( + message: OmitPartialGroupDMChannel>, +): boolean { + if (message.author.bot) return false + + const commandNameWithPrefix = message.content.split(' ')[0] + if (!commandNameWithPrefix.startsWith(storage.prefix)) return false + + return true +} diff --git a/src/utils/log.ts b/src/utils/log.ts deleted file mode 100644 index 590bb24..0000000 --- a/src/utils/log.ts +++ /dev/null @@ -1,43 +0,0 @@ -import chalk from 'chalk' - -export const Log = { - info(message: string, useColor: boolean = true) { - if (useColor) { - console.log(`${chalk.cyanBright('[INFO]')} ${chalk.cyan(message)}`) - } else { - console.log(`[INFO] ${message}`) - } - }, - - warn(message: string, useColor: boolean = true) { - if (useColor) { - console.warn( - `${chalk.yellowBright('[WARN]')} ${chalk.yellow(message)}`, - ) - } else { - console.warn(`[WARN] ${message}`) - } - }, - - error(message: string, useColor: boolean = true) { - if (useColor) { - console.error(`${chalk.redBright('[ERROR]')} ${chalk.red(message)}`) - } else { - console.error(`[ERROR] ${message}`) - } - }, - - success(message: string, useColor: boolean = true) { - if (useColor) { - console.log( - `${chalk.greenBright('[SUCCESS]')} ${chalk.green(message)}`, - ) - } else { - console.log(`[SUCCESS] ${message}`) - } - }, - - database(message: string) { - console.log(`${chalk.magentaBright('[DATABASE]')} ${message}`) - }, -} diff --git a/src/utils/logCommands.ts b/src/utils/logCommands.ts deleted file mode 100644 index 45facf5..0000000 --- a/src/utils/logCommands.ts +++ /dev/null @@ -1,19 +0,0 @@ -import chalk from 'chalk' -import { ChatInputCommandInteraction, TextChannel } from 'discord.js' - -import { Log } from './log' - -export function logCommandUsage(interaction: ChatInputCommandInteraction) { - const user = interaction.user.tag - const server = interaction.guild?.name || 'DM' - const channel = - interaction.channel?.type === 0 || - interaction.channel?.type === 5 || - interaction.channel?.type === 11 - ? (interaction.channel as TextChannel).name - : 'Canal privado ou sem nome' - const command = interaction.commandName - - const logMessage = `${chalk.hex('#ff69b4')(`[${server}]`)} ${chalk.green(`#${channel}`)} - ${chalk.yellow(`@${user}`)} executou ${chalk.blue(`/${command}`)}` - Log.info(logMessage, false) -} diff --git a/src/utils/logger.ts b/src/utils/logger.ts new file mode 100644 index 0000000..dadc4b2 --- /dev/null +++ b/src/utils/logger.ts @@ -0,0 +1,31 @@ +import chalk from 'chalk' + +type LogArgs = [message: string, ...params: any[]] + +function log(...args: LogArgs) { + return console.log(chalk.gray(`• [LOG]:`), ...args) +} + +function success(...args: LogArgs) { + return console.log(chalk.green(`✓ [SUCCESS]:`), ...args) +} + +function warn(...args: LogArgs) { + return console.warn(chalk.yellow(`▲ [WARN]:`), ...args) +} + +function error(...args: LogArgs) { + return console.error(chalk.red(`✖︎ [ERROR]:`), ...args) +} + +function debug(...args: LogArgs) { + return console.debug(chalk.blue(`➤ [DEBUG]:`), ...args) +} + +export const logger = { + log, + success, + warn, + error, + debug, +} diff --git a/src/utils/embeds/embed.types.ts b/src/utils/utils.types.ts similarity index 100% rename from src/utils/embeds/embed.types.ts rename to src/utils/utils.types.ts