diff --git a/.github/workflows/build-dev.yml b/.github/workflows/build-dev.yml index 8c0e35c..951464b 100644 --- a/.github/workflows/build-dev.yml +++ b/.github/workflows/build-dev.yml @@ -50,7 +50,7 @@ jobs: uses: docker/build-push-action@v3 with: context: . - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 push: true tags: | remnawave/node:dev diff --git a/.eslintrc.js b/.old.eslintrc.js similarity index 100% rename from .eslintrc.js rename to .old.eslintrc.js diff --git a/Dockerfile b/Dockerfile index 69208ba..da755ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,7 @@ RUN apk add --no-cache \ unzip \ bash \ supervisor \ - && curl -L https://raw.githubusercontent.com/remnawave/scripts/main/scripts/install-latest-xray.sh | bash -s -- v25.2.21 \ + && curl -L https://raw.githubusercontent.com/remnawave/scripts/main/scripts/install-latest-xray.sh | bash -s -- v25.3.6 \ && apk del curl COPY supervisord.conf /etc/supervisord.conf diff --git a/Dockerfile.dev b/Dockerfile.dev index 56b3f1d..3d2b263 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -10,15 +10,15 @@ RUN apt-get update && apt-get install -y \ ENV NVM_DIR=/root/.nvm RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash \ && . $NVM_DIR/nvm.sh \ - && nvm install v22.12.0 \ - && nvm alias default v22.12.0 \ + && nvm install v22.14.0 \ + && nvm alias default v22.14.0 \ && nvm use default -ENV PATH="/root/.nvm/versions/node/v22.12.0/bin:${PATH}" +ENV PATH="/root/.nvm/versions/node/v22.14.0/bin:${PATH}" # Установка Xray -RUN curl -L https://raw.githubusercontent.com/remnawave/scripts/main/scripts/install-latest-xray.sh | bash -s -- v25.2.21 +RUN curl -L https://raw.githubusercontent.com/remnawave/scripts/main/scripts/install-latest-xray.sh | bash -s -- v25.3.6 RUN mkdir -p /var/log/supervisor /var/lib/rnode/xray /app \ diff --git a/docker-compose-prod.yml b/docker-compose-prod.yml index cecf0ad..2dc97f6 100644 --- a/docker-compose-prod.yml +++ b/docker-compose-prod.yml @@ -6,3 +6,4 @@ services: env_file: - .env network_mode: host + restart: always diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..2f9fd90 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,163 @@ +import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin'; +import perfectionist from 'eslint-plugin-perfectionist'; +import tsParser from '@typescript-eslint/parser'; +import { FlatCompat } from '@eslint/eslintrc'; +import { fileURLToPath } from 'node:url'; +import paths from 'eslint-plugin-paths'; +import globals from 'globals'; +import path from 'node:path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +export default [ + { + ignores: ['**/.eslintrc.js', 'prisma/**/*', '.hygen.js', '.hygen/**/*'], + }, + ...compat.extends('plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'), + perfectionist.configs['recommended-alphabetical'], + { + plugins: { + '@typescript-eslint': typescriptEslintEslintPlugin, + paths, + }, + + languageOptions: { + globals: { + ...globals.node, + }, + + parser: tsParser, + ecmaVersion: 'latest', + sourceType: 'commonjs', + + parserOptions: { + project: 'tsconfig.json', + tsconfigRootDir: __dirname, + }, + }, + + rules: { + 'perfectionist/sort-imports': [ + 'error', + { + type: 'line-length', + order: 'desc', + ignoreCase: true, + specialCharacters: 'keep', + internalPattern: ['^~/.+'], + tsconfigRootDir: '.', + partitionByComment: false, + partitionByNewLine: false, + newlinesBetween: 'always', + maxLineLength: undefined, + tsconfigRootDir: __dirname, + + groups: [ + 'type', + ['builtin', 'external'], + 'internal-type', + 'internal', + 'nestJs', + 'remnawave', + 'aliasCommon', + { newlinesBetween: 'never' }, + 'aliasLibs', + 'aliasIntegrationModules', + 'aliasModules', + 'aliasScheduler', + 'aliasQueue', + ['parent-type', 'sibling-type', 'index-type'], + ['parent', 'sibling', 'index'], + 'object', + 'unknown', + ], + + customGroups: { + value: { + aliasModules: '@modules/*.', + aliasCommon: '@common/*.', + aliasLibs: '@libs/*.', + aliasIntegrationModules: '@integration-modules/*.', + aliasScheduler: '@scheduler/*.', + aliasQueue: '@queue/*.', + remnawave: '@remnawave/*.', + nestJs: '@nestjs/*.', + }, + }, + + environment: 'node', + }, + ], + 'perfectionist/sort-decorators': [ + 'error', + { + groups: [ + 'unknown', + 'httpCodes', + 'filters', + 'guards', + 'controllers', + 'nestJSMethods', + ], + + customGroups: { + httpCodes: ['HttpCode'], + filters: ['UseFilters'], + guards: ['UseGuards'], + controllers: ['Controller'], + nestJSMethods: ['Post', 'Get', 'Put', 'Delete', 'Patch', 'Options', 'Head'], + }, + }, + ], + + 'perfectionist/sort-objects': ['off'], + 'perfectionist/sort-classes': ['off'], + 'perfectionist/sort-switch-case': ['off'], + 'perfectionist/sort-object-types': ['off'], + 'perfectionist/sort-interfaces': ['off'], + 'perfectionist/sort-union-types': ['off'], + 'perfectionist/sort-named-imports': ['off'], + 'perfectionist/sort-modules': ['off'], + 'paths/alias': 'error', + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-namespace': 'off', + 'linebreak-style': 0, + 'no-console': 'warn', + + 'prettier/prettier': [ + 'error', + { + bracketSpacing: true, + tabWidth: 4, + printWidth: 100, + singleQuote: true, + trailingComma: 'all', + + overrides: [ + { + files: ['*.js', '*.jsx', '*.ts', '*.tsx'], + + options: { + parser: 'typescript', + }, + }, + { + files: ['*.md', '*.json', '*.yaml', '*.yml'], + + options: { + tabWidth: 2, + }, + }, + ], + }, + ], + }, + }, +]; diff --git a/libs/contract/commands/handler/remove-user.command.ts b/libs/contract/commands/handler/remove-user.command.ts index 3dde832..f6dfbdb 100644 --- a/libs/contract/commands/handler/remove-user.command.ts +++ b/libs/contract/commands/handler/remove-user.command.ts @@ -6,7 +6,6 @@ export namespace RemoveUserCommand { export const url = REST_API.HANDLER.REMOVE_USER; export const RequestSchema = z.object({ - tags: z.array(z.string()), username: z.string(), }); diff --git a/libs/contract/constants/xray/stats.ts b/libs/contract/constants/xray/stats.ts index 1da0e46..ee81217 100644 --- a/libs/contract/constants/xray/stats.ts +++ b/libs/contract/constants/xray/stats.ts @@ -22,7 +22,8 @@ export const XRAY_DEFAULT_STATS_MODEL = { export const XRAY_DEFAULT_API_MODEL = { api: { services: ['HandlerService', 'StatsService', 'RoutingService'], - tag: 'api', + listen: '127.0.0.1:61000', + tag: 'REMNAWAVE_API', }, } as const; diff --git a/libs/contract/package.json b/libs/contract/package.json index 2edcaa9..cfc0f1e 100644 --- a/libs/contract/package.json +++ b/libs/contract/package.json @@ -1,6 +1,6 @@ { "name": "@remnawave/node-contract", - "version": "0.4.1", + "version": "0.5.0", "description": "A node-contract library for Remnawave Panel", "main": "build/index.js", "types": "build/index.d.ts", diff --git a/package-lock.json b/package-lock.json index 5f3d58b..9e68885 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,69 +1,74 @@ { "name": "@remnawave/node", - "version": "1.4.0", + "version": "1.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@remnawave/node", - "version": "1.4.0", + "version": "1.5.0", "license": "AGPL-3.0-only", "dependencies": { "@cjs-exporter/execa": "9.5.2", - "@nestjs/common": "11.0.11", - "@nestjs/config": "4.0.1", - "@nestjs/core": "11.0.11", + "@nestjs/common": "11.0.12", + "@nestjs/config": "4.0.2", + "@nestjs/core": "11.0.12", "@nestjs/jwt": "11.0.0", "@nestjs/passport": "11.0.5", - "@nestjs/platform-express": "11.0.11", - "@remnawave/xtls-sdk": "0.2.0", + "@nestjs/platform-express": "11.0.12", + "@remnawave/supervisord-nestjs": "0.1.1", + "@remnawave/xtls-sdk": "0.3.0", "@remnawave/xtls-sdk-nestjs": "0.2.2", - "enhanced-ms": "^3.0.0", - "helmet": "^7.1.0", - "husky": "9.0.11", + "enhanced-ms": "^4.1.0", + "helmet": "^8.1.0", + "husky": "9.1.7", "morgan": "^1.10.0", + "nanoid": "^5.1.5", "nest-winston": "^1.10.2", - "nestjs-zod": "3.0.0", + "nestjs-zod": "4.3.1", "node-object-hash": "^3.1.1", + "node-supervisord": "^1.0.6-rc.2", "object-hash": "^3.0.0", + "p-retry": "^6.2.1", "passport": "0.7.0", "passport-jwt": "4.0.1", - "pretty-bytes": "^5.6.0", + "pkg-types": "^2.1.0", + "pretty-bytes": "^6.1.1", "reflect-metadata": "0.2.2", "rxjs": "7.8.2", - "semver": "^7.6.3", - "systeminformation": "^5.25.5", + "selfsigned": "^2.4.1", + "semver": "^7.7.1", + "systeminformation": "^5.25.11", "table": "^6.9.0", "winston": "^3.17.0", - "zod": "^3.22.4" + "zod": "^3.24.2" }, "devDependencies": { "@nestjs/cli": "11.0.5", "@nestjs/schematics": "11.0.2", - "@types/bcryptjs": "^2.4.6", - "@types/express": "^5.0.0", + "@types/express": "^5.0.1", "@types/js-yaml": "^4.0.9", - "@types/jsonwebtoken": "^9.0.7", + "@types/jsonwebtoken": "^9.0.9", "@types/mjml": "^4.7.4", "@types/morgan": "^1.9.9", - "@types/node": "^22.13.9", + "@types/node": "^22.13.14", "@types/nunjucks": "^3.2.6", "@types/object-hash": "^3.0.6", "@types/passport-jwt": "^4.0.1", - "@types/semver": "^7.5.8", - "@typescript-eslint/eslint-plugin": "8.18.1", - "@typescript-eslint/parser": "8.18.1", - "eslint": "8.57.1", - "eslint-config-prettier": "^9.0.0", + "@types/semver": "^7.7.0", + "@typescript-eslint/eslint-plugin": "8.28.0", + "@typescript-eslint/parser": "8.28.0", + "eslint": "9.23.0", + "eslint-config-prettier": "^10.1.1", "eslint-plugin-paths": "^1.1.0", - "eslint-plugin-perfectionist": "^4.4.0", - "eslint-plugin-prettier": "^5.0.0", - "prettier": "^3.0.0", + "eslint-plugin-perfectionist": "^4.10.1", + "eslint-plugin-prettier": "^5.2.5", + "prettier": "^3.5.3", "source-map-support": "^0.5.21", - "ts-loader": "9.5.1", + "ts-loader": "9.5.2", "ts-node": "10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "5.7.2" + "typescript": "~5.8.2" } }, "node_modules/@angular-devkit/core": { @@ -285,17 +290,79 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.2.tgz", + "integrity": "sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.0.tgz", + "integrity": "sha512-yJLLmLexii32mGrhW29qvU3QBVTu0GUmEf/J4XsBtVhp4JkIUFN/BjWqTF63yRvGApIDpZm5fa97LtYtINmfeQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -303,7 +370,7 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -358,13 +425,37 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.23.0.tgz", + "integrity": "sha512-35MJ8vCPU0ZMxo7zfev2pypqTwWTofFZO6m4KAtdoFhRpLJUpHTZZ+KB3C7Hb1d7bULYwO4lJXGCi5Se+8OMbw==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz", + "integrity": "sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.12.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@grpc/grpc-js": { @@ -398,44 +489,42 @@ "node": ">=6" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "Apache-2.0", "engines": { - "node": "*" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/module-importer": { @@ -452,13 +541,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@inquirer/checkbox": { "version": "4.1.2", @@ -986,6 +1081,32 @@ "node": ">=8" } }, + "node_modules/@nest-zod/z": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nest-zod/z/-/z-2.0.0.tgz", + "integrity": "sha512-OqmJUZlpcx9ECzPYSIjaR/q/xLKrm9FkV+0FIWLEb9MVc9YeP21GmnQJBxE1dPRlLJ1kybNFBlt4D/PB8YAPkA==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^10.0.0 || ^11.0.0", + "@nestjs/core": "^10.0.0 || ^11.0.0", + "@nestjs/swagger": "^7.4.2 || ^8.0.0 || ^11.0.0", + "zod": ">= 3.14.3" + }, + "peerDependenciesMeta": { + "@nestjs/common": { + "optional": true + }, + "@nestjs/core": { + "optional": true + }, + "@nestjs/swagger": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, "node_modules/@nestjs/cli": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.5.tgz", @@ -1160,9 +1281,9 @@ } }, "node_modules/@nestjs/common": { - "version": "11.0.11", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.0.11.tgz", - "integrity": "sha512-b3zYiho5/XGCnLa7W2hHv5ecSBR1huQrXCHu6pxd+g2HY2B7sKP5CXHMv4gHYqpIqu4ClOb7Q4tLKXMp9LyLUg==", + "version": "11.0.12", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.0.12.tgz", + "integrity": "sha512-6PXxmDe2iYmb57xacnxzpW1NAxRZ7Gf+acMT7/hmRB/4KpZiFU/cNvLWwgbM2BL5QSzQulOwY6ny5bbKnPpB+A==", "license": "MIT", "dependencies": { "iterare": "1.2.1", @@ -1189,9 +1310,9 @@ } }, "node_modules/@nestjs/config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.1.tgz", - "integrity": "sha512-0hr6lKS//Wf8A6VcV69ts8uD0fke6jtmmmXSxzvwAzOM/HEXEKYEp21nRU+cpYxlYqm7Khb0oTOoVuDGk+AWUw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-4.0.2.tgz", + "integrity": "sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==", "license": "MIT", "dependencies": { "dotenv": "16.4.7", @@ -1204,9 +1325,9 @@ } }, "node_modules/@nestjs/core": { - "version": "11.0.11", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.0.11.tgz", - "integrity": "sha512-jMH3jrjrPiaGrkQ5hANNcgDWN+j+hcM5GMQ3jSs4vOWNs3lmKHTVR11wJ9y5tTNnwKydzMogeju0VTUdfXDI5Q==", + "version": "11.0.12", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-11.0.12.tgz", + "integrity": "sha512-micQrbh9iL0PuYVx2vsUojuNmMUyqoMCuj7eGAUhvjiZUh4DBLPdxYmJEayCT/equHSiw9vNC95Vm0JigVZ44g==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -1257,6 +1378,15 @@ "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0" } }, + "node_modules/@nestjs/jwt/node_modules/@types/jsonwebtoken": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz", + "integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@nestjs/passport": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz", @@ -1268,9 +1398,9 @@ } }, "node_modules/@nestjs/platform-express": { - "version": "11.0.11", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.0.11.tgz", - "integrity": "sha512-iv6nH66i/RuRQufg5UUboQ4jQX4NuuePrYQpHB3ueiEIhJm2yLhhNYM6Y2l/76y9woW2eckbiqbzmW/JajAgeQ==", + "version": "11.0.12", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-11.0.12.tgz", + "integrity": "sha512-Jze6dY1q1BBAjFuPQT9CLjYFl5IxMSQQxD+xs6cV+4EIysHxgSFZMJqiTpknZTFgPneyp0zF1TtQAjxBshnwlg==", "license": "MIT", "dependencies": { "cors": "2.8.5", @@ -1417,9 +1547,9 @@ } }, "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.0.tgz", + "integrity": "sha512-vsJDAkYR6qCPu+ioGScGiMYR7LvZYIXh/dlQeviqoTWNCVfKTLYD/LkNWH4Mxsv2a5vpIRc77FN5DnmK1eBggQ==", "dev": true, "license": "MIT", "engines": { @@ -1493,10 +1623,23 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "license": "BSD-3-Clause" }, + "node_modules/@remnawave/supervisord-nestjs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@remnawave/supervisord-nestjs/-/supervisord-nestjs-0.1.1.tgz", + "integrity": "sha512-y+ek9xXIeQ4/kH/yg7/iDb6nvPNTqNI8l1E1uYUhBK/1dDhWo9Q7vpDuPwALKOhdUhotnm0yGPWVh0EoMTnqJw==", + "license": "AGPL-3.0-only", + "dependencies": { + "@nestjs/common": "^11.0.12", + "@nestjs/core": "^11.0.12" + }, + "peerDependencies": { + "node-supervisord": ">=1.0.6-rc.2" + } + }, "node_modules/@remnawave/xtls-sdk": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@remnawave/xtls-sdk/-/xtls-sdk-0.2.0.tgz", - "integrity": "sha512-LbG1/vyBteLg+s9PFdv4BKzUpf+7hTNDx7Eu0CcwG1e0+j14VFIgN9v1izh4OHWr66uwQxDNAG9bHz/01wg9gA==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@remnawave/xtls-sdk/-/xtls-sdk-0.3.0.tgz", + "integrity": "sha512-bSeayeDWBTuHqFASgFNrO9ThFUOhjcbuuM3aFW3BiZlGJ23F/36tLtdc3/f2wrC3zHixlf8UJzjOUSR8C5zHPg==", "license": "AGPL-3.0-only", "dependencies": { "@bufbuild/protobuf": "^2.2.2", @@ -1574,13 +1717,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/bcryptjs": { - "version": "2.4.6", - "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", - "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/body-parser": { "version": "1.19.5", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", @@ -1632,15 +1768,14 @@ "license": "MIT" }, "node_modules/@types/express": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", - "integrity": "sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.1.tgz", + "integrity": "sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==", "dev": true, "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^5.0.0", - "@types/qs": "*", "@types/serve-static": "*" } }, @@ -1679,11 +1814,13 @@ "license": "MIT" }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.7.tgz", - "integrity": "sha512-ugo316mmTYBl2g81zDFnZ7cfxlut3o+/EQdaP7J8QN2kY6lJ22hmQYCK5EHcJHbrW+dkCGSCPgbG8JtYj6qSrg==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", + "dev": true, "license": "MIT", "dependencies": { + "@types/ms": "*", "@types/node": "*" } }, @@ -1721,15 +1858,31 @@ "@types/node": "*" } }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "22.13.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz", - "integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==", + "version": "22.13.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz", + "integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==", "license": "MIT", "dependencies": { "undici-types": "~6.20.0" } }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/nunjucks": { "version": "3.2.6", "resolved": "https://registry.npmjs.org/@types/nunjucks/-/nunjucks-3.2.6.tgz", @@ -1790,10 +1943,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "license": "MIT" + }, "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", "dev": true, "license": "MIT" }, @@ -1827,21 +1986,21 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz", - "integrity": "sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.28.0.tgz", + "integrity": "sha512-lvFK3TCGAHsItNdWZ/1FkvpzCxTHUVuFrdnOGLMa0GGCFIbCgQWVk3CzCGdA7kM3qGVc+dfW9tr0Z/sHnGDFyg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/type-utils": "8.18.1", - "@typescript-eslint/utils": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/scope-manager": "8.28.0", + "@typescript-eslint/type-utils": "8.28.0", + "@typescript-eslint/utils": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1853,20 +2012,20 @@ "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.1.tgz", - "integrity": "sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.28.0.tgz", + "integrity": "sha512-LPcw1yHD3ToaDEoljFEfQ9j2xShY367h7FZ1sq5NJT9I3yj4LHer1Xd1yRSOdYy9BpsrxU7R+eoDokChYM53lQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/typescript-estree": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/scope-manager": "8.28.0", + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/typescript-estree": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0", "debug": "^4.3.4" }, "engines": { @@ -1878,18 +2037,18 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz", - "integrity": "sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.28.0.tgz", + "integrity": "sha512-u2oITX3BJwzWCapoZ/pXw6BCOl8rJP4Ij/3wPoGvY8XwvXflOzd1kLrDUUUAIEdJSFh+ASwdTHqtan9xSg8buw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1" + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1900,16 +2059,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz", - "integrity": "sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.28.0.tgz", + "integrity": "sha512-oRoXu2v0Rsy/VoOGhtWrOKDiIehvI+YNrDk5Oqj40Mwm0Yt01FC/Q7nFqg088d3yAsR1ZcZFVfPCTTFCe/KPwg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.18.1", - "@typescript-eslint/utils": "8.18.1", + "@typescript-eslint/typescript-estree": "8.28.0", + "@typescript-eslint/utils": "8.28.0", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1920,13 +2079,13 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.1.tgz", - "integrity": "sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.28.0.tgz", + "integrity": "sha512-bn4WS1bkKEjx7HqiwG2JNB3YJdC1q6Ue7GyGlwPHyt0TnVq6TtD/hiOdTZt71sq0s7UzqBFXD8t8o2e63tXgwA==", "dev": true, "license": "MIT", "engines": { @@ -1938,20 +2097,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz", - "integrity": "sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.28.0.tgz", + "integrity": "sha512-H74nHEeBGeklctAVUvmDkxB1mk+PAZ9FiOMPFncdqeRBXxk1lWSYraHw8V12b7aa6Sg9HOBNbGdSHobBPuQSuA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/visitor-keys": "8.18.1", + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/visitor-keys": "8.28.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1961,20 +2120,20 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.1.tgz", - "integrity": "sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.28.0.tgz", + "integrity": "sha512-OELa9hbTYciYITqgurT1u/SzpQVtDLmQMFzy/N8pQE+tefOyCWT79jHsav294aTqV1q1u+VzqDGbuujvRYaeSQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.18.1", - "@typescript-eslint/types": "8.18.1", - "@typescript-eslint/typescript-estree": "8.18.1" + "@typescript-eslint/scope-manager": "8.28.0", + "@typescript-eslint/types": "8.28.0", + "@typescript-eslint/typescript-estree": "8.28.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1985,17 +2144,17 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.8.0" + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz", - "integrity": "sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==", + "version": "8.28.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.28.0.tgz", + "integrity": "sha512-hbn8SZ8w4u2pRwgQ1GlUrPKE+t2XvcCW5tTRF7j6SMYIuYG37XuzIW44JCZPa36evi0Oy2SnM664BlIaAuQcvg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.18.1", + "@typescript-eslint/types": "8.28.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2019,13 +2178,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", - "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", - "dev": true, - "license": "ISC" - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -2432,15 +2584,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-flatten": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-3.0.0.tgz", @@ -2950,22 +3093,6 @@ "node": ">=0.8" } }, - "node_modules/clone-deep": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", - "integrity": "sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==", - "license": "MIT", - "dependencies": { - "for-own": "^0.1.3", - "is-plain-object": "^2.0.1", - "kind-of": "^3.0.2", - "lazy-cache": "^1.0.3", - "shallow-clone": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", @@ -3078,6 +3205,12 @@ "typedarray": "^0.0.6" } }, + "node_modules/confbox": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.1.tgz", + "integrity": "sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==", + "license": "MIT" + }, "node_modules/consola": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz", @@ -3221,7 +3354,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3269,19 +3401,6 @@ "node": ">=0.3.1" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dotenv": { "version": "16.4.7", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", @@ -3374,9 +3493,9 @@ } }, "node_modules/enhanced-ms": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/enhanced-ms/-/enhanced-ms-3.0.0.tgz", - "integrity": "sha512-snksUu7ukLqwaoMQt5R6DqPgY0nyA3s/xIL+w5m+vsYJw3DDJEKRjhjAa2Lw1I+ZNbL6hZVfQ90r/58sugu09A==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-ms/-/enhanced-ms-4.1.0.tgz", + "integrity": "sha512-m2ERryfuotoqsbKA5h7Hgnihejp8ZYV9fNFq3TWkcmmQ+WDZjSELx076v/v0r7QMveeLGMqZINNjoa2v17/Vng==", "license": "MIT" }, "node_modules/enhanced-resolve": { @@ -3469,66 +3588,70 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.23.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", + "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.2", + "@eslint/config-helpers": "^0.2.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.23.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.1.tgz", + "integrity": "sha512-4EQQr6wXwS+ZJSzaR5ZCrYgLxqvUjdXctaEtBqHcbkW944B1NQyO4qpdHQbXBONfwxXdkAY81HH4+LUfrg+zPw==", "dev": true, "license": "MIT", "bin": { @@ -3549,32 +3672,32 @@ } }, "node_modules/eslint-plugin-perfectionist": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-4.4.0.tgz", - "integrity": "sha512-B78pWxCsA2sClourpWEmWziCcjEsAEyxsNV5G6cxxteu/NI0/2en9XZUONf5e/+O+dgoLZsEPHQEhnIxJcnUvA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-perfectionist/-/eslint-plugin-perfectionist-4.10.1.tgz", + "integrity": "sha512-GXwFfL47RfBLZRGQdrvGZw9Ali2T2GPW8p4Gyj2fyWQ9396R/HgJMf0m9kn7D6WXRwrINfTDGLS+QYIeok9qEg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "^8.18.1", - "@typescript-eslint/utils": "^8.18.1", + "@typescript-eslint/types": "^8.26.0", + "@typescript-eslint/utils": "^8.26.0", "natural-orderby": "^5.0.0" }, "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "eslint": ">=8.0.0" + "eslint": ">=8.45.0" } }, "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.5.tgz", + "integrity": "sha512-IKKP8R87pJyMl7WWamLgPkloB16dagPIdd2FjBDbyRYPKo93wS/NbCOPh6gH+ieNLC+XZrhJt/kWj0PS/DFdmg==", "dev": true, "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" + "synckit": "^0.10.2" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -3585,7 +3708,7 @@ "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", - "eslint-config-prettier": "*", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "peerDependenciesMeta": { @@ -3598,9 +3721,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -3608,7 +3731,7 @@ "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3655,6 +3778,19 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3689,18 +3825,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -3889,6 +4038,12 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, + "node_modules/exsolve": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.4.tgz", + "integrity": "sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==", + "license": "MIT" + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -3918,9 +4073,9 @@ "license": "Apache-2.0" }, "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==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { @@ -3928,7 +4083,7 @@ "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -3971,9 +4126,9 @@ "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, "license": "ISC", "dependencies": { @@ -4002,16 +4157,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -4087,24 +4242,23 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true, "license": "ISC" }, @@ -4114,27 +4268,6 @@ "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", "license": "MIT" }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", - "license": "MIT", - "dependencies": { - "for-in": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -4245,13 +4378,6 @@ "dev": true, "license": "Unlicense" }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -4346,16 +4472,13 @@ "license": "BSD-2-Clause" }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4432,12 +4555,12 @@ } }, "node_modules/helmet": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.2.0.tgz", - "integrity": "sha512-ZRiwvN089JfMXokizgqEPXsl2Guk094yExfoDXR0cBYWxtBbaSww/w+vT4WEJsBW2iTUi1GgZ6swmoug3Oy4Xw==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz", + "integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==", "license": "MIT", "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/http-errors": { @@ -4466,12 +4589,12 @@ } }, "node_modules/husky": { - "version": "9.0.11", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", - "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "license": "MIT", "bin": { - "husky": "bin.mjs" + "husky": "bin.js" }, "engines": { "node": ">=18" @@ -4551,18 +4674,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -4598,21 +4709,6 @@ "node": ">=8" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "license": "MIT" - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4655,6 +4751,18 @@ "node": ">=8" } }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4665,16 +4773,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -4687,18 +4785,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -4741,15 +4827,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/iterare": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz", @@ -4923,33 +5000,12 @@ "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", "license": "MIT" }, - "node_modules/lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5174,20 +5230,6 @@ "node": ">= 4.0.0" } }, - "node_modules/merge-deep": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", - "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", - "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "clone-deep": "^0.2.4", - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/merge-descriptors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", @@ -5328,28 +5370,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", - "license": "MIT", - "dependencies": { - "for-in": "^0.1.3", - "is-extendable": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-object/node_modules/for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -5461,6 +5481,24 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/nanoid": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -5508,17 +5546,18 @@ } }, "node_modules/nestjs-zod": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/nestjs-zod/-/nestjs-zod-3.0.0.tgz", - "integrity": "sha512-vL9CHShCVj6TmjCVPOd4my46D8d7FdoB4nQvvh+lmVTuzvnwuD+slSxjT4EDdPDWDFtjhfpvQnnkr55/80KHEQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/nestjs-zod/-/nestjs-zod-4.3.1.tgz", + "integrity": "sha512-gl10NOf/AhWt4HLcnMI1J0WUlBCKyteJBftD6SwNyX71/vzAorr5MJQWiDJoPPkou9QL2CRHHBtyjr55o7++Xw==", "license": "MIT", "dependencies": { - "merge-deep": "^3.0.3" + "@nest-zod/z": "*", + "deepmerge": "^4.3.1" }, "peerDependencies": { - "@nestjs/common": ">= 8.0.0", - "@nestjs/core": ">= 8.0.0", - "@nestjs/swagger": ">= 5.0.0", + "@nestjs/common": "^10.0.0 || ^11.0.0", + "@nestjs/core": "^10.0.0 || ^11.0.0", + "@nestjs/swagger": "^7.4.2 || ^8.0.0 || ^11.0.0", "zod": ">= 3.14.3" }, "peerDependenciesMeta": { @@ -5573,6 +5612,15 @@ "lodash": "^4.17.21" } }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, "node_modules/node-object-hash": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-object-hash/-/node-object-hash-3.1.1.tgz", @@ -5590,6 +5638,19 @@ "dev": true, "license": "MIT" }, + "node_modules/node-supervisord": { + "version": "1.0.6-rc.2", + "resolved": "https://registry.npmjs.org/node-supervisord/-/node-supervisord-1.0.6-rc.2.tgz", + "integrity": "sha512-lkDcHxuuo9m4Z4o0xQgbr819t6JH0NGzSJAoiw4RN4B1Byt3BN2JlNZa3Nmy63iIVysxHcVYFI5VqQZX5m3wDA==", + "license": "MIT", + "dependencies": { + "url": "^0.11.3", + "xmlrpc": "^1.3.2" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -5810,6 +5871,23 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -5916,16 +5994,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5954,6 +6022,12 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, "node_modules/pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", @@ -5979,6 +6053,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pkg-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", + "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.1", + "exsolve": "^1.0.1", + "pathe": "^2.0.3" + } + }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -6000,9 +6085,9 @@ } }, "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", "bin": { @@ -6029,12 +6114,12 @@ } }, "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz", + "integrity": "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==", "license": "MIT", "engines": { - "node": ">=6" + "node": "^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6302,78 +6387,24 @@ "dev": true, "license": "ISC" }, - "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, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "license": "MIT", "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 4" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, "node_modules/router": { @@ -6462,6 +6493,12 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "license": "ISC" + }, "node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -6505,10 +6542,23 @@ "dev": true, "license": "MIT" }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6580,42 +6630,6 @@ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "license": "ISC" }, - "node_modules/shallow-clone": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==", - "license": "MIT", - "dependencies": { - "is-extendable": "^0.1.1", - "kind-of": "^2.0.1", - "lazy-cache": "^0.2.3", - "mixin-object": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-clone/node_modules/kind-of": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==", - "license": "MIT", - "dependencies": { - "is-buffer": "^1.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-clone/node_modules/lazy-cache": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6940,14 +6954,14 @@ } }, "node_modules/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.10.3.tgz", + "integrity": "sha512-R1urvuyiTaWfeCggqEvpDJwAlDVdsT9NM+IP//Tk2x7qHCkSvBk/fwFgw/TLAHzZlrAnnazMcRw0ZD8HlYFTEQ==", "dev": true, "license": "MIT", "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" + "@pkgr/core": "^0.2.0", + "tslib": "^2.8.1" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -7137,13 +7151,6 @@ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "license": "MIT" }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -7199,16 +7206,16 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/ts-error": { @@ -7218,9 +7225,9 @@ "license": "MIT" }, "node_modules/ts-loader": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", - "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", + "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -7332,19 +7339,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.0.tgz", @@ -7378,9 +7372,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", - "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -7481,6 +7475,25 @@ "punycode": "^2.1.0" } }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "license": "MIT" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7828,6 +7841,29 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/xmlbuilder": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz", + "integrity": "sha512-eKRAFz04jghooy8muekqzo8uCSVNeyRedbuJrp0fovbLIi7wlsYtdUn3vBAAPq2Y3/0xMz2WMEUQ8yhVVO9Stw==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlrpc": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/xmlrpc/-/xmlrpc-1.3.2.tgz", + "integrity": "sha512-jQf5gbrP6wvzN71fgkcPPkF4bF/Wyovd7Xdff8d6/ihxYmgETQYSuTc+Hl+tsh/jmgPLro/Aro48LMFlIyEKKQ==", + "license": "MIT", + "dependencies": { + "sax": "1.2.x", + "xmlbuilder": "8.2.x" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.0.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -7922,9 +7958,9 @@ } }, "node_modules/zod": { - "version": "3.24.1", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz", - "integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==", + "version": "3.24.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", + "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index ad406d1..af10367 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "@remnawave/node", - "version": "1.4.0", - "description": "", + "version": "1.5.0", + "description": "Remnawave Node", "private": true, + "type": "commonjs", "license": "AGPL-3.0-only", "author": "REMNAWAVE ", "homepage": "https://github.com/remnawave", @@ -27,59 +28,64 @@ }, "dependencies": { "@cjs-exporter/execa": "9.5.2", - "@nestjs/common": "11.0.11", - "@nestjs/config": "4.0.1", - "@nestjs/core": "11.0.11", + "@nestjs/common": "11.0.12", + "@nestjs/config": "4.0.2", + "@nestjs/core": "11.0.12", "@nestjs/jwt": "11.0.0", "@nestjs/passport": "11.0.5", - "@nestjs/platform-express": "11.0.11", - "@remnawave/xtls-sdk": "0.2.0", + "@nestjs/platform-express": "11.0.12", + "@remnawave/supervisord-nestjs": "0.1.1", + "@remnawave/xtls-sdk": "0.3.0", "@remnawave/xtls-sdk-nestjs": "0.2.2", - "enhanced-ms": "^3.0.0", - "helmet": "^7.1.0", - "husky": "9.0.11", + "enhanced-ms": "^4.1.0", + "helmet": "^8.1.0", + "husky": "9.1.7", "morgan": "^1.10.0", + "nanoid": "^5.1.5", "nest-winston": "^1.10.2", - "nestjs-zod": "3.0.0", + "nestjs-zod": "4.3.1", "node-object-hash": "^3.1.1", + "node-supervisord": "^1.0.6-rc.2", "object-hash": "^3.0.0", + "p-retry": "^6.2.1", "passport": "0.7.0", "passport-jwt": "4.0.1", - "pretty-bytes": "^5.6.0", + "pkg-types": "^2.1.0", + "pretty-bytes": "^6.1.1", "reflect-metadata": "0.2.2", "rxjs": "7.8.2", - "semver": "^7.6.3", - "systeminformation": "^5.25.5", + "selfsigned": "^2.4.1", + "semver": "^7.7.1", + "systeminformation": "^5.25.11", "table": "^6.9.0", "winston": "^3.17.0", - "zod": "^3.22.4" + "zod": "^3.24.2" }, "devDependencies": { "@nestjs/cli": "11.0.5", "@nestjs/schematics": "11.0.2", - "@types/bcryptjs": "^2.4.6", - "@types/express": "^5.0.0", + "@types/express": "^5.0.1", "@types/js-yaml": "^4.0.9", - "@types/jsonwebtoken": "^9.0.7", + "@types/jsonwebtoken": "^9.0.9", "@types/mjml": "^4.7.4", "@types/morgan": "^1.9.9", - "@types/node": "^22.13.9", + "@types/node": "^22.13.14", "@types/nunjucks": "^3.2.6", "@types/object-hash": "^3.0.6", "@types/passport-jwt": "^4.0.1", - "@types/semver": "^7.5.8", - "@typescript-eslint/eslint-plugin": "8.18.1", - "@typescript-eslint/parser": "8.18.1", - "eslint": "8.57.1", - "eslint-config-prettier": "^9.0.0", + "@types/semver": "^7.7.0", + "@typescript-eslint/eslint-plugin": "8.28.0", + "@typescript-eslint/parser": "8.28.0", + "eslint": "9.23.0", + "eslint-config-prettier": "^10.1.1", "eslint-plugin-paths": "^1.1.0", - "eslint-plugin-perfectionist": "^4.4.0", - "eslint-plugin-prettier": "^5.0.0", - "prettier": "^3.0.0", + "eslint-plugin-perfectionist": "^4.10.1", + "eslint-plugin-prettier": "^5.2.5", + "prettier": "^3.5.3", "source-map-support": "^0.5.21", - "ts-loader": "9.5.1", + "ts-loader": "9.5.2", "ts-node": "10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "5.7.2" + "typescript": "~5.8.2" } -} \ No newline at end of file +} diff --git a/src/app.module.ts b/src/app.module.ts index 9c1c602..fbd6320 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,8 +1,10 @@ -import { XtlsSdkNestjsModule } from '@remnawave/xtls-sdk-nestjs'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; +import { SupervisordNestjsModule } from '@remnawave/supervisord-nestjs'; +import { XtlsSdkNestjsModule } from '@remnawave/xtls-sdk-nestjs'; + import { JwtStrategy } from '@common/guards/jwt-guards/strategies/validate-token'; import { validateEnvConfig } from '@common/utils/validate-env-config'; import { configSchema, Env } from '@common/config/app-config'; @@ -27,6 +29,17 @@ import { InternalModule } from './modules/internal/internal.module'; port: configService.getOrThrow('XTLS_PORT'), }), }), + SupervisordNestjsModule.forRootAsync({ + imports: [], + inject: [], + useFactory: () => ({ + host: 'http://127.0.0.1:61002', + options: { + username: 'remnawave', + password: 'glcmYQLRwPXDXIBq', + }, + }), + }), RemnawaveNodeModules, InternalModule, JwtModule.registerAsync(getJWTConfig()), diff --git a/src/common/config/app-config/config.schema.ts b/src/common/config/app-config/config.schema.ts index b252824..61fed82 100644 --- a/src/common/config/app-config/config.schema.ts +++ b/src/common/config/app-config/config.schema.ts @@ -1,19 +1,36 @@ import { createZodDto } from 'nestjs-zod'; import { z } from 'zod'; -export const configSchema = z.object({ - APP_PORT: z - .string() - .default('3000') - .transform((port) => parseInt(port, 10)), - SSL_CERT: z.string(), - XTLS_IP: z.string().default('127.0.0.1'), - XTLS_PORT: z.string().default('61000'), - CONFIG_EQUAL_CHECKING: z - .string() - .default('true') - .transform((val) => val === 'true'), -}); +import { parseNodePayloadFromConfigService } from '@common/utils/decode-node-payload'; + +export const configSchema = z + .object({ + APP_PORT: z + .string() + .default('3000') + .transform((port) => parseInt(port, 10)), + SSL_CERT: z.string(), + XTLS_IP: z.string().default('127.0.0.1'), + JWT_PUBLIC_KEY: z.string().optional(), + XTLS_PORT: z.string().default('61000'), + CONFIG_EQUAL_CHECKING: z + .string() + .default('true') + .transform((val) => val === 'true'), + }) + .superRefine((data, ctx) => { + if (data.SSL_CERT) { + try { + const parsed = parseNodePayloadFromConfigService(data.SSL_CERT); + data.JWT_PUBLIC_KEY = parsed.jwtPublicKey; + } catch { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Invalid SSL certificate payload', + }); + } + } + }); export type ConfigSchema = z.infer; export class Env extends createZodDto(configSchema) {} diff --git a/src/common/config/jwt/jwt.config.ts b/src/common/config/jwt/jwt.config.ts index 0bf4861..b112524 100644 --- a/src/common/config/jwt/jwt.config.ts +++ b/src/common/config/jwt/jwt.config.ts @@ -5,7 +5,7 @@ export const getJWTConfig = (): JwtModuleAsyncOptions => ({ imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => ({ - secret: configService.getOrThrow('SSL_CERT'), + secret: configService.getOrThrow('JWT_PUBLIC_KEY'), algorithms: ['RS256'], }), }); diff --git a/src/common/exception/httpException.filter.ts b/src/common/exception/httpException.filter.ts index 7927c4f..5057469 100644 --- a/src/common/exception/httpException.filter.ts +++ b/src/common/exception/httpException.filter.ts @@ -1,7 +1,8 @@ -import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus, Logger } from '@nestjs/common'; import { ZodValidationException } from 'nestjs-zod'; import { Request, Response } from 'express'; +import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus, Logger } from '@nestjs/common'; + import { HttpExceptionWithErrorCodeType } from './http-exeception-with-error-code.type'; @Catch(HttpExceptionWithErrorCodeType, ZodValidationException) diff --git a/src/common/guards/jwt-guards/def-jwt-guard.ts b/src/common/guards/jwt-guards/def-jwt-guard.ts index bcb1fe5..5fe3a4e 100644 --- a/src/common/guards/jwt-guards/def-jwt-guard.ts +++ b/src/common/guards/jwt-guards/def-jwt-guard.ts @@ -8,6 +8,8 @@ export class JwtDefaultGuard extends AuthGuard('registeredUserJWT') { if (info instanceof Error || err || !user) { const response = context.switchToHttp().getResponse(); + this.logger.debug(`${JSON.stringify(context.switchToHttp().getRequest().headers)}`); + this.logger.error( `Incorrect SSL_CERT or JWT! Request dropped. URL: ${context.switchToHttp().getRequest().url}, IP: ${context.switchToHttp().getRequest().ip}`, ); diff --git a/src/common/guards/jwt-guards/strategies/validate-token.ts b/src/common/guards/jwt-guards/strategies/validate-token.ts index f736c80..dfe162a 100644 --- a/src/common/guards/jwt-guards/strategies/validate-token.ts +++ b/src/common/guards/jwt-guards/strategies/validate-token.ts @@ -1,5 +1,6 @@ -import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; + +import { PassportStrategy } from '@nestjs/passport'; import { ConfigService } from '@nestjs/config'; import { Injectable } from '@nestjs/common'; @@ -9,7 +10,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'registeredUserJWT') super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, - secretOrKey: configService.getOrThrow('SSL_CERT'), + secretOrKey: configService.getOrThrow('JWT_PUBLIC_KEY'), algorithms: ['RS256'], }); } diff --git a/src/common/utils/decode-node-payload/decode-node-payload.ts b/src/common/utils/decode-node-payload/decode-node-payload.ts new file mode 100644 index 0000000..fdc568b --- /dev/null +++ b/src/common/utils/decode-node-payload/decode-node-payload.ts @@ -0,0 +1,60 @@ +interface INodePayload { + caCertPem: string; + jwtPublicKey: string; + nodeCertPem: string; + nodeKeyPem: string; +} + +export function parseNodePayload(): INodePayload { + const nodePayload = process.env.SSL_CERT; + if (!nodePayload) { + throw new Error('SSL_CERT is not set'); + } + + try { + const parsed = JSON.parse(Buffer.from(nodePayload, 'base64').toString('utf-8')); + + if (!isValidNodePayload(parsed)) { + throw new Error('Invalid SSL certificate payload structure'); + } + + return parsed; + } catch (error) { + if (error instanceof SyntaxError) { + throw new Error('SSL_CERT contains invalid JSON'); + } + throw error; + } +} + +export function parseNodePayloadFromConfigService(sslCert: string): INodePayload { + try { + const parsed = JSON.parse(Buffer.from(sslCert, 'base64').toString('utf-8')); + + if (!isValidNodePayload(parsed)) { + throw new Error('Invalid SSL certificate payload structure'); + } + + return parsed; + } catch (error) { + if (error instanceof SyntaxError) { + throw new Error('SSL_CERT contains invalid JSON'); + } + throw error; + } +} + +function isValidNodePayload(payload: unknown): payload is INodePayload { + if (!payload || typeof payload !== 'object') return false; + + return ( + 'caCertPem' in payload && + typeof payload.caCertPem === 'string' && + 'jwtPublicKey' in payload && + typeof payload.jwtPublicKey === 'string' && + 'nodeCertPem' in payload && + typeof payload.nodeCertPem === 'string' && + 'nodeKeyPem' in payload && + typeof payload.nodeKeyPem === 'string' + ); +} diff --git a/src/common/utils/decode-node-payload/index.ts b/src/common/utils/decode-node-payload/index.ts new file mode 100644 index 0000000..140e3b7 --- /dev/null +++ b/src/common/utils/decode-node-payload/index.ts @@ -0,0 +1 @@ +export * from './decode-node-payload'; diff --git a/src/common/utils/filter-logs/filter-logs.ts b/src/common/utils/filter-logs/filter-logs.ts new file mode 100644 index 0000000..40041b3 --- /dev/null +++ b/src/common/utils/filter-logs/filter-logs.ts @@ -0,0 +1,13 @@ +import winston from 'winston'; + +const contextsToIgnore = ['InstanceLoader', 'RoutesResolver', 'RouterExplorer']; + +export const customLogFilter = winston.format((info) => { + if (info.context) { + const contextValue = String(info.context); + if (contextsToIgnore.some((ctx) => contextValue === ctx)) { + return false; + } + } + return info; +}); diff --git a/src/common/utils/filter-logs/index.ts b/src/common/utils/filter-logs/index.ts new file mode 100644 index 0000000..894aad2 --- /dev/null +++ b/src/common/utils/filter-logs/index.ts @@ -0,0 +1 @@ +export * from './filter-logs'; diff --git a/src/common/utils/generate-api-config.ts b/src/common/utils/generate-api-config.ts index b47bab1..1cdcc3c 100644 --- a/src/common/utils/generate-api-config.ts +++ b/src/common/utils/generate-api-config.ts @@ -1,5 +1,4 @@ import { - XRAY_API_INBOUND_MODEL, XRAY_DEFAULT_API_MODEL, XRAY_DEFAULT_POLICY_MODEL, XRAY_DEFAULT_STATS_MODEL, @@ -18,9 +17,9 @@ export const generateApiConfig = (config: Record): Record false, + border: getBorderCharacters('ramac'), + }, + ); +} diff --git a/src/main.ts b/src/main.ts index d84ba63..748e17e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,34 +1,56 @@ import { utilities as nestWinstonModuleUtilities, WinstonModule } from 'nest-winston'; -import { ConfigService } from '@nestjs/config'; import { ZodValidationPipe } from 'nestjs-zod'; -import { NestFactory } from '@nestjs/core'; import express, { json } from 'express'; +import { createLogger } from 'winston'; import * as winston from 'winston'; import helmet from 'helmet'; import morgan from 'morgan'; -import { XRAY_INTERNAL_API_PORT, XRAY_INTERNAL_FULL_PATH } from '@libs/contracts/constants'; +import { ConfigService } from '@nestjs/config'; +import { NestFactory } from '@nestjs/core'; + import { NotFoundExceptionFilter } from '@common/exception/not-found-exception.filter'; +import { customLogFilter } from '@common/utils/filter-logs/filter-logs'; +import { parseNodePayload } from '@common/utils/decode-node-payload'; +import { getStartMessage } from '@common/utils/get-start-message'; import { isDevelopment } from '@common/utils/is-development'; +import { XRAY_INTERNAL_API_PORT, XRAY_INTERNAL_FULL_PATH } from '@libs/contracts/constants'; import { REST_API, ROOT } from '@libs/contracts/api'; import { AppModule } from './app.module'; +const logger = createLogger({ + transports: [new winston.transports.Console()], + format: winston.format.combine( + customLogFilter(), + winston.format.timestamp({ + format: 'YYYY-MM-DD HH:mm:ss.SSS', + }), + winston.format.align(), + // winston.format.ms(), + nestWinstonModuleUtilities.format.nestLike('', { + colors: true, + prettyPrint: true, + processId: false, + appName: false, + }), + ), + level: isDevelopment() ? 'debug' : 'info', +}); + async function bootstrap(): Promise { + const nodePayload = parseNodePayload(); + const app = await NestFactory.create(AppModule, { + httpsOptions: { + key: nodePayload.nodeKeyPem, + cert: nodePayload.nodeCertPem, + ca: [nodePayload.caCertPem], + requestCert: true, + rejectUnauthorized: true, + }, logger: WinstonModule.createLogger({ - transports: [new winston.transports.Console()], - format: winston.format.combine( - winston.format.timestamp(), - // winston.format.ms(), - nestWinstonModuleUtilities.format.nestLike('', { - colors: true, - prettyPrint: true, - processId: false, - appName: false, - }), - ), - level: isDevelopment() ? 'debug' : 'info', + instance: logger, }), }); @@ -73,6 +95,16 @@ async function bootstrap(): Promise { ); internalApp.listen(XRAY_INTERNAL_API_PORT, '127.0.0.1'); + + logger.info( + '\n' + + (await getStartMessage( + Number(config.getOrThrow('APP_PORT')), + XRAY_INTERNAL_API_PORT, + app, + )) + + '\n', + ); } void bootstrap(); diff --git a/src/modules/handler/handler.controller.ts b/src/modules/handler/handler.controller.ts index 705cd6c..e37d327 100644 --- a/src/modules/handler/handler.controller.ts +++ b/src/modules/handler/handler.controller.ts @@ -1,9 +1,9 @@ import { Body, Controller, Post, UseFilters, UseGuards } from '@nestjs/common'; -import { HANDLER_CONTROLLER, HANDLER_ROUTES } from '@libs/contracts/api/controllers/handler'; import { HttpExceptionFilter } from '@common/exception/httpException.filter'; import { JwtDefaultGuard } from '@common/guards/jwt-guards/def-jwt-guard'; import { errorHandler } from '@common/helpers/error-handler.helper'; +import { HANDLER_CONTROLLER, HANDLER_ROUTES } from '@libs/contracts/api/controllers/handler'; import { GetInboundUsersCountRequestDto, @@ -17,9 +17,9 @@ import { AddUserRequestDto, AddUserResponseDto } from './dtos/add-user.dto'; import { RemoveUserRequestDto, RemoveUserResponseDto } from './dtos'; import { HandlerService } from './handler.service'; -@Controller(HANDLER_CONTROLLER) @UseFilters(HttpExceptionFilter) @UseGuards(JwtDefaultGuard) +@Controller(HANDLER_CONTROLLER) export class HandlerController { constructor(private readonly handlerService: HandlerService) {} diff --git a/src/modules/handler/handler.module.ts b/src/modules/handler/handler.module.ts index 0e39afc..ea2f24c 100644 --- a/src/modules/handler/handler.module.ts +++ b/src/modules/handler/handler.module.ts @@ -1,10 +1,10 @@ import { Module } from '@nestjs/common'; import { HandlerController } from './handler.controller'; +import { XrayModule } from '../xray-core/xray.module'; import { HandlerService } from './handler.service'; - @Module({ - imports: [], + imports: [XrayModule], controllers: [HandlerController], providers: [HandlerService], }) diff --git a/src/modules/handler/handler.service.ts b/src/modules/handler/handler.service.ts index de14527..0d36056 100644 --- a/src/modules/handler/handler.service.ts +++ b/src/modules/handler/handler.service.ts @@ -1,8 +1,9 @@ +import { Injectable, Logger } from '@nestjs/common'; + import { RemoveUserResponseModel as RemoveUserResponseModelFromSdk } from '@remnawave/xtls-sdk/build/src/handler/models/remove-user'; import { AddUserResponseModel as AddUserResponseModelFromSdk } from '@remnawave/xtls-sdk/build/src/handler/models/add-user'; import { ISdkResponse } from '@remnawave/xtls-sdk/build/src/common/types'; import { InjectXtls } from '@remnawave/xtls-sdk-nestjs'; -import { Injectable, Logger } from '@nestjs/common'; import { XtlsApi } from '@remnawave/xtls-sdk'; import { ICommandResponse } from '@common/types/command-response.type'; @@ -11,6 +12,7 @@ import { ERRORS } from '@libs/contracts/constants/errors'; import { AddUserResponseModel, RemoveUserResponseModel } from './models'; import { GetInboundUsersCountResponseModel } from './models'; import { GetInboundUsersResponseModel } from './models'; +import { XrayService } from '../xray-core/xray.service'; import { IRemoveUserRequest } from './interfaces'; import { TAddUserRequest } from './interfaces'; @@ -18,13 +20,23 @@ import { TAddUserRequest } from './interfaces'; export class HandlerService { private readonly logger = new Logger(HandlerService.name); - constructor(@InjectXtls() private readonly xtlsApi: XtlsApi) {} + constructor( + @InjectXtls() private readonly xtlsApi: XtlsApi, + private readonly xrayService: XrayService, + ) {} public async addUser(data: TAddUserRequest): Promise> { try { const { data: requestData } = data; const response: Array> = []; + const inboundsTags = this.xrayService.getSavedInboundsTags(); + + for (const tag of inboundsTags) { + this.logger.debug(`Removing user: ${requestData[0].username} from tag: ${tag}`); + await this.xtlsApi.handler.removeUser(tag, requestData[0].username); + } + for (const item of requestData) { let tempRes = null; @@ -126,9 +138,12 @@ export class HandlerService { data: IRemoveUserRequest, ): Promise> { try { - const { username, tags } = data; + const { username } = data; const response: Array> = []; - for (const tag of tags) { + + const inboundsTags = this.xrayService.getSavedInboundsTags(); + + for (const tag of inboundsTags) { const tempRes = await this.xtlsApi.handler.removeUser(tag, username); response.push(tempRes); } diff --git a/src/modules/handler/interfaces/remove-user.interface.ts b/src/modules/handler/interfaces/remove-user.interface.ts index 85fffba..b9129fd 100644 --- a/src/modules/handler/interfaces/remove-user.interface.ts +++ b/src/modules/handler/interfaces/remove-user.interface.ts @@ -1,4 +1,3 @@ export interface IRemoveUserRequest { - tags: string[]; username: string; } diff --git a/src/modules/internal/internal.controller.ts b/src/modules/internal/internal.controller.ts index e3beedb..9047d62 100644 --- a/src/modules/internal/internal.controller.ts +++ b/src/modules/internal/internal.controller.ts @@ -1,20 +1,20 @@ import { Controller, Get, UseFilters, UseGuards } from '@nestjs/common'; +import { PortGuard } from '@common/guards/request-port-guard/request-port.guard'; +import { HttpExceptionFilter } from '@common/exception/httpException.filter'; +import { OnPort } from '@common/decorators/port/port.decorator'; import { XRAY_INTERNAL_API_CONTROLLER, XRAY_INTERNAL_API_PATH, XRAY_INTERNAL_API_PORT, } from '@libs/contracts/constants'; -import { PortGuard } from '@common/guards/request-port-guard/request-port.guard'; -import { HttpExceptionFilter } from '@common/exception/httpException.filter'; -import { OnPort } from '@common/decorators/port/port.decorator'; import { InternalService } from './internal.service'; -@Controller(XRAY_INTERNAL_API_CONTROLLER) @OnPort(XRAY_INTERNAL_API_PORT) @UseFilters(HttpExceptionFilter) @UseGuards(PortGuard) +@Controller(XRAY_INTERNAL_API_CONTROLLER) export class InternalController { constructor(private readonly internalService: InternalService) {} diff --git a/src/modules/stats/stats.controller.ts b/src/modules/stats/stats.controller.ts index 1ccbd50..9ac33cd 100644 --- a/src/modules/stats/stats.controller.ts +++ b/src/modules/stats/stats.controller.ts @@ -1,9 +1,9 @@ import { Body, Controller, Get, Post, UseFilters, UseGuards } from '@nestjs/common'; -import { STATS_CONTROLLER, STATS_ROUTES } from '@libs/contracts/api/controllers/stats'; import { HttpExceptionFilter } from '@common/exception/httpException.filter'; import { JwtDefaultGuard } from '@common/guards/jwt-guards/def-jwt-guard'; import { errorHandler } from '@common/helpers/error-handler.helper'; +import { STATS_CONTROLLER, STATS_ROUTES } from '@libs/contracts/api/controllers/stats'; import { GetAllInboundsStatsRequestDto, @@ -22,13 +22,11 @@ import { } from './dto'; import { StatsService } from './stats.service'; -@Controller(STATS_CONTROLLER) @UseFilters(HttpExceptionFilter) @UseGuards(JwtDefaultGuard) +@Controller(STATS_CONTROLLER) export class StatsController { - constructor(private readonly statsService: StatsService) { - this.statsService = statsService; - } + constructor(private readonly statsService: StatsService) {} @Post(STATS_ROUTES.GET_USER_ONLINE_STATUS) public async getUserOnlineStatus( diff --git a/src/modules/stats/stats.service.ts b/src/modules/stats/stats.service.ts index 31d3ea8..b2e312b 100644 --- a/src/modules/stats/stats.service.ts +++ b/src/modules/stats/stats.service.ts @@ -1,5 +1,6 @@ -import { InjectXtls } from '@remnawave/xtls-sdk-nestjs'; import { Injectable, Logger } from '@nestjs/common'; + +import { InjectXtls } from '@remnawave/xtls-sdk-nestjs'; import { XtlsApi } from '@remnawave/xtls-sdk'; import { ICommandResponse } from '@common/types/command-response.type'; @@ -87,7 +88,9 @@ export class StatsService { return { isOk: true, - response: new GetUsersStatsResponseModel(response.data.users), + response: new GetUsersStatsResponseModel( + response.data.users.filter((user) => user.uplink !== 0 || user.downlink !== 0), + ), }; } catch (error) { this.logger.error(error); diff --git a/src/modules/vision/vision.service.ts b/src/modules/vision/vision.service.ts index 91bd812..9ab4831 100644 --- a/src/modules/vision/vision.service.ts +++ b/src/modules/vision/vision.service.ts @@ -1,7 +1,9 @@ -import { InjectXtls } from '@remnawave/xtls-sdk-nestjs'; +import objectHash from 'object-hash'; + import { Injectable, Logger } from '@nestjs/common'; + +import { InjectXtls } from '@remnawave/xtls-sdk-nestjs'; import { XtlsApi } from '@remnawave/xtls-sdk'; -import objectHash from 'object-hash'; import { ICommandResponse } from '@common/types/command-response.type'; import { ERRORS } from '@libs/contracts/constants/errors'; diff --git a/src/modules/xray-core/xray.controller.ts b/src/modules/xray-core/xray.controller.ts index 38fa0fd..4343142 100644 --- a/src/modules/xray-core/xray.controller.ts +++ b/src/modules/xray-core/xray.controller.ts @@ -1,9 +1,9 @@ -import { Body, Controller, Get, Ip, Post, UseFilters, UseGuards } from '@nestjs/common'; +import { Body, Controller, Get, Ip, Logger, Post, UseFilters, UseGuards } from '@nestjs/common'; -import { XRAY_CONTROLLER, XRAY_ROUTES } from '@libs/contracts/api/controllers/xray'; import { HttpExceptionFilter } from '@common/exception/httpException.filter'; import { JwtDefaultGuard } from '@common/guards/jwt-guards/def-jwt-guard'; import { errorHandler } from '@common/helpers/error-handler.helper'; +import { XRAY_CONTROLLER, XRAY_ROUTES } from '@libs/contracts/api/controllers/xray'; import { GetNodeHealthCheckResponseDto, @@ -14,13 +14,13 @@ import { } from './dtos/'; import { XrayService } from './xray.service'; -@Controller(XRAY_CONTROLLER) @UseFilters(HttpExceptionFilter) @UseGuards(JwtDefaultGuard) +@Controller(XRAY_CONTROLLER) export class XrayController { - constructor(private readonly xrayService: XrayService) { - this.xrayService = xrayService; - } + private readonly logger = new Logger(XrayController.name); + + constructor(private readonly xrayService: XrayService) {} @Post(XRAY_ROUTES.START) public async startXray( diff --git a/src/modules/xray-core/xray.module.ts b/src/modules/xray-core/xray.module.ts index 7a48be2..34c29df 100644 --- a/src/modules/xray-core/xray.module.ts +++ b/src/modules/xray-core/xray.module.ts @@ -8,7 +8,7 @@ import { XrayService } from './xray.service'; imports: [InternalModule], providers: [XrayService], controllers: [XrayController], - exports: [], + exports: [XrayService], }) export class XrayModule implements OnModuleDestroy { constructor(private readonly xrayService: XrayService) {} diff --git a/src/modules/xray-core/xray.service.ts b/src/modules/xray-core/xray.service.ts index 4809b1d..4cdd2be 100644 --- a/src/modules/xray-core/xray.service.ts +++ b/src/modules/xray-core/xray.service.ts @@ -1,13 +1,19 @@ -import { Injectable, Logger, OnApplicationBootstrap, OnModuleInit } from '@nestjs/common'; -import { InjectXtls } from '@remnawave/xtls-sdk-nestjs'; -import { ConfigService } from '@nestjs/config'; -import { XtlsApi } from '@remnawave/xtls-sdk'; +import { ProcessInfo } from 'node-supervisord/dist/interfaces'; +import { SupervisordClient } from 'node-supervisord'; import { execa } from '@cjs-exporter/execa'; import { hasher } from 'node-object-hash'; import { table } from 'table'; import ems from 'enhanced-ms'; +import pRetry from 'p-retry'; import semver from 'semver'; +import { Injectable, Logger, OnApplicationBootstrap, OnModuleInit } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; + +import { InjectSupervisord } from '@remnawave/supervisord-nestjs'; +import { InjectXtls } from '@remnawave/xtls-sdk-nestjs'; +import { XtlsApi } from '@remnawave/xtls-sdk'; + import { ISystemStats } from '@common/utils/get-system-stats/get-system-stats.interface'; import { ICommandResponse } from '@common/types/command-response.type'; import { generateApiConfig } from '@common/utils/generate-api-config'; @@ -21,6 +27,8 @@ import { } from './models'; import { InternalService } from '../internal/internal.service'; +const XRAY_PROCESS_NAME = 'xray' as const; + @Injectable() export class XrayService implements OnApplicationBootstrap, OnModuleInit { private readonly logger = new Logger(XrayService.name); @@ -33,9 +41,11 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { private isXrayOnline: boolean = false; private systemStats: ISystemStats | null = null; private isXrayStartedProccesing: boolean = false; + private xtlsConfigInbounds: Array = []; constructor( @InjectXtls() private readonly xtlsSdk: XtlsApi, + @InjectSupervisord() private readonly supervisordApi: SupervisordClient, private readonly internalService: InternalService, private readonly configService: ConfigService, ) { @@ -43,6 +53,7 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { this.xrayVersion = null; this.systemStats = null; this.isXrayStartedProccesing = false; + this.xtlsConfigInbounds = []; this.configEqualChecking = this.configService.getOrThrow('CONFIG_EQUAL_CHECKING'); } @@ -53,9 +64,10 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { async onApplicationBootstrap() { try { this.systemStats = await getSystemStats(); - this.logger.log(`${JSON.stringify(this.systemStats)}`); + + await this.supervisordApi.getState(); } catch (error) { - this.logger.error(`Failed to get node hardware info: ${error}`); + this.logger.error(`Error in Application Bootstrap: ${error}`); } this.isXrayOnline = false; @@ -85,6 +97,8 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { const fullConfig = generateApiConfig(config); + this.xtlsConfigInbounds = await this.extractInboundTags(fullConfig); + if (this.configEqualChecking) { this.logger.log('Getting config checksum...'); const newChecksum = this.getConfigChecksum(fullConfig); @@ -104,7 +118,7 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { `); if (oldChecksum === newChecksum && isXrayOnline) { - this.logger.error( + this.logger.warn( 'Xray is already online with the same config. Skipping...', ); @@ -125,22 +139,27 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { this.internalService.setXrayConfig(fullConfig); - this.logger.log(`XTLS config generated in ${performance.now() - tm}ms`); + this.logger.log( + 'XTLS config generated in: ' + + ems(performance.now() - tm, { + extends: 'short', + includeMs: true, + }), + ); - const xrayProcess = await execa('supervisorctl', ['restart', 'xray'], { - reject: false, - all: true, - cleanup: true, - timeout: 60_000, - lines: true, - }); + const xrayProcess = await this.restartXrayProcess(); - this.logger.debug(xrayProcess.all); + if (xrayProcess.error) { + this.logger.error(xrayProcess.error); + return { + isOk: false, + response: new StartXrayResponseModel(false, null, xrayProcess.error, null), + }; + } let isStarted = await this.getXrayInternalStatus(); - if (!isStarted && xrayProcess.all[1] === 'xray: started') { - await new Promise((resolve) => setTimeout(resolve, 2000)); + if (!isStarted && xrayProcess.processInfo!.state === 20) { isStarted = await this.getXrayInternalStatus(); } @@ -155,7 +174,7 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { ['Checksum', this.configChecksum], ['Master IP', ip], ['Internal Status', isStarted], - ['Error', xrayProcess.all.join(' | ')], + ['Error', xrayProcess.error], ], { header: { @@ -171,7 +190,7 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { response: new StartXrayResponseModel( isStarted, this.xrayVersion, - xrayProcess.all.join('\n'), + xrayProcess.error, this.systemStats, ), }; @@ -220,7 +239,10 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { } finally { this.logger.log( 'Start XTLS took: ' + - ems(performance.now() - tm, { shortFormat: true, includeMs: true }), + ems(performance.now() - tm, { + extends: 'short', + includeMs: true, + }), ); this.isXrayStartedProccesing = false; @@ -235,7 +257,6 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { this.configChecksum = null; this.internalService.setXrayConfig({}); - this.logger.log('Xray stopped due to request.'); return { isOk: true, response: new StopXrayResponseModel(true), @@ -292,7 +313,11 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { public async killAllXrayProcesses(): Promise { try { - await execa('supervisorctl', ['stop', 'xray'], { reject: false }); + try { + await this.supervisordApi.stopProcess(XRAY_PROCESS_NAME, true); + } catch (error) { + this.logger.error(`Response from supervisorctl stop: ${error}`); + } await execa('pkill', ['xray'], { reject: false }); @@ -311,13 +336,13 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { this.logger.log('Killed all Xray processes'); } catch (error) { - this.logger.log('No existing Xray processes found. Error: ', error); + this.logger.log(`No existing Xray processes found. Error: ${error}`); } } public async supervisorctlStop(): Promise { try { - await execa('supervisorctl', ['stop', 'xray'], { reject: false, timeout: 10_000 }); + await this.supervisordApi.stopProcess(XRAY_PROCESS_NAME, true); this.logger.log('Supervisorctl: XTLS stopped.'); } catch (error) { @@ -335,6 +360,7 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { private async getXrayVersionFromExec(): Promise { const output = await execa(this.xrayPath, ['version']); + const version = semver.valid(semver.coerce(output.stdout)); if (version) { @@ -344,31 +370,89 @@ export class XrayService implements OnApplicationBootstrap, OnModuleInit { return version; } + public async getXrayInfo(): Promise<{ + version: string | null; + path: string; + systemInfo: ISystemStats | null; + }> { + const output = await execa(this.xrayPath, ['version']); + const version = semver.valid(semver.coerce(output.stdout)); + + if (version) { + this.xrayVersion = version; + } + + return { + version: version, + path: this.xrayPath, + systemInfo: this.systemStats, + }; + } + private async getXrayInternalStatus(): Promise { - const maxRetries = 8; - const delay = 2000; + try { + return await pRetry( + async () => { + const { isOk, message } = await this.xtlsSdk.stats.getSysStats(); - for (let attempt = 0; attempt < maxRetries; attempt++) { - try { - const { isOk } = await this.xtlsSdk.stats.getSysStats(); + if (!isOk) { + throw new Error(message); + } - if (isOk) { return true; - } + }, + { + retries: 10, + minTimeout: 2000, + maxTimeout: 2000, + onFailedAttempt: (error) => { + this.logger.debug( + `Get Xray internal status attempt ${error.attemptNumber} failed. ${error.retriesLeft} retries left.`, + ); + }, + }, + ); + } catch (error) { + this.logger.error(`Failed to get Xray internal status: ${error}`); + return false; + } + } - if (attempt < maxRetries - 1) { - this.logger.debug( - `Xray status check attempt ${attempt + 1} failed, retrying in ${delay}ms...`, - ); - await new Promise((resolve) => setTimeout(resolve, delay)); - } - } catch (error) { - this.logger.error(`Unexpected error during Xray status check: ${error}`); - return false; + private async restartXrayProcess(): Promise<{ + processInfo: ProcessInfo | null; + error: string | null; + }> { + try { + const processState = await this.supervisordApi.getProcessInfo(XRAY_PROCESS_NAME); + + // Reference: https://supervisord.org/subprocess.html#process-states + if (processState.state === 20) { + await this.supervisordApi.stopProcess(XRAY_PROCESS_NAME, true); } + + await this.supervisordApi.startProcess(XRAY_PROCESS_NAME, true); + + return { + processInfo: await this.supervisordApi.getProcessInfo(XRAY_PROCESS_NAME), + error: null, + }; + } catch (error) { + return { + processInfo: null, + error: error instanceof Error ? error.message : 'Unknown error', + }; } + } + + private async extractInboundTags(config: Record): Promise { + if (!config.inbounds || !Array.isArray(config.inbounds)) { + return []; + } + + return config.inbounds.map((inbound: { tag: string }) => inbound.tag); + } - this.logger.error(`Failed to get positive Xray status after ${maxRetries} attempts`); - return false; + public getSavedInboundsTags(): string[] { + return this.xtlsConfigInbounds; } } diff --git a/supervisord.conf b/supervisord.conf index 7ce5d9c..2e8c967 100644 --- a/supervisord.conf +++ b/supervisord.conf @@ -1,9 +1,3 @@ -[unix_http_server] -file=/var/run/supervisor.sock -chmod=0700 -username=remnawave -password=glcmYQLRwPXDXIBq - [supervisord] nodaemon=true user=root @@ -16,7 +10,12 @@ loglevel=info silent=true [supervisorctl] -serverurl=unix:///var/run/supervisor.sock +serverurl=127.0.0.1:61002 +username=remnawave +password=glcmYQLRwPXDXIBq + +[inet_http_server] +port=127.0.0.1:61002 username=remnawave password=glcmYQLRwPXDXIBq diff --git a/tsconfig.json b/tsconfig.json index 2cab9fd..fc306bd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,13 +1,14 @@ { "compilerOptions": { - "module": "commonjs", + "module": "NodeNext", "declaration": true, "removeComments": true, "emitDecoratorMetadata": true, "esModuleInterop": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, - "target": "ES2021", + "moduleResolution": "NodeNext", + "target": "ESNext", "sourceMap": true, "resolveJsonModule": true, "outDir": "./dist",