From b40270f05899910e3bf4c365f4a7dad8687af5fa Mon Sep 17 00:00:00 2001 From: SepehrYahyaee <7heycallmegray@gmail.com> Date: Sat, 14 Mar 2026 13:36:05 +0330 Subject: [PATCH 1/2] Added refactored version of car-body --- package-lock.json | 2848 ++++++++--------- package.json | 1 + .../blameWorkflow-steps.enum.ts | 5 +- src/auth/auth-services/user.auth.service.ts | 14 +- .../claim-request-management.service.ts | 120 +- .../dto/create-request-management.dto.ts | 64 +- .../schema/accidentInformation.type.ts | 5 + .../entities/schema/blame-cases.schema.ts | 41 +- .../entities/schema/partyRole.enum.ts | 24 + .../expert-initiated.v2.controller.ts | 244 ++ .../request-management.module.ts | 2 + .../request-management.service.ts | 874 ++++- .../request-management.v2.controller.ts | 50 +- .../dto/create-workflow-step.dto.ts | 4 +- .../workflow-step-management.service.ts | 37 + 15 files changed, 2786 insertions(+), 1547 deletions(-) create mode 100644 src/request-management/expert-initiated.v2.controller.ts diff --git a/package-lock.json b/package-lock.json index 5d4602c..34f9792 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@arashioz/errjson-talieh": "^2.2.5", "@fraybabak/kavenegar_nest": "^1.0.5", - "@nestjs-modules/mailer": "^2.0.2", + "@nestjs-modules/mailer": "^1.8.1", "@nestjs/axios": "^3.1.3", "@nestjs/common": "^10.4.15", "@nestjs/core": "^10.4.15", @@ -23,8 +23,8 @@ "@nestjs/platform-fastify": "^10.4.15", "@nestjs/platform-socket.io": "^10.4.15", "@nestjs/schedule": "^4.1.2", - "@nestjs/serve-static": "^5.0.3", - "@nestjs/swagger": "^8.1.0", + "@nestjs/serve-static": "^4.0.2", + "@nestjs/swagger": "^7.4.2", "@nestjs/websockets": "^10.4.15", "@types/uuid": "^10.0.0", "axios": "^1.9.0", @@ -33,6 +33,7 @@ "class-validator": "^0.14.1", "crypto": "^1.0.1", "dotenv": "^16.4.7", + "express": "^4.22.1", "express-basic-auth": "^1.2.1", "fastest-levenshtein": "^1.0.16", "form-data": "^4.0.2", @@ -52,7 +53,7 @@ "yargs": "^17.7.2" }, "devDependencies": { - "@nestjs/cli": "^10.4.9", + "@nestjs/cli": "^11.0.14", "@nestjs/schematics": "^10.2.3", "@nestjs/testing": "^10.4.15", "@types/express": "^5.0.0", @@ -184,16 +185,16 @@ } }, "node_modules/@angular-devkit/schematics-cli": { - "version": "17.3.11", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-17.3.11.tgz", - "integrity": "sha512-kcOMqp+PHAKkqRad7Zd7PbpqJ0LqLaNZdY1+k66lLWmkEBozgq8v4ASn/puPWf9Bo0HpCiK+EzLf0VHE8Z/y6Q==", + "version": "19.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-19.2.19.tgz", + "integrity": "sha512-7q9UY6HK6sccL9F3cqGRUwKhM7b/XfD2YcVaZ2WD7VMaRlRm85v6mRjSrfKIAwxcQU0UK27kMc79NIIqaHjzxA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.11", - "@angular-devkit/schematics": "17.3.11", + "@angular-devkit/core": "19.2.19", + "@angular-devkit/schematics": "19.2.19", + "@inquirer/prompts": "7.3.2", "ansi-colors": "4.1.3", - "inquirer": "9.2.15", "symbol-observable": "4.0.0", "yargs-parser": "21.1.1" }, @@ -201,79 +202,192 @@ "schematics": "bin/schematics.js" }, "engines": { - "node": "^18.13.0 || >=20.9.0", + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/schematics-cli/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/@angular-devkit/schematics-cli/node_modules/inquirer": { - "version": "9.2.15", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", - "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/core": { + "version": "19.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.19.tgz", + "integrity": "sha512-JbLL+4IMLMBgjLZlnPG4lYDfz4zGrJ/s6Aoon321NJKuw1Kb1k5KpFu9dUY0BqLIe8xPQ2UJBpI+xXdK5MXMHQ==", "dev": true, "license": "MIT", "dependencies": { - "@ljharb/through": "^2.3.12", - "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "figures": "^3.2.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/@angular-devkit/schematics": { + "version": "19.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.19.tgz", + "integrity": "sha512-J4Jarr0SohdrHcb40gTL4wGPCQ952IMWF1G/MSAQfBAPvA9ZKApYhpxcY7PmehVePve+ujpus1dGsJ7dPxz8Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.19", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.17", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/@inquirer/prompts": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.3.2.tgz", + "integrity": "sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.1.2", + "@inquirer/confirm": "^5.1.6", + "@inquirer/editor": "^4.2.7", + "@inquirer/expand": "^4.0.9", + "@inquirer/input": "^4.1.6", + "@inquirer/number": "^3.0.9", + "@inquirer/password": "^4.0.9", + "@inquirer/rawlist": "^4.0.9", + "@inquirer/search": "^3.0.9", + "@inquirer/select": "^4.0.9" }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@angular-devkit/schematics-cli/node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "node_modules/@angular-devkit/schematics-cli/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@angular-devkit/schematics-cli/node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "node_modules/@angular-devkit/schematics-cli/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.12.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/schematics-cli/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/@arashioz/errjson-talieh": { @@ -2075,62 +2189,28 @@ } }, "node_modules/@css-inline/css-inline": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.14.1.tgz", - "integrity": "sha512-u4eku+hnPqqHIGq/ZUQcaP0TrCbYeLIYBaK7qClNRGZbnh8RC4gVxLEIo8Pceo1nOK9E5G4Lxzlw5KnXcvflfA==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline/-/css-inline-0.13.0.tgz", + "integrity": "sha512-ZozAXBiW1I8hf6eW5eTNqhxUdNOBxrNNxxUnQRiKQpWcs5ORuGaiWwV5focMBTJ5WXGN+Z8VLP93BOwWFPzCJw==", "license": "MIT", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@css-inline/css-inline-android-arm-eabi": "0.14.1", - "@css-inline/css-inline-android-arm64": "0.14.1", - "@css-inline/css-inline-darwin-arm64": "0.14.1", - "@css-inline/css-inline-darwin-x64": "0.14.1", - "@css-inline/css-inline-linux-arm-gnueabihf": "0.14.1", - "@css-inline/css-inline-linux-arm64-gnu": "0.14.1", - "@css-inline/css-inline-linux-arm64-musl": "0.14.1", - "@css-inline/css-inline-linux-x64-gnu": "0.14.1", - "@css-inline/css-inline-linux-x64-musl": "0.14.1", - "@css-inline/css-inline-win32-x64-msvc": "0.14.1" - } - }, - "node_modules/@css-inline/css-inline-android-arm-eabi": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm-eabi/-/css-inline-android-arm-eabi-0.14.1.tgz", - "integrity": "sha512-LNUR8TY4ldfYi0mi/d4UNuHJ+3o8yLQH9r2Nt6i4qeg1i7xswfL3n/LDLRXvGjBYqeEYNlhlBQzbPwMX1qrU6A==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@css-inline/css-inline-android-arm64": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-android-arm64/-/css-inline-android-arm64-0.14.1.tgz", - "integrity": "sha512-tH5us0NYGoTNBHOUHVV7j9KfJ4DtFOeTLA3cM0XNoMtArNu2pmaaBMFJPqECzavfXkLc7x5Z22UPZYjoyHfvCA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" + "@css-inline/css-inline-darwin-arm64": "0.13.0", + "@css-inline/css-inline-darwin-x64": "0.13.0", + "@css-inline/css-inline-linux-arm-gnueabihf": "0.13.0", + "@css-inline/css-inline-linux-arm64-gnu": "0.13.0", + "@css-inline/css-inline-linux-arm64-musl": "0.13.0", + "@css-inline/css-inline-linux-x64-gnu": "0.13.0", + "@css-inline/css-inline-linux-x64-musl": "0.13.0", + "@css-inline/css-inline-win32-x64-msvc": "0.13.0" } }, "node_modules/@css-inline/css-inline-darwin-arm64": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.14.1.tgz", - "integrity": "sha512-QE5W1YRIfRayFrtrcK/wqEaxNaqLULPI0gZB4ArbFRd3d56IycvgBasDTHPre5qL2cXCO3VyPx+80XyHOaVkag==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-arm64/-/css-inline-darwin-arm64-0.13.0.tgz", + "integrity": "sha512-A4QvlZdhp8v+3IHKF/UftRf5GrAVUMEHCGRuk2Dx594xn/UR4ieh+B70aMm5rfONh2hv5mlR9UcoYAkVpEQ99g==", "cpu": [ "arm64" ], @@ -2144,9 +2224,9 @@ } }, "node_modules/@css-inline/css-inline-darwin-x64": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.14.1.tgz", - "integrity": "sha512-mAvv2sN8awNFsbvBzlFkZPbCNZ6GCWY5/YcIz7V5dPYw+bHHRbjnlkNTEZq5BsDxErVrMIGvz05PGgzuNvZvdQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-darwin-x64/-/css-inline-darwin-x64-0.13.0.tgz", + "integrity": "sha512-px9z4ypzeECMyBEtlrNzTMpA1tnw5MmMIiMkBRhb8UGRr2pOBZY3yd/eEIxWzVVSPt0aIjVDwUOJ3+d0Z+BskA==", "cpu": [ "x64" ], @@ -2160,9 +2240,9 @@ } }, "node_modules/@css-inline/css-inline-linux-arm-gnueabihf": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.14.1.tgz", - "integrity": "sha512-AWC44xL0X7BgKvrWEqfSqkT2tJA5kwSGrAGT+m0gt11wnTYySvQ6YpX0fTY9i3ppYGu4bEdXFjyK2uY1DTQMHA==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm-gnueabihf/-/css-inline-linux-arm-gnueabihf-0.13.0.tgz", + "integrity": "sha512-+uo0coLQNgk/AKeOB8mXSRd8VIlUg38zRSB9B9q0ior9oBCDPtEdn1HuCSvWxHoOSJ8QNNk+uwbz0zW4CETzFw==", "cpu": [ "arm" ], @@ -2176,9 +2256,9 @@ } }, "node_modules/@css-inline/css-inline-linux-arm64-gnu": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.14.1.tgz", - "integrity": "sha512-drj0ciiJgdP3xKXvNAt4W+FH4KKMs8vB5iKLJ3HcH07sNZj58Sx++2GxFRS1el3p+GFp9OoYA6dgouJsGEqt0Q==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-gnu/-/css-inline-linux-arm64-gnu-0.13.0.tgz", + "integrity": "sha512-GVrsFbY5l0Hxyzxsm5S5JPGObvHm/Ybf2wZgnWBsQigxqGtr1FL535HaTwEnq6aHOpH3f08gR5Vx33gB7jG4pw==", "cpu": [ "arm64" ], @@ -2192,9 +2272,9 @@ } }, "node_modules/@css-inline/css-inline-linux-arm64-musl": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.14.1.tgz", - "integrity": "sha512-FzknI+st8eA8YQSdEJU9ykcM0LZjjigBuynVF5/p7hiMm9OMP8aNhWbhZ8LKJpKbZrQsxSGS4g9Vnr6n6FiSdQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-arm64-musl/-/css-inline-linux-arm64-musl-0.13.0.tgz", + "integrity": "sha512-V5h5+CRnE01EgoafI/kyjEcM8zvN+sKLnp17Aq9LqQfsut7mO3i72d8g/xeVC37DCLoGQFLvDCzbze2NbF2dIQ==", "cpu": [ "arm64" ], @@ -2208,9 +2288,9 @@ } }, "node_modules/@css-inline/css-inline-linux-x64-gnu": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.14.1.tgz", - "integrity": "sha512-yubbEye+daDY/4vXnyASAxH88s256pPati1DfVoZpU1V0+KP0BZ1dByZOU1ktExurbPH3gZOWisAnBE9xon0Uw==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-gnu/-/css-inline-linux-x64-gnu-0.13.0.tgz", + "integrity": "sha512-vbRV++73MW7dvz/AIbozkv4R68/k/sEp57hno/L6lx034VYxpCwdfqtGN4D0W1TOTzdr2b6qBOGNZ1oLKQZOQQ==", "cpu": [ "x64" ], @@ -2224,9 +2304,9 @@ } }, "node_modules/@css-inline/css-inline-linux-x64-musl": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.14.1.tgz", - "integrity": "sha512-6CRAZzoy1dMLPC/tns2rTt1ZwPo0nL/jYBEIAsYTCWhfAnNnpoLKVh5Nm+fSU3OOwTTqU87UkGrFJhObD/wobQ==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-linux-x64-musl/-/css-inline-linux-x64-musl-0.13.0.tgz", + "integrity": "sha512-2tCnwU23W/yMs9cGc2/i2jd9y2pjuntx0a5OytqX7s9fvUtmI3nc0Od6wuf51LnmdU+XAU8HLT9pZppsQiwPfQ==", "cpu": [ "x64" ], @@ -2240,9 +2320,9 @@ } }, "node_modules/@css-inline/css-inline-win32-x64-msvc": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.14.1.tgz", - "integrity": "sha512-nzotGiaiuiQW78EzsiwsHZXbxEt6DiMUFcDJ6dhiliomXxnlaPyBfZb6/FMBgRJOf6sknDt/5695OttNmbMYzg==", + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@css-inline/css-inline-win32-x64-msvc/-/css-inline-win32-x64-msvc-0.13.0.tgz", + "integrity": "sha512-6VFhFSXp4FH+NzJhLd6fFi7jKCPvIRW+vq0tV+CPuiQ3zPzMfC9nIk8sB/1VJR8EcvBAjMV53YnacuDjRFRT9g==", "cpu": [ "x64" ], @@ -2358,74 +2438,6 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@fastify/ajv-compiler": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.2.tgz", - "integrity": "sha512-Rkiu/8wIjpsf46Rr+Fitd3HRP+VsxUFDDeag0hs9L0ksfnwx2g7SPQQTFL0E8Qv+rfXzQOxBJnjUB9ITUDjfWQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "fast-uri": "^3.0.0" - } - }, - "node_modules/@fastify/ajv-compiler/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@fastify/ajv-compiler/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/@fastify/ajv-compiler/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/@fastify/cors": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-9.0.1.tgz", @@ -2442,27 +2454,6 @@ "integrity": "sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==", "license": "MIT" }, - "node_modules/@fastify/fast-json-stringify-compiler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz", - "integrity": "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "fast-json-stringify": "^6.0.0" - } - }, "node_modules/@fastify/formbody": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@fastify/formbody/-/formbody-7.4.0.tgz", @@ -2472,35 +2463,6 @@ "fastify-plugin": "^4.0.0" } }, - "node_modules/@fastify/forwarded": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.0.tgz", - "integrity": "sha512-kJExsp4JCms7ipzg7SJ3y8DwmePaELHxKYtg+tZow+k0znUTf3cb+npgyqm8+ATZOdmfgfydIebPDWM172wfyA==", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/@fastify/merge-json-schemas": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz", - "integrity": "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, "node_modules/@fastify/middie": { "version": "8.3.3", "resolved": "https://registry.npmjs.org/@fastify/middie/-/middie-8.3.3.tgz", @@ -2519,29 +2481,6 @@ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "license": "MIT" }, - "node_modules/@fastify/proxy-addr": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.0.0.tgz", - "integrity": "sha512-37qVVA1qZ5sgH7KpHkkC4z9SK6StIsIcOmpjvMPXNb3vx2GQxhZocogVYbr2PbbeLCQxYIPDok307xEvRZOzGA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@fastify/forwarded": "^3.0.0", - "ipaddr.js": "^2.1.0" - } - }, - "node_modules/@fastify/proxy-addr/node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 10" - } - }, "node_modules/@fraybabak/kavenegar_nest": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@fraybabak/kavenegar_nest/-/kavenegar_nest-1.0.5.tgz", @@ -3181,6 +3120,413 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core/node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/@inquirer/core/node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor/node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -3716,9 +4062,9 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", "dev": true, "license": "MIT", "dependencies": { @@ -3727,9 +4073,10 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -3741,19 +4088,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@ljharb/through": { - "version": "2.3.13", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", - "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/@lukeed/csprng": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", @@ -3819,60 +4153,67 @@ } }, "node_modules/@nestjs-modules/mailer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-2.0.2.tgz", - "integrity": "sha512-+z4mADQasg0H1ZaGu4zZTuKv2pu+XdErqx99PLFPzCDNTN/q9U59WPgkxVaHnsvKHNopLj5Xap7G4ZpptduoYw==", + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@nestjs-modules/mailer/-/mailer-1.11.2.tgz", + "integrity": "sha512-k07wyKbtCzxWMm6IqGwcGIisnXD/6sneGvUR8rBBZbxtLn1HE1FLGyiaXBrPui/0K7W41aS9x9jAIhfTawtlUg==", "license": "MIT", "dependencies": { - "@css-inline/css-inline": "0.14.1", - "glob": "10.3.12" + "@css-inline/css-inline": "0.13.0", + "glob": "10.3.10", + "mjml": "4.15.3", + "preview-email": "3.0.19" }, "optionalDependencies": { "@types/ejs": "^3.1.5", - "@types/mjml": "^4.7.4", "@types/pug": "^2.0.10", - "ejs": "^3.1.10", + "ejs": "^3.1.9", "handlebars": "^4.7.8", - "liquidjs": "^10.11.1", - "mjml": "^4.15.3", - "preview-email": "^3.0.19", "pug": "^3.0.2" }, "peerDependencies": { "@nestjs/common": ">=7.0.9", "@nestjs/core": ">=7.0.9", "@types/ejs": ">=3.0.3", - "@types/mjml": ">=4.7.4", "@types/pug": ">=2.0.6", "ejs": ">=3.1.2", "handlebars": ">=4.7.6", - "liquidjs": ">=10.8.2", - "mjml": ">=4.15.3", "nodemailer": ">=6.4.6", - "preview-email": ">=3.0.19", "pug": ">=3.0.1" } }, + "node_modules/@nestjs-modules/mailer/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/@nestjs-modules/mailer/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/@nestjs-modules/mailer/node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", + "jackspeak": "^2.3.5", "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" }, "bin": { "glob": "dist/esm/bin.mjs" @@ -3885,12 +4226,12 @@ } }, "node_modules/@nestjs-modules/mailer/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.7.tgz", + "integrity": "sha512-MOwgjc8tfrpn5QQEvjijjmDVtMw2oL88ugTevzxQnzRLm6l3fVEF2gzU0kYeYYKD8C66+IdGX6peJ4MyUlUnPg==", "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -3911,40 +4252,39 @@ } }, "node_modules/@nestjs/cli": { - "version": "10.4.9", - "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.4.9.tgz", - "integrity": "sha512-s8qYd97bggqeK7Op3iD49X2MpFtW4LVNLAwXFkfbRxKME6IYT7X0muNTJ2+QfI8hpbNx9isWkrLWIp+g5FOhiA==", + "version": "11.0.16", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-11.0.16.tgz", + "integrity": "sha512-P0H+Vcjki6P5160E5QnMt3Q0X5FTg4PZkP99Ig4lm/4JWqfw32j3EXv3YBTJ2DmxLwOQ/IS9F7dzKpMAgzKTGg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "17.3.11", - "@angular-devkit/schematics": "17.3.11", - "@angular-devkit/schematics-cli": "17.3.11", - "@nestjs/schematics": "^10.0.1", - "chalk": "4.1.2", - "chokidar": "3.6.0", + "@angular-devkit/core": "19.2.19", + "@angular-devkit/schematics": "19.2.19", + "@angular-devkit/schematics-cli": "19.2.19", + "@inquirer/prompts": "7.10.1", + "@nestjs/schematics": "^11.0.1", + "ansis": "4.2.0", + "chokidar": "4.0.3", "cli-table3": "0.6.5", "commander": "4.1.1", - "fork-ts-checker-webpack-plugin": "9.0.2", - "glob": "10.4.5", - "inquirer": "8.2.6", + "fork-ts-checker-webpack-plugin": "9.1.0", + "glob": "13.0.0", "node-emoji": "1.11.0", "ora": "5.4.1", - "tree-kill": "1.2.2", "tsconfig-paths": "4.2.0", "tsconfig-paths-webpack-plugin": "4.2.0", - "typescript": "5.7.2", - "webpack": "5.97.1", + "typescript": "5.9.3", + "webpack": "5.104.1", "webpack-node-externals": "3.0.0" }, "bin": { "nest": "bin/nest.js" }, "engines": { - "node": ">= 16.14" + "node": ">= 20.11" }, "peerDependencies": { - "@swc/cli": "^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0", + "@swc/cli": "^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0", "@swc/core": "^1.3.62" }, "peerDependenciesMeta": { @@ -3956,73 +4296,322 @@ } } }, - "node_modules/@nestjs/cli/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@nestjs/cli/node_modules/@angular-devkit/core": { + "version": "19.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.19.tgz", + "integrity": "sha512-JbLL+4IMLMBgjLZlnPG4lYDfz4zGrJ/s6Aoon321NJKuw1Kb1k5KpFu9dUY0BqLIe8xPQ2UJBpI+xXdK5MXMHQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@nestjs/cli/node_modules/@angular-devkit/schematics": { + "version": "19.2.19", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.19.tgz", + "integrity": "sha512-J4Jarr0SohdrHcb40gTL4wGPCQ952IMWF1G/MSAQfBAPvA9ZKApYhpxcY7PmehVePve+ujpus1dGsJ7dPxz8Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.19", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.17", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@nestjs/cli/node_modules/@nestjs/schematics": { + "version": "11.0.9", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-11.0.9.tgz", + "integrity": "sha512-0NfPbPlEaGwIT8/TCThxLzrlz3yzDNkfRNpbL7FiplKq3w4qXpJg0JYwqgMEJnLQZm3L/L/5XjoyfJHUO3qX9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.17", + "@angular-devkit/schematics": "19.2.17", + "comment-json": "4.4.1", + "jsonc-parser": "3.3.1", + "pluralize": "8.0.0" + }, + "peerDependencies": { + "typescript": ">=4.8.2" + } + }, + "node_modules/@nestjs/cli/node_modules/@nestjs/schematics/node_modules/@angular-devkit/core": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-19.2.17.tgz", + "integrity": "sha512-Ah008x2RJkd0F+NLKqIpA34/vUGwjlprRCkvddjDopAWRzYn6xCkz1Tqwuhn0nR1Dy47wTLKYD999TYl5ONOAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.17.1", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.2", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@nestjs/cli/node_modules/@nestjs/schematics/node_modules/@angular-devkit/schematics": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-19.2.17.tgz", + "integrity": "sha512-ADfbaBsrG8mBF6Mfs+crKA/2ykB8AJI50Cv9tKmZfwcUcyAdmTr+vVvhsBCfvUAEokigSsgqgpYxfkJVxhJYeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "19.2.17", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.17", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@nestjs/cli/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@nestjs/cli/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@nestjs/cli/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@nestjs/cli/node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@nestjs/cli/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nestjs/cli/node_modules/comment-json": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.4.1.tgz", + "integrity": "sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/@nestjs/cli/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@nestjs/cli/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.0.tgz", + "integrity": "sha512-tvZgpqk6fz4BaNZ66ZsRaZnbHvP/jG3uKJvAZOwEVUL4RTA5nJeeLYfyN9/VA8NX/V3IBG+hkeuGpKjvELkVhA==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/cliui": "^8.0.2" + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/@nestjs/cli/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nestjs/cli/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@nestjs/cli/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@nestjs/cli/node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/@nestjs/cli/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", + "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^5.0.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@nestjs/cli/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@nestjs/cli/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@nestjs/cli/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nestjs/cli/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.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4670,19 +5259,19 @@ "license": "MIT" }, "node_modules/@nestjs/serve-static": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@nestjs/serve-static/-/serve-static-5.0.3.tgz", - "integrity": "sha512-0jFjTlSVSLrI+mot8lfm+h2laXtKzCvgsVStv9T1ZBZTDwS26gM5czIhIESmWAod0PfrbCDFiu9C1MglObL8VA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/serve-static/-/serve-static-4.0.2.tgz", + "integrity": "sha512-cT0vdWN5ar7jDI2NKbhf4LcwJzU4vS5sVpMkVrHuyLcltbrz6JdGi1TfIMMatP2pNiq5Ie/uUdPSFDVaZX/URQ==", "license": "MIT", "dependencies": { - "path-to-regexp": "8.2.0" + "path-to-regexp": "0.2.5" }, "peerDependencies": { - "@fastify/static": "^8.0.4", - "@nestjs/common": "^11.0.2", - "@nestjs/core": "^11.0.2", - "express": "^5.0.1", - "fastify": "^5.2.1" + "@fastify/static": "^6.5.0 || ^7.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "express": "^4.18.1", + "fastify": "^4.7.0" }, "peerDependenciesMeta": { "@fastify/static": { @@ -4697,26 +5286,23 @@ } }, "node_modules/@nestjs/serve-static/node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "license": "MIT", - "engines": { - "node": ">=16" - } + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.2.5.tgz", + "integrity": "sha512-l6qtdDPIkmAmzEO6egquYDfqQGPMRNGjYtrU13HAXb3YSRrt7HSb1sJY0pKp6o2bAa86tSB6iwaW2JbthPKr7Q==", + "license": "MIT" }, "node_modules/@nestjs/swagger": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-8.1.1.tgz", - "integrity": "sha512-5Mda7H1DKnhKtlsb0C7PYshcvILv8UFyUotHzxmWh0G65Z21R3LZH/J8wmpnlzL4bmXIfr42YwbEwRxgzpJ5sQ==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.4.2.tgz", + "integrity": "sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ==", "license": "MIT", "dependencies": { "@microsoft/tsdoc": "^0.15.0", - "@nestjs/mapped-types": "2.0.6", + "@nestjs/mapped-types": "2.0.5", "js-yaml": "4.1.0", "lodash": "4.17.21", "path-to-regexp": "3.3.0", - "swagger-ui-dist": "5.18.2" + "swagger-ui-dist": "5.17.14" }, "peerDependencies": { "@fastify/static": "^6.0.0 || ^7.0.0", @@ -4738,6 +5324,26 @@ } } }, + "node_modules/@nestjs/swagger/node_modules/@nestjs/mapped-types": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz", + "integrity": "sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==", + "license": "MIT", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/swagger/node_modules/path-to-regexp": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-3.3.0.tgz", @@ -4865,8 +5471,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", @@ -4891,18 +5496,10 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/@scarf/scarf": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", - "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", - "hasInstallScript": true, - "license": "Apache-2.0" - }, "node_modules/@selderee/plugin-htmlparser2": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", - "optional": true, "dependencies": { "domhandler": "^5.0.3", "selderee": "^0.11.0" @@ -5093,9 +5690,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/express": { @@ -5214,23 +5811,6 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, - "node_modules/@types/mjml": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.7.4.tgz", - "integrity": "sha512-vyi1vzWgMzFMwZY7GSZYX0GU0dmtC8vLHwpgk+NWmwbwRSrlieVyJ9sn5elodwUfklJM7yGl0zQeet1brKTWaQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/mjml-core": "*" - } - }, - "node_modules/@types/mjml-core": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@types/mjml-core/-/mjml-core-4.15.1.tgz", - "integrity": "sha512-qu8dUksU8yXX18qMTFINkM4uoz7WQYC5F14lcWeSNmWbulaGG0KG19yeZwpx75b9RJXr8WI/FRHH0LyQTU9JbA==", - "license": "MIT", - "optional": true - }, "node_modules/@types/multer": { "version": "1.4.12", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.12.tgz", @@ -5832,9 +6412,9 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -5843,6 +6423,19 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -5941,7 +6534,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/alce/-/alce-1.2.0.tgz", "integrity": "sha512-XppPf2S42nO2WhvKzlwzlfcApcXHzjlod30pKmcWjRgLOtqoe5DMuqdiYoM6AgyXksc6A6pV4v1L/WW217e57w==", - "optional": true, "dependencies": { "esprima": "^1.2.0", "estraverse": "^1.5.0" @@ -5954,7 +6546,6 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz", "integrity": "sha512-S9VbPDU0adFErpDai3qDkjq8+G05ONtKzcyNrPKg/ZKa+tf879nX2KexNU95b31UoTJjRLInNBHHHjFPoCd7lQ==", - "optional": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -5967,7 +6558,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -5976,7 +6566,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -6029,11 +6618,20 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", + "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "devOptional": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6277,15 +6875,13 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "devOptional": true + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/assert-never": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/assert-never/-/assert-never-1.4.0.tgz", "integrity": "sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/async": { "version": "3.2.6", @@ -6332,36 +6928,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/avvio": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-9.1.0.tgz", - "integrity": "sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@fastify/error": "^4.0.0", - "fastq": "^1.17.1" - } - }, - "node_modules/avvio/node_modules/@fastify/error": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.1.0.tgz", - "integrity": "sha512-KeFcciOr1eo/YvIXHP65S94jfEEqn1RxTRBT1aJaHxY5FK0/GDXYozsQMMWlZoHgi8i0s+YtrLsgj/JkUUjSkQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/axios": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", @@ -6548,7 +7114,6 @@ "resolved": "https://registry.npmjs.org/babel-walk/-/babel-walk-3.0.0-canary-5.tgz", "integrity": "sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/types": "^7.9.6" }, @@ -6589,6 +7154,18 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -6622,7 +7199,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "devOptional": true, "engines": { "node": ">=8" } @@ -6693,8 +7269,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -6709,7 +7284,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "devOptional": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -6719,9 +7293,9 @@ } }, "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "funding": [ { "type": "opencollective", @@ -6738,10 +7312,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" @@ -6903,7 +7478,6 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", "license": "MIT", - "optional": true, "dependencies": { "no-case": "^2.2.0", "upper-case": "^1.1.1" @@ -6920,9 +7494,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001696", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001696.tgz", - "integrity": "sha512-pDCPkvzfa39ehJtJ+OwGT/2yvT2SbjfHhiIW2LWOAcMQ7BzwxT/XuyUp4OTOd0XFWA6BKw0JalnBHgSi5DGJBQ==", + "version": "1.0.30001774", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", + "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", "funding": [ { "type": "opencollective", @@ -6968,7 +7542,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", "integrity": "sha512-+UqJQjFEFaTAs3bNsF2j2kEN1baG/zghZbdqoYEDxGZtJo9LBzl1A+m0D4n3qKx8N2FNv8/Xp6yV9mQmBuptaw==", - "optional": true, "dependencies": { "is-regex": "^1.0.3" } @@ -6983,7 +7556,6 @@ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", "license": "MIT", - "optional": true, "dependencies": { "cheerio-select": "^2.1.0", "dom-serializer": "^2.0.0", @@ -7005,7 +7577,6 @@ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", "license": "BSD-2-Clause", - "optional": true, "dependencies": { "boolbase": "^1.0.0", "css-select": "^5.1.0", @@ -7022,7 +7593,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "devOptional": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -7065,7 +7635,6 @@ "version": "3.8.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "devOptional": true, "funding": [ { "type": "github", @@ -7103,7 +7672,6 @@ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", "license": "MIT", - "optional": true, "dependencies": { "source-map": "~0.6.0" }, @@ -7116,7 +7684,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "license": "BSD-3-Clause", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -7316,7 +7883,6 @@ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "license": "MIT", - "optional": true, "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -7336,7 +7902,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-4.0.1.tgz", "integrity": "sha512-vCrqcSIq4//Gx74TXXCGnHpulY1dskqLTFGDmhrGxzeXL8lF8kvXv6mpNWlJj1uD4DW23D4ljAqbY4RRaaUZIw==", - "optional": true, "dependencies": { "@babel/parser": "^7.6.0", "@babel/types": "^7.6.1" @@ -7508,7 +8073,6 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "license": "BSD-2-Clause", - "optional": true, "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -7525,7 +8089,6 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "license": "BSD-2-Clause", - "optional": true, "engines": { "node": ">= 6" }, @@ -7619,7 +8182,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "optional": true, "engines": { "node": ">=4.0.0" } @@ -7633,7 +8195,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==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -7704,17 +8265,6 @@ "node": ">= 0.8" } }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/destroy": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", @@ -7729,7 +8279,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", - "optional": true, "engines": { "node": ">=8" } @@ -7746,7 +8295,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "devOptional": true, "engines": { "node": ">=8" } @@ -7755,8 +8303,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/dezalgo": { "version": "1.0.4", @@ -7805,7 +8352,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/display-notification/-/display-notification-2.0.0.tgz", "integrity": "sha512-TdmtlAcdqy1NU+j7zlkDdMnCL878zriLaBmoD9quOoq1ySSSGv03l0hXK5CvIFZlIfFI/hizqdQuW+Num7xuhw==", - "optional": true, "dependencies": { "escape-string-applescript": "^1.0.0", "run-applescript": "^3.0.0" @@ -7830,14 +8376,12 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", "integrity": "sha512-LLBi6pEqS6Do3EKQ3J0NqHWV5hhb78Pi8vvESYwyOy2c31ZEZVdtitdzsQsKb7878PEERhzUk0ftqGhG6Mz+pQ==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "optional": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -7856,14 +8400,12 @@ "type": "github", "url": "https://github.com/sponsors/fb55" } - ], - "optional": true + ] }, "node_modules/domhandler": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "optional": true, "dependencies": { "domelementtype": "^2.3.0" }, @@ -7878,7 +8420,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "optional": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -7933,7 +8474,6 @@ "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", "license": "MIT", - "optional": true, "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", @@ -7952,7 +8492,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -7962,7 +8501,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "license": "MIT", - "optional": true, "engines": { "node": ">=14" } @@ -7972,7 +8510,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -8005,9 +8542,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.90", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.90.tgz", - "integrity": "sha512-C3PN4aydfW91Natdyd449Kw+BzhLmof6tzy5W1pFC5SpQxVXT+oyiyOG9AgYYSN9OdA/ik3YkCrpwqI8ug5Tug==", + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", "license": "ISC" }, "node_modules/emittery": { @@ -8043,7 +8580,6 @@ "resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz", "integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==", "license": "MIT", - "optional": true, "engines": { "node": ">=8.10.0" } @@ -8104,7 +8640,6 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "optional": true, "engines": { "node": ">=0.12" }, @@ -8235,9 +8770,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", "dev": true, "license": "MIT" }, @@ -8307,7 +8842,6 @@ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", "license": "MIT", - "optional": true, "engines": { "node": ">=10" }, @@ -8324,7 +8858,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/escape-string-applescript/-/escape-string-applescript-1.0.0.tgz", "integrity": "sha512-4/hFwoYaC6TkpDn9A3pTC52zQPArFeXuIfhUtCGYdauTzXVP9H3BDr3oO/QzQehMpLDC7srvYgfwvImPFGfvBA==", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -9142,43 +9675,45 @@ } }, "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" }, "engines": { - "node": ">= 18" + "node": ">= 0.10.0" }, "funding": { "type": "opencollective", @@ -9193,96 +9728,22 @@ "basic-auth": "^2.0.1" } }, - "node_modules/express/node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.0", - "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/express/node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/express/node_modules/cookie": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", - "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.6" } }, - "node_modules/express/node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=6.6.0" - } - }, "node_modules/express/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "ms": "2.0.0" } }, "node_modules/express/node_modules/encodeurl": { @@ -9290,113 +9751,36 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/express/node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.8" } }, "node_modules/express/node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=18" - }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/express/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/express/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true, - "peer": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/express/node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.6" - } + "node_modules/express/node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" }, "node_modules/express/node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "license": "BSD-3-Clause", - "optional": true, - "peer": true, "dependencies": { "side-channel": "^1.1.0" }, @@ -9407,44 +9791,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/express/node_modules/raw-body": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", - "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.6.3", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/extend-object": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", - "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==", - "optional": true + "integrity": "sha512-0dHDIXC7y7LDmCh/lp1oYkmv73K25AMugQI07r8eFopkW6f7Ufn1q+ETMsJjnV9Am14SlElkqy3O92r6xEaxPw==" }, "node_modules/external-editor": { "version": "3.1.0", @@ -9503,77 +9853,6 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, - "node_modules/fast-json-stringify": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.0.1.tgz", - "integrity": "sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@fastify/merge-json-schemas": "^0.2.0", - "ajv": "^8.12.0", - "ajv-formats": "^3.0.1", - "fast-uri": "^3.0.0", - "json-schema-ref-resolver": "^2.0.0", - "rfdc": "^1.2.0" - } - }, - "node_modules/fast-json-stringify/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/fast-json-stringify/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/fast-json-stringify/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", @@ -9625,64 +9904,11 @@ "node": ">= 4.9.1" } }, - "node_modules/fastify": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-5.3.2.tgz", - "integrity": "sha512-AIPqBgtqBAwkOkrnwesEE+dOyU30dQ4kh7udxeGVR05CRGwubZx+p2H8P0C4cRnQT0+EPK4VGea2DTL2RtWttg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@fastify/ajv-compiler": "^4.0.0", - "@fastify/error": "^4.0.0", - "@fastify/fast-json-stringify-compiler": "^5.0.0", - "@fastify/proxy-addr": "^5.0.0", - "abstract-logging": "^2.0.1", - "avvio": "^9.0.0", - "fast-json-stringify": "^6.0.0", - "find-my-way": "^9.0.0", - "light-my-request": "^6.0.0", - "pino": "^9.0.0", - "process-warning": "^5.0.0", - "rfdc": "^1.3.1", - "secure-json-parse": "^4.0.0", - "semver": "^7.6.0", - "toad-cache": "^3.7.0" - } - }, "node_modules/fastify-plugin": { "version": "4.5.1", "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.1.tgz", "integrity": "sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==" }, - "node_modules/fastify/node_modules/@fastify/error": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.1.0.tgz", - "integrity": "sha512-KeFcciOr1eo/YvIXHP65S94jfEEqn1RxTRBT1aJaHxY5FK0/GDXYozsQMMWlZoHgi8i0s+YtrLsgj/JkUUjSkQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/fastq": { "version": "1.19.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz", @@ -9773,7 +9999,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "devOptional": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -9783,41 +10008,30 @@ } }, "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, "node_modules/finalhandler/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/encodeurl": { @@ -9825,34 +10039,23 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.8" } }, "node_modules/finalhandler/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true, - "peer": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, - "node_modules/find-my-way": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.3.0.tgz", - "integrity": "sha512-eRoFWQw+Yv2tuYlK2pjFS2jGXSxSppAs3hSQjfxVKxM5amECzIgYYc1FEI8ZmhSh/Ig+FrKEz43NLRKJjYCZVg==", + "node_modules/finalhandler/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-querystring": "^1.0.0", - "safe-regex2": "^5.0.0" - }, "engines": { - "node": ">=20" + "node": ">= 0.8" } }, "node_modules/find-up": { @@ -9874,7 +10077,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/fixpack/-/fixpack-4.0.0.tgz", "integrity": "sha512-5SM1+H2CcuJ3gGEwTiVo/+nd/hYpNj9Ch3iMDOQ58ndY+VGQ2QdvaUTkd3otjZvYnd/8LF/HkJ5cx7PBq0orCQ==", - "optional": true, "dependencies": { "alce": "1.2.0", "chalk": "^3.0.0", @@ -9891,7 +10093,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "optional": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9983,15 +10184,15 @@ } }, "node_modules/fork-ts-checker-webpack-plugin": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", - "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.1.0.tgz", + "integrity": "sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.7", "chalk": "^4.1.2", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "cosmiconfig": "^8.2.0", "deepmerge": "^4.2.2", "fs-extra": "^10.0.0", @@ -10003,14 +10204,43 @@ "tapable": "^2.2.1" }, "engines": { - "node": ">=12.13.0", - "yarn": ">=1.0.0" + "node": ">=14.21.3" }, "peerDependencies": { "typescript": ">3.6.0", "webpack": "^5.11.0" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/form-data": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", @@ -10100,9 +10330,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/fs-monkey": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", - "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", "dev": true, "license": "Unlicense" }, @@ -10120,7 +10350,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -10240,7 +10469,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", - "optional": true, "engines": { "node": ">=8" }, @@ -10325,7 +10553,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -10545,7 +10772,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "optional": true, "bin": { "he": "bin/he" } @@ -10572,7 +10798,6 @@ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", "license": "MIT", - "optional": true, "dependencies": { "camel-case": "^3.0.0", "clean-css": "^4.2.1", @@ -10593,14 +10818,12 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/html-to-text": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", - "optional": true, "dependencies": { "@selderee/plugin-htmlparser2": "^0.11.0", "deepmerge": "^4.3.1", @@ -10623,7 +10846,6 @@ "url": "https://github.com/sponsors/fb55" } ], - "optional": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -10769,8 +10991,7 @@ "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "optional": true + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/inquirer": { "version": "8.2.6", @@ -10879,7 +11100,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "devOptional": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -10963,7 +11183,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "optional": true, "bin": { "is-docker": "cli.js" }, @@ -10978,7 +11197,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-4.0.0.tgz", "integrity": "sha512-zMIXX63sxzG3XrkHkrAPvm/OVZVSCPNkwMHU8oTX7/U3AL78I0QXCEICXUM13BIa8TYGZ68PiTKfQz3yaTNr4A==", - "optional": true, "dependencies": { "acorn": "^7.1.1", "object-assign": "^4.1.1" @@ -10988,7 +11206,6 @@ "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "optional": true, "bin": { "acorn": "bin/acorn" }, @@ -11090,7 +11307,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -11124,8 +11340,7 @@ "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", - "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", - "optional": true + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" }, "node_modules/is-regex": { "version": "1.2.1", @@ -11291,7 +11506,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "optional": true, "dependencies": { "is-docker": "^2.0.0" }, @@ -12081,7 +12295,6 @@ "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.1.tgz", "integrity": "sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==", "license": "MIT", - "optional": true, "dependencies": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", @@ -12103,7 +12316,6 @@ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", "license": "ISC", - "optional": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -12113,7 +12325,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -12123,7 +12334,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "license": "ISC", - "optional": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -12144,7 +12354,6 @@ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "license": "BlueOak-1.0.0", - "optional": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -12160,7 +12369,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -12176,7 +12384,6 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "license": "ISC", - "optional": true, "dependencies": { "abbrev": "^2.0.0" }, @@ -12192,7 +12399,6 @@ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", "license": "MIT", - "optional": true, "engines": { "node": ">=14" } @@ -12201,8 +12407,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", "integrity": "sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/js-tokens": { "version": "4.0.0", @@ -12250,27 +12455,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-schema-ref-resolver": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-2.0.1.tgz", - "integrity": "sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -12301,9 +12485,9 @@ "license": "MIT" }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", "dependencies": { @@ -12339,7 +12523,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", "integrity": "sha512-C9YK3Rf8q6VAPDCCU9fnqo3mAfOH6vUGnMcP4AQAYIEpWtfGLpwOTmZ+igtdK5y+VvI2n3CyYSzy4Qh34eq24A==", - "optional": true, "dependencies": { "is-promise": "^2.0.0", "promise": "^7.0.1" @@ -12364,7 +12547,6 @@ "resolved": "https://registry.npmjs.org/juice/-/juice-10.0.1.tgz", "integrity": "sha512-ZhJT1soxJCkOiO55/mz8yeBKTAJhRzX9WBO+16ZTqNTONnnVlUPyVBIzQ7lDRjaBdTbid+bAnyIon/GM3yp4cA==", "license": "MIT", - "optional": true, "dependencies": { "cheerio": "1.0.0-rc.12", "commander": "^6.1.0", @@ -12384,7 +12566,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "license": "MIT", - "optional": true, "engines": { "node": ">= 6" } @@ -12445,7 +12626,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", - "optional": true, "funding": { "url": "https://ko-fi.com/killymxi" } @@ -12476,15 +12656,13 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz", "integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/libmime": { "version": "5.3.6", "resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.6.tgz", "integrity": "sha512-j9mBC7eiqi6fgBPAGvKCXJKJSIASanYF4EeA4iBzSG0HxQxmXnR3KbyWqTn4CwsKSebqCv2f5XZfAO6sKzgvwA==", "license": "MIT", - "optional": true, "dependencies": { "encoding-japanese": "2.2.0", "iconv-lite": "0.6.3", @@ -12497,7 +12675,6 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -12514,8 +12691,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz", "integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/light-my-request": { "version": "6.3.0", @@ -12565,42 +12741,10 @@ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "license": "MIT", - "optional": true, "dependencies": { "uc.micro": "^2.0.0" } }, - "node_modules/liquidjs": { - "version": "10.20.2", - "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.20.2.tgz", - "integrity": "sha512-MbAueOtO8aH+GzC/kmhcJTiMrMu+MVel/3+yhFVmP3K89WP0ZuvVPi8ZRKCHAO6SLJvV0Y0Jz6tUEy6Hg8xO/g==", - "license": "MIT", - "optional": true, - "dependencies": { - "commander": "^10.0.0" - }, - "bin": { - "liquid": "bin/liquid.js", - "liquidjs": "bin/liquid.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/liquidjs" - } - }, - "node_modules/liquidjs/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/load-json-file": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", @@ -12645,13 +12789,17 @@ } }, "node_modules/loader-runner": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", "dev": true, "license": "MIT", "engines": { "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/locate-path": { @@ -12771,8 +12919,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/lru-cache": { "version": "5.1.1", @@ -12809,7 +12956,6 @@ "resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.2.tgz", "integrity": "sha512-iI0p2TCcIodR1qGiRoDBBwboSSff50vQAWytM5JRggLfABa4hHYCf3YVujtuzV454xrOP352VsAPIzviqMTo4Q==", "license": "MIT", - "optional": true, "dependencies": { "encoding-japanese": "2.2.0", "he": "1.2.0", @@ -12827,7 +12973,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -12840,7 +12985,6 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz", "integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==", "license": "MIT-0", - "optional": true, "engines": { "node": ">=6.0.0" } @@ -12850,7 +12994,6 @@ "resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz", "integrity": "sha512-4cczG/3Iu3pyl8JgQ76dKkisurZTmxMrA4dj/e8d2jKYcFTZ7MxOzg1gTioTDMPuFXwTrVuN/gxhkrO7wLg7qA==", "license": "(MIT OR EUPL-1.1+)", - "optional": true, "dependencies": { "libbase64": "1.3.0", "libmime": "5.3.6", @@ -12929,8 +13072,7 @@ "version": "0.3.4", "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/merge-descriptors": { "version": "1.0.1", @@ -13077,7 +13219,6 @@ "resolved": "https://registry.npmjs.org/mjml/-/mjml-4.15.3.tgz", "integrity": "sha512-bW2WpJxm6HS+S3Yu6tq1DUPFoTxU9sPviUSmnL7Ua+oVO3WA5ILFWqvujUlz+oeuM+HCwEyMiP5xvKNPENVjYA==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "mjml-cli": "4.15.3", @@ -13095,7 +13236,6 @@ "resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.15.3.tgz", "integrity": "sha512-LPNVSj1LyUVYT9G1gWwSw3GSuDzDsQCu0tPB2uDsq4VesYNnU6v3iLCQidMiR6azmIt13OEozG700ygAUuA6Ng==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13107,7 +13247,6 @@ "resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.15.3.tgz", "integrity": "sha512-7pfUOVPtmb0wC+oUOn4xBsAw4eT5DyD6xqaxj/kssu6RrFXOXgJaVnDPAI9AzIvXJ/5as9QrqRGYAddehwWpHQ==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13119,7 +13258,6 @@ "resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.15.3.tgz", "integrity": "sha512-79qwn9AgdGjJR1vLnrcm2rq2AsAZkKC5JPwffTMG+Nja6zGYpTDZFZ56ekHWr/r1b5WxkukcPj2PdevUug8c+Q==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13131,7 +13269,6 @@ "resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.15.3.tgz", "integrity": "sha512-3ju6I4l7uUhPRrJfN3yK9AMsfHvrYbRkcJ1GRphFHzUj37B2J6qJOQUpzA547Y4aeh69TSb7HFVf1t12ejQxVw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13143,7 +13280,6 @@ "resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.15.3.tgz", "integrity": "sha512-+V2TDw3tXUVEptFvLSerz125C2ogYl8klIBRY1m5BHd4JvGVf3yhx8N3PngByCzA6PGcv/eydGQN+wy34SHf0Q==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "chokidar": "^3.0.0", @@ -13167,7 +13303,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "license": "MIT", - "optional": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -13177,7 +13312,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "license": "ISC", - "optional": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -13198,7 +13332,6 @@ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "license": "BlueOak-1.0.0", - "optional": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -13214,7 +13347,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "license": "ISC", - "optional": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -13230,7 +13362,6 @@ "resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.15.3.tgz", "integrity": "sha512-hYdEFdJGHPbZJSEysykrevEbB07yhJGSwfDZEYDSbhQQFjV2tXrEgYcFD5EneMaowjb55e3divSJxU4c5q4Qgw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13242,7 +13373,6 @@ "resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.15.3.tgz", "integrity": "sha512-Dmwk+2cgSD9L9GmTbEUNd8QxkTZtW9P7FN/ROZW/fGZD6Hq6/4TB0zEspg2Ow9eYjZXO2ofOJ3PaQEEShKV0kQ==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "cheerio": "1.0.0-rc.12", @@ -13261,7 +13391,6 @@ "resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.15.3.tgz", "integrity": "sha512-vh27LQ9FG/01y0b9ntfqm+GT5AjJnDSDY9hilss2ixIUh0FemvfGRfsGVeV5UBVPBKK7Ffhvfqc7Rciob9Spzw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13273,7 +13402,6 @@ "resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.15.3.tgz", "integrity": "sha512-HSu/rKnGZVKFq3ciT46vi1EOy+9mkB0HewO4+P6dP/Y0UerWkN6S3UK11Cxsj0cAp0vFwkPDCdOeEzRdpFEkzA==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13285,7 +13413,6 @@ "resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.15.3.tgz", "integrity": "sha512-o3mRuuP/MB5fZycjD3KH/uXsnaPl7Oo8GtdbJTKtH1+O/3pz8GzGMkscTKa97l03DAG2EhGrzzLcU2A6eshwFw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13297,7 +13424,6 @@ "resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.15.3.tgz", "integrity": "sha512-2ISo0r5ZKwkrvJgDou9xVPxxtXMaETe2AsAA02L89LnbB2KC0N5myNsHV0sEysTw9+CfCmgjAb0GAI5QGpxKkQ==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13309,7 +13435,6 @@ "resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.15.3.tgz", "integrity": "sha512-Eo56FA5C2v6ucmWQL/JBJ2z641pLOom4k0wP6CMZI2utfyiJ+e2Uuinj1KTrgDcEvW4EtU9HrfAqLK9UosLZlg==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13321,7 +13446,6 @@ "resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.15.3.tgz", "integrity": "sha512-CzV2aDPpiNIIgGPHNcBhgyedKY4SX3BJoTwOobSwZVIlEA6TAWB4Z9WwFUmQqZOgo1AkkiTHPZQvGcEhFFXH6g==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13333,7 +13457,6 @@ "resolved": "https://registry.npmjs.org/mjml-head-html-attributes/-/mjml-head-html-attributes-4.15.3.tgz", "integrity": "sha512-MDNDPMBOgXUZYdxhosyrA2kudiGO8aogT0/cODyi2Ed9o/1S7W+je11JUYskQbncqhWKGxNyaP4VWa+6+vUC/g==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13345,7 +13468,6 @@ "resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.15.3.tgz", "integrity": "sha512-J2PxCefUVeFwsAExhrKo4lwxDevc5aKj888HBl/wN4EuWOoOg06iOGCxz4Omd8dqyFsrqvbBuPqRzQ+VycGmaA==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13357,7 +13479,6 @@ "resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.15.3.tgz", "integrity": "sha512-9J+JuH+mKrQU65CaJ4KZegACUgNIlYmWQYx3VOBR/tyz+8kDYX7xBhKJCjQ1I4wj2Tvga3bykd89Oc2kFZ5WOw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13369,7 +13490,6 @@ "resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.15.3.tgz", "integrity": "sha512-IM59xRtsxID4DubQ0iLmoCGXguEe+9BFG4z6y2xQDrscIa4QY3KlfqgKGT69ojW+AVbXXJPEVqrAi4/eCsLItQ==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13381,7 +13501,6 @@ "resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.15.3.tgz", "integrity": "sha512-9cLAPuc69yiuzNrMZIN58j+HMK1UWPaq2i3/Fg2ZpimfcGFKRcPGCbEVh0v+Pb6/J0+kf8yIO0leH20opu3AyQ==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13393,7 +13512,6 @@ "resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.15.3.tgz", "integrity": "sha512-g1OhSdofIytE9qaOGdTPmRIp7JsCtgO0zbsn1Fk6wQh2gEL55Z40j/VoghslWAWTgT2OHFdBKnMvWtN6U5+d2Q==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13405,7 +13523,6 @@ "resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.15.3.tgz", "integrity": "sha512-sr/+35RdxZroNQVegjpfRHJ5hda9XCgaS4mK2FGO+Mb1IUevKfeEPII3F/cHDpNwFeYH3kAgyqQ22ClhGLWNBA==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "js-beautify": "^1.6.14", @@ -13423,7 +13540,6 @@ "resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.15.3.tgz", "integrity": "sha512-VsKH/Jdlf8Yu3y7GpzQV5n7JMdpqvZvTSpF6UQXL0PWOm7k6+LX+sCZimOfpHJ+wCaaybpxokjWZ71mxOoCWoA==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13435,7 +13551,6 @@ "resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.15.3.tgz", "integrity": "sha512-Tz0UX8/JVYICLjT+U8J1f/TFxIYVYjzZHeh4/Oyta0pLpRLeZlxEd71f3u3kdnulCKMP4i37pFRDmyLXAlEuLw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "detect-node": "2.1.0", @@ -13455,7 +13570,6 @@ } ], "license": "MIT", - "optional": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -13468,7 +13582,6 @@ "resolved": "https://registry.npmjs.org/mjml-preset-core/-/mjml-preset-core-4.15.3.tgz", "integrity": "sha512-1zZS8P4O0KweWUqNS655+oNnVMPQ1Rq1GaZq5S9JfwT1Vh/m516lSmiTW9oko6gGHytt5s6Yj6oOeu5Zm8FoLw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "mjml-accordion": "4.15.3", @@ -13503,7 +13616,6 @@ "resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.15.3.tgz", "integrity": "sha512-IGyHheOYyRchBLiAEgw3UM11kFNmBSMupu2BDdejC6ZiDhEAdG+tyERlsCwDPYtXanvFpGWULIu3XlsUPc+RZw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13515,7 +13627,6 @@ "resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.15.3.tgz", "integrity": "sha512-JfVPRXH++Hd933gmQfG8JXXCBCR6fIzC3DwiYycvanL/aW1cEQ2EnebUfQkt5QzlYjOkJEH+JpccAsq3ln6FZQ==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13527,7 +13638,6 @@ "resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.15.3.tgz", "integrity": "sha512-7sD5FXrESOxpT9Z4Oh36bS6u/geuUrMP1aCg2sjyAwbPcF1aWa2k9OcatQfpRf6pJEhUZ18y6/WBBXmMVmSzXg==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13539,7 +13649,6 @@ "resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.15.3.tgz", "integrity": "sha512-3B7Qj+17EgDdAtZ3NAdMyOwLTX1jfmJuY7gjyhS2HtcZAmppW+cxqHUBwCKfvSRgTQiccmEvtNxaQK+tfyrZqA==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13551,7 +13660,6 @@ "resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.15.3.tgz", "integrity": "sha512-FLx7DcRKTdKdcOCbMyBaeudeHaHpwPveRrBm6WyQe3LXx6FfdmOh59i71/16LFQMgBOD3N4/UJkzxLzlTJzMqQ==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13563,7 +13671,6 @@ "resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.15.3.tgz", "integrity": "sha512-+C0hxCmw9kg0XzT6vhE5mFkK6y225nC8UEQcN94K0fBCjPKkM+HqZMwGX205fzdGRi+Bxa55b/VhrIVwdv+8vw==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13575,7 +13682,6 @@ "resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.15.3.tgz", "integrity": "sha512-Xb72KdqRwjv/qM2rJpV22syyP2N3cRQ9VVDrN6u2FSzLq02buFNxmSPJ7CKhat3PrUNdVHU75KZwOf/tz4UEhA==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9" } @@ -13585,7 +13691,6 @@ "resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.15.3.tgz", "integrity": "sha512-ditsCijeHJrmBmObtJmQ18ddLxv5oPyMTdPU8Di8APOnD2zPk7Z4UAuJSl7HXB45oFiivr3MJf4koFzMUSZ6Gg==", "license": "MIT", - "optional": true, "dependencies": { "@babel/runtime": "^7.23.9", "lodash": "^4.17.21", @@ -13830,15 +13935,13 @@ "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "optional": true + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "node_modules/no-case": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", "license": "MIT", - "optional": true, "dependencies": { "lower-case": "^1.1.1" } @@ -13891,9 +13994,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "license": "MIT" }, "node_modules/nodemailer": { @@ -13923,7 +14026,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -13957,7 +14059,6 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "license": "BSD-2-Clause", - "optional": true, "dependencies": { "boolbase": "^1.0.0" }, @@ -14128,7 +14229,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "optional": true, "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -14207,7 +14307,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", - "optional": true, "dependencies": { "p-timeout": "^3.1.0" }, @@ -14222,7 +14321,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "optional": true, "engines": { "node": ">=4" } @@ -14259,7 +14357,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", - "optional": true, "dependencies": { "p-finally": "^1.0.0" }, @@ -14279,7 +14376,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.2.0.tgz", "integrity": "sha512-wpgERjNkLrBiFmkMEjuZJEWKKDrNfHCKA1OhyN1wg1FrLkULbviEy6py1AyJUgZ72YWFbZ38FIpnqvVqAlDUwA==", - "optional": true, "dependencies": { "p-timeout": "^3.0.0" }, @@ -14294,7 +14390,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "devOptional": true, "license": "BlueOak-1.0.0" }, "node_modules/param-case": { @@ -14302,7 +14397,6 @@ "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", "license": "MIT", - "optional": true, "dependencies": { "no-case": "^2.2.0" } @@ -14343,7 +14437,6 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "license": "MIT", - "optional": true, "dependencies": { "entities": "^4.5.0" }, @@ -14356,7 +14449,6 @@ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", "license": "MIT", - "optional": true, "dependencies": { "domhandler": "^5.0.3", "parse5": "^7.0.0" @@ -14369,7 +14461,6 @@ "version": "0.12.1", "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", - "optional": true, "dependencies": { "leac": "^0.6.0", "peberminta": "^0.9.0" @@ -14508,7 +14599,6 @@ "version": "0.9.0", "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", - "optional": true, "funding": { "url": "https://ko-fi.com/killymxi" } @@ -14523,7 +14613,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "devOptional": true, "engines": { "node": ">=8.6" }, @@ -14824,7 +14913,6 @@ "version": "3.0.19", "resolved": "https://registry.npmjs.org/preview-email/-/preview-email-3.0.19.tgz", "integrity": "sha512-DBS3Nir18YtKc8loYCCOGitmiaQ0vTdahPoiXxwNweJDpmVZo+w3tppufOhoK0m8skpRxT56llYLs3VrORnmNQ==", - "optional": true, "dependencies": { "ci-info": "^3.8.0", "display-notification": "2.0.0", @@ -14851,7 +14939,6 @@ "https://github.com/sponsors/ctavan" ], "license": "MIT", - "optional": true, "bin": { "uuid": "dist/bin/uuid" } @@ -14861,29 +14948,10 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "node_modules/process-warning": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "optional": true, "dependencies": { "asap": "~2.0.3" } @@ -14921,8 +14989,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "license": "ISC", - "optional": true + "license": "ISC" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -14947,7 +15014,6 @@ "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.3.tgz", "integrity": "sha512-uBi6kmc9f3SZ3PXxqcHiUZLmIXgfgWooKWXcwSGwQd2Zi5Rb0bT14+8CJjJgI8AB+nndLaNgHGrcc6bPIB665g==", "license": "MIT", - "optional": true, "dependencies": { "pug-code-gen": "^3.0.3", "pug-filters": "^4.0.0", @@ -14964,7 +15030,6 @@ "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-3.0.0.tgz", "integrity": "sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==", "license": "MIT", - "optional": true, "dependencies": { "constantinople": "^4.0.1", "js-stringify": "^1.0.2", @@ -14976,7 +15041,6 @@ "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-3.0.3.tgz", "integrity": "sha512-cYQg0JW0w32Ux+XTeZnBEeuWrAY7/HNE6TWnhiHGnnRYlCgyAUPoyh9KzCMa9WhcJlJ1AtQqpEYHc+vbCzA+Aw==", "license": "MIT", - "optional": true, "dependencies": { "constantinople": "^4.0.1", "doctypes": "^1.1.0", @@ -14992,14 +15056,12 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-2.1.0.tgz", "integrity": "sha512-lv7sU9e5Jk8IeUheHata6/UThZ7RK2jnaaNztxfPYUY+VxZyk/ePVaNZ/vwmH8WqGvDz3LrNYt/+gA55NDg6Pg==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/pug-filters": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-4.0.0.tgz", "integrity": "sha512-yeNFtq5Yxmfz0f9z2rMXGw/8/4i1cCFecw/Q7+D0V2DdtII5UvqE12VaZ2AY7ri6o5RNXiweGH79OCq+2RQU4A==", - "optional": true, "dependencies": { "constantinople": "^4.0.1", "jstransformer": "1.0.0", @@ -15012,7 +15074,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-5.0.1.tgz", "integrity": "sha512-0I6C62+keXlZPZkOJeVam9aBLVP2EnbeDw3An+k0/QlqdwH6rv8284nko14Na7c0TtqtogfWXcRoFE4O4Ff20w==", - "optional": true, "dependencies": { "character-parser": "^2.2.0", "is-expression": "^4.0.0", @@ -15023,7 +15084,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-4.0.0.tgz", "integrity": "sha512-gjD1yzp0yxbQqnzBAdlhbgoJL5qIFJw78juN1NpTLt/mfPJ5VgC4BvkoD3G23qKzJtIIXBbcCt6FioLSFLOHdw==", - "optional": true, "dependencies": { "pug-error": "^2.0.0", "pug-walk": "^2.0.0" @@ -15033,7 +15093,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-3.0.0.tgz", "integrity": "sha512-OCjTEnhLWZBvS4zni/WUMjH2YSUosnsmjGBB1An7CsKQarYSWQ0GCVyd4eQPMFJqZ8w9xgs01QdiZXKVjk92EQ==", - "optional": true, "dependencies": { "object-assign": "^4.1.1", "pug-walk": "^2.0.0" @@ -15043,7 +15102,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-6.0.0.tgz", "integrity": "sha512-ukiYM/9cH6Cml+AOl5kETtM9NR3WulyVP2y4HOU45DyMim1IeP/OOiyEWRr6qk5I5klpsBnbuHpwKmTx6WURnw==", - "optional": true, "dependencies": { "pug-error": "^2.0.0", "token-stream": "1.0.0" @@ -15053,14 +15111,12 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-3.0.1.tgz", "integrity": "sha512-L50zbvrQ35TkpHwv0G6aLSuueDRwc/97XdY8kL3tOT0FmhgG7UypU3VztfV/LATAvmUfYi4wNxSajhSAeNN+Kg==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/pug-strip-comments": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-2.0.0.tgz", "integrity": "sha512-zo8DsDpH7eTkPHCXFeAk1xZXJbyoTfdPlNR0bK7rpOMuhBYb0f5qUVCO1xlsitYd3w5FQTK7zpNVKb3rZoUrrQ==", - "optional": true, "dependencies": { "pug-error": "^2.0.0" } @@ -15068,8 +15124,7 @@ "node_modules/pug-walk": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-2.0.0.tgz", - "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", - "optional": true + "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==" }, "node_modules/punycode": { "version": "2.3.1", @@ -15085,7 +15140,6 @@ "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", "license": "MIT", - "optional": true, "engines": { "node": ">=6" } @@ -15185,7 +15239,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "optional": true, "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", @@ -15200,7 +15253,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -15234,7 +15286,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "devOptional": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -15379,7 +15430,6 @@ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", "license": "MIT", - "optional": true, "engines": { "node": ">= 0.10" } @@ -15481,17 +15531,6 @@ "node": ">=8" } }, - "node_modules/ret": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", - "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=10" - } - }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -15524,75 +15563,10 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/router/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/router/node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/router/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/router/node_modules/path-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=16" - } - }, "node_modules/run-applescript": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-3.2.0.tgz", "integrity": "sha512-Ep0RsvAjnRcBX1p5vogbaBdAGu/8j/ewpvGqnQYunnLd9SM0vWcPJewPKNnWFggf0hF0pwIgwV5XK7qQ7UZ8Qg==", - "optional": true, "dependencies": { "execa": "^0.10.0" }, @@ -15605,7 +15579,6 @@ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", "license": "MIT", - "optional": true, "dependencies": { "nice-try": "^1.0.4", "path-key": "^2.0.1", @@ -15621,7 +15594,6 @@ "version": "0.10.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", - "optional": true, "dependencies": { "cross-spawn": "^6.0.0", "get-stream": "^3.0.0", @@ -15639,7 +15611,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "optional": true, "engines": { "node": ">=4" } @@ -15648,7 +15619,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -15657,7 +15627,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "optional": true, "dependencies": { "path-key": "^2.0.0" }, @@ -15669,7 +15638,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "optional": true, "engines": { "node": ">=4" } @@ -15678,7 +15646,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "optional": true, "bin": { "semver": "bin/semver" } @@ -15687,7 +15654,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "optional": true, "dependencies": { "shebang-regex": "^1.0.0" }, @@ -15699,7 +15665,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -15708,7 +15673,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "optional": true, "dependencies": { "isexe": "^2.0.0" }, @@ -15838,27 +15802,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-regex2": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz", - "integrity": "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "ret": "~0.5.0" - } - }, "node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", @@ -15892,29 +15835,10 @@ "url": "https://opencollective.com/webpack" } }, - "node_modules/secure-json-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.0.0.tgz", - "integrity": "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, "node_modules/selderee": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", - "optional": true, "dependencies": { "parseley": "^0.12.0" }, @@ -15935,102 +15859,87 @@ } }, "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" }, "engines": { - "node": ">= 18" + "node": ">= 0.8.0" } }, "node_modules/send/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "ms": "2.0.0" } }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/send/node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.8" } }, - "node_modules/send/node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/send/node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/send/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "mime-db": "^1.54.0" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "license": "MIT", - "optional": true, - "peer": true + "engines": { + "node": ">= 0.8" + } }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -16043,20 +15952,18 @@ } }, "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", "license": "MIT", - "optional": true, - "peer": true, "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" }, "engines": { - "node": ">= 18" + "node": ">= 0.8.0" } }, "node_modules/serve-static/node_modules/encodeurl": { @@ -16064,8 +15971,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "optional": true, - "peer": true, "engines": { "node": ">= 0.8" } @@ -16268,7 +16173,6 @@ "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", "license": "MIT (http://mootools.net/license.txt)", - "optional": true, "engines": { "node": "*" } @@ -16845,7 +16749,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -16943,13 +16846,10 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz", - "integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==", - "license": "Apache-2.0", - "dependencies": { - "@scarf/scarf": "=1.4.0" - } + "version": "5.17.14", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz", + "integrity": "sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==", + "license": "Apache-2.0" }, "node_modules/symbol-observable": { "version": "4.0.0", @@ -16979,12 +16879,17 @@ } }, "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/tar": { @@ -17029,14 +16934,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/terser": { - "version": "5.37.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.37.0.tgz", - "integrity": "sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==", + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", + "acorn": "^8.15.0", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -17048,9 +16953,9 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.11", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz", - "integrity": "sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==", + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -17083,9 +16988,9 @@ } }, "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -17135,9 +17040,9 @@ "license": "MIT" }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "license": "MIT", "dependencies": { @@ -17217,7 +17122,6 @@ "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz", "integrity": "sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw==", "license": "MIT", - "optional": true, "bin": { "tlds": "bin.js" } @@ -17244,7 +17148,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -17274,23 +17177,13 @@ "node_modules/token-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz", - "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==", - "optional": true + "integrity": "sha512-VSsyNPPW74RpHwR8Fc21uubwHY7wMDeJLys2IX5zJNih+OnAnaifKHo+1LHT7DAdloQ7apeaaWg8l7qnf/TnEg==" }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, "node_modules/ts-api-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.1.tgz", @@ -18257,14 +18150,12 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", - "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" }, @@ -18361,9 +18252,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz", - "integrity": "sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "funding": [ { "type": "opencollective", @@ -18394,8 +18285,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/uri-js": { "version": "4.4.1", @@ -18457,7 +18347,6 @@ "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", "license": "MIT", - "optional": true, "engines": { "node": ">=10" } @@ -18491,7 +18380,6 @@ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -18507,9 +18395,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", - "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", "dev": true, "license": "MIT", "dependencies": { @@ -18533,7 +18421,6 @@ "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz", "integrity": "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==", "license": "MIT", - "optional": true, "dependencies": { "ansi-colors": "^4.1.1", "escape-goat": "^3.0.0", @@ -18551,7 +18438,6 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "license": "MIT", - "optional": true, "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -18566,7 +18452,6 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "license": "BSD-2-Clause", - "optional": true, "dependencies": { "domelementtype": "^2.2.0" }, @@ -18582,7 +18467,6 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", "license": "BSD-2-Clause", - "optional": true, "dependencies": { "domelementtype": "^2.0.1" }, @@ -18598,7 +18482,6 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "license": "BSD-2-Clause", - "optional": true, "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -18613,7 +18496,6 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "license": "BSD-2-Clause", - "optional": true, "dependencies": { "domelementtype": "^2.2.0" }, @@ -18629,7 +18511,6 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "license": "BSD-2-Clause", - "optional": true, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -18639,7 +18520,6 @@ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", "license": "MIT", - "optional": true, "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^3.3.0", @@ -18655,7 +18535,6 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "license": "MIT", - "optional": true, "bin": { "mime": "cli.js" }, @@ -18669,35 +18548,37 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/webpack": { - "version": "5.97.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", - "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", + "version": "5.104.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", + "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", - "@types/estree": "^1.0.6", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.14.0", - "browserslist": "^4.24.0", + "acorn": "^8.15.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.1", - "es-module-lexer": "^1.2.1", + "enhanced-resolve": "^5.17.4", + "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.11", "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", + "loader-runner": "^4.3.1", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.10", - "watchpack": "^2.4.1", - "webpack-sources": "^3.2.3" + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.4.4", + "webpack-sources": "^3.3.3" }, "bin": { "webpack": "bin/webpack.js" @@ -18725,15 +18606,45 @@ } }, "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", "dev": true, "license": "MIT", "engines": { "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -18758,6 +18669,33 @@ "node": ">=4.0" } }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", @@ -18885,7 +18823,6 @@ "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz", "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==", "license": "MIT", - "optional": true, "dependencies": { "@babel/parser": "^7.9.6", "@babel/types": "^7.9.6", @@ -19046,6 +18983,19 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index 1527bc8..846b83a 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "class-validator": "^0.14.1", "crypto": "^1.0.1", "dotenv": "^16.4.7", + "express": "^4.22.1", "express-basic-auth": "^1.2.1", "fastest-levenshtein": "^1.0.16", "form-data": "^4.0.2", diff --git a/src/Types&Enums/blame-request-management/blameWorkflow-steps.enum.ts b/src/Types&Enums/blame-request-management/blameWorkflow-steps.enum.ts index 9d19a5a..0b661be 100644 --- a/src/Types&Enums/blame-request-management/blameWorkflow-steps.enum.ts +++ b/src/Types&Enums/blame-request-management/blameWorkflow-steps.enum.ts @@ -2,7 +2,10 @@ export enum WorkflowStep { CREATED = "CREATED", - + + // ---------- CAR_BODY only (no confession; accident type form) ---------- + CAR_BODY_ACCIDENT_TYPE = "CAR_BODY_ACCIDENT_TYPE", + // ---------- First party ---------- FIRST_BLAME_CONFESSION = "FIRST_BLAME_CONFESSION", FIRST_VIDEO = "FIRST_VIDEO", diff --git a/src/auth/auth-services/user.auth.service.ts b/src/auth/auth-services/user.auth.service.ts index 347377d..72113e2 100644 --- a/src/auth/auth-services/user.auth.service.ts +++ b/src/auth/auth-services/user.auth.service.ts @@ -71,6 +71,12 @@ export class UserAuthService { }); const otp = this.otpCreator.create(); const hashOtp = await this.hashService.hash(otp); + const rawExpireMinutes = Number(process.env.EXP_OTP_TIME ?? "2"); + const expireMinutes = + Number.isFinite(rawExpireMinutes) && rawExpireMinutes > 0 + ? rawExpireMinutes + : 2; + const otpExpire = Date.now() + expireMinutes * 60 * 1000; if (!userExist) { await this.smsSender(otp, mobile); /// create otp request @@ -90,9 +96,7 @@ export class UserAuthService { city: "", address: "", state: "", - otpExpire: new Date( - new Date().getTime() + +process.env.EXP_OTP_TIME * 60 * 1000, - ).getTime(), + otpExpire, }); return new LoginDtoRs(newUser); } @@ -105,9 +109,7 @@ export class UserAuthService { }, { otp: hashOtp, - otpExpire: new Date( - new Date().getTime() + +process.env.EXP_OTP_TIME * 60 * 1000, - ).getTime(), + otpExpire, }, ); if (updateTokens) return new LoginDtoRs(userExist); diff --git a/src/claim-request-management/claim-request-management.service.ts b/src/claim-request-management/claim-request-management.service.ts index 355b11f..bc95685 100644 --- a/src/claim-request-management/claim-request-management.service.ts +++ b/src/claim-request-management/claim-request-management.service.ts @@ -49,6 +49,7 @@ import { ClaimRequiredDocumentType, CarAngle } from "src/Types&Enums/claim-reque import { ClaimStatus } from "src/Types&Enums/claim-request-management/claimStatus.enum"; import { ClaimWorkflowStep } from "src/Types&Enums/claim-request-management/claim-workflow-steps.enum"; import { CaseStatus as BlameCaseStatus } from "src/Types&Enums/blame-request-management/caseStatus.enum"; +import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum"; import { ClaimSignDbService } from "./entites/db-service/claim-sign.db.service"; import { DamageImageDbService } from "./entites/db-service/damage-image.db.service"; import { ClaimFactorsImageDbService } from "./entites/db-service/factor-image.db.service"; @@ -556,11 +557,10 @@ export class ClaimRequestManagementService { const isCarBody = claimRequest.blameFile?.type === "CAR_BODY"; if (isCarBody) { - // Check if accident is with another object (not a car) - // This can be determined by: - // 1. carBodyForm.carBodyForm.car === false (explicitly set to false) - // 2. OR no secondPartyCarDetail exists (no second party car) - const isAccidentWithOtherObject = + // Accident with object (not another car): v2 uses parties[0].carBodyFirstForm.object, v1 uses carBodyForm.carBodyForm.car === false + const firstPartyCarBody = claimRequest.blameFile?.parties?.[0]?.carBodyFirstForm; + const isAccidentWithOtherObject = + (firstPartyCarBody && firstPartyCarBody.object === true) || claimRequest.blameFile?.carBodyForm?.carBodyForm?.car === false || !claimRequest.blameFile?.secondPartyDetails?.secondPartyCarDetail; @@ -2734,44 +2734,68 @@ export class ClaimRequestManagementService { ); } - // 3. Validate expert decision exists - if (!blameRequest.expert?.decision) { - throw new BadRequestException( - "Cannot create claim until expert has made a decision", - ); - } - - const guiltyPartyId = String(blameRequest.expert.decision.guiltyPartyId); - - // 4. Validate both parties have signed and accepted const parties = blameRequest.parties || []; - if (parties.length < 2) { - throw new BadRequestException( - "Both parties must be present in the blame request", + const isCarBody = blameRequest.type === BlameRequestType.CAR_BODY; + + if (isCarBody) { + // CAR_BODY: single party, no expert; first party is the damaged one who creates the claim + if (parties.length < 1) { + throw new BadRequestException("Blame request has no party"); + } + const firstParty = parties.find((p) => p.role === "FIRST"); + if (!firstParty || String(firstParty.person?.userId) !== currentUserId) { + throw new ForbiddenException( + "Only the first party (damaged) can create a claim from this CAR_BODY blame request", + ); + } + } else { + // THIRD_PARTY: require expert decision and both parties signed + if (!blameRequest.expert?.decision) { + throw new BadRequestException( + "Cannot create claim until expert has made a decision", + ); + } + + const guiltyPartyId = String(blameRequest.expert.decision.guiltyPartyId); + + if (parties.length < 2) { + throw new BadRequestException( + "Both parties must be present in the blame request", + ); + } + + const allPartiesSigned = parties.every( + (p) => p.confirmation !== undefined && p.confirmation !== null, ); + + if (!allPartiesSigned) { + throw new BadRequestException( + "Both parties must sign the expert decision before creating a claim", + ); + } + + const allPartiesAccepted = parties.every( + (p) => p.confirmation?.accepted === true, + ); + + if (!allPartiesAccepted) { + throw new BadRequestException( + "Both parties must accept the expert decision. If rejected, in-person resolution is required.", + ); + } + + const guiltyParty = parties.find((p) => { + return String(p.person?.userId) === guiltyPartyId; + }); + + if (guiltyParty && String(guiltyParty.person?.userId) === currentUserId) { + throw new ForbiddenException( + "You cannot create a claim as you are the guilty party", + ); + } } - const allPartiesSigned = parties.every( - (p) => p.confirmation !== undefined && p.confirmation !== null, - ); - - if (!allPartiesSigned) { - throw new BadRequestException( - "Both parties must sign the expert decision before creating a claim", - ); - } - - const allPartiesAccepted = parties.every( - (p) => p.confirmation?.accepted === true, - ); - - if (!allPartiesAccepted) { - throw new BadRequestException( - "Both parties must accept the expert decision. If rejected, in-person resolution is required.", - ); - } - - // 5. Validate current user is the DAMAGED party (NOT the guilty party) + // 5. Validate current user is a party (and for THIRD_PARTY not the guilty one) const currentUserParty = parties.find( (p) => String(p.person?.userId) === currentUserId, ); @@ -2782,24 +2806,6 @@ export class ClaimRequestManagementService { ); } - const currentUserIsGuilty = parties.some( - (p) => - String(p.person?.userId) === currentUserId && - String((p as any)._id || p.person?.userId) === guiltyPartyId, - ); - - // Better check: compare guiltyPartyId with person.userId of each party - const guiltyParty = parties.find((p) => { - // guiltyPartyId could be userId or party identifier - return String(p.person?.userId) === guiltyPartyId; - }); - - if (guiltyParty && String(guiltyParty.person?.userId) === currentUserId) { - throw new ForbiddenException( - "You cannot create a claim as you are the guilty party", - ); - } - // 6. Validate no existing claim for this blame const existingClaim = await this.claimCaseDbService.findOne({ blameRequestId: new Types.ObjectId(blameRequestId), diff --git a/src/request-management/dto/create-request-management.dto.ts b/src/request-management/dto/create-request-management.dto.ts index 12c3b67..b48b3ef 100644 --- a/src/request-management/dto/create-request-management.dto.ts +++ b/src/request-management/dto/create-request-management.dto.ts @@ -48,44 +48,74 @@ export class FirstPartyFileDto { } export class DescriptionDto { - @ApiProperty() + @ApiProperty({ description: "Accident description (required for all types)" }) desc: string; - // CAR_BODY specific fields - @ApiPropertyOptional({ - description: "Date of accident (for CAR_BODY type only)", - example: "2025-12-08" + @ApiPropertyOptional({ + description: "CAR_BODY only. Ignored for THIRD_PARTY.", + example: "2025-12-08", }) accidentDate?: Date; - @ApiPropertyOptional({ - description: "Time of accident (for CAR_BODY type only)", - example: "14:30" + @ApiPropertyOptional({ + description: "CAR_BODY only. Ignored for THIRD_PARTY.", + example: "14:30", }) accidentTime?: string; - @ApiPropertyOptional({ + @ApiPropertyOptional({ enum: WeatherCondition, - description: "Weather condition at time of accident (for CAR_BODY type only)", - example: WeatherCondition.CLEAR + description: "CAR_BODY only. Ignored for THIRD_PARTY.", + example: WeatherCondition.CLEAR, }) weatherCondition?: WeatherCondition; - @ApiPropertyOptional({ + @ApiPropertyOptional({ enum: RoadCondition, - description: "Road condition at time of accident (for CAR_BODY type only)", - example: RoadCondition.DRY + description: "CAR_BODY only. Ignored for THIRD_PARTY.", + example: RoadCondition.DRY, }) roadCondition?: RoadCondition; - @ApiPropertyOptional({ + @ApiPropertyOptional({ enum: LightCondition, - description: "Light condition at time of accident (for CAR_BODY type only)", - example: LightCondition.DAYLIGHT + description: "CAR_BODY only. Ignored for THIRD_PARTY.", + example: LightCondition.DAYLIGHT, }) lightCondition?: LightCondition; } +/** + * THIRD_PARTY description step: only desc is accepted. + */ +export class ThirdPartyDescriptionDto { + @ApiProperty({ description: "Accident description" }) + desc: string; +} + +/** + * CAR_BODY description step: desc + accident date/time and conditions required. + */ +export class CarBodyDescriptionDto { + @ApiProperty({ description: "Accident description" }) + desc: string; + + @ApiProperty({ description: "Date of accident", example: "2025-12-08" }) + accidentDate: Date; + + @ApiProperty({ description: "Time of accident", example: "14:30" }) + accidentTime: string; + + @ApiProperty({ enum: WeatherCondition, example: WeatherCondition.CLEAR }) + weatherCondition: WeatherCondition; + + @ApiProperty({ enum: RoadCondition, example: RoadCondition.DRY }) + roadCondition: RoadCondition; + + @ApiProperty({ enum: LightCondition, example: LightCondition.DAYLIGHT }) + lightCondition: LightCondition; +} + export class FirstPartyDetail { // @ApiProperty({ type: String }) firstPartyId?: Types.ObjectId; diff --git a/src/request-management/entities/schema/accidentInformation.type.ts b/src/request-management/entities/schema/accidentInformation.type.ts index fb1e03a..67f4650 100644 --- a/src/request-management/entities/schema/accidentInformation.type.ts +++ b/src/request-management/entities/schema/accidentInformation.type.ts @@ -50,5 +50,10 @@ export class AccidentInfo { @Prop({ type: AccidentClassificationSchema }) classification?: AccidentClassification; + + /** CAR_BODY: weather / road / light at time of accident */ + @Prop() weatherCondition?: string; + @Prop() roadCondition?: string; + @Prop() lightCondition?: string; } export const AccidentInfoSchema = SchemaFactory.createForClass(AccidentInfo); \ No newline at end of file diff --git a/src/request-management/entities/schema/blame-cases.schema.ts b/src/request-management/entities/schema/blame-cases.schema.ts index c92ae5b..b46816c 100644 --- a/src/request-management/entities/schema/blame-cases.schema.ts +++ b/src/request-management/entities/schema/blame-cases.schema.ts @@ -1,19 +1,27 @@ import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { HydratedDocument } from "mongoose"; +import { HydratedDocument, Types } from "mongoose"; import { BlameRequestType } from "src/Types&Enums/blame-request-management/blameRequestType.enum"; import { Party, PartySchema } from "./partyRole.enum"; -import { AccidentInfo, AccidentInfoSchema } from "./accidentInformation.type"; import { ExpertSection, ExpertSectionSchema } from "./expert-section.type"; import { Workflow, WorkflowSchema } from "./workflow.type"; import { HistoryEvent, HistoryEventSchema } from "./historyEvent.type"; import { CaseStatus } from "src/Types&Enums/blame-request-management/caseStatus.enum"; import { BlameStatus } from "src/Types&Enums/blame-request-management/blameStatus.enum"; +import { CreationMethod, FilledBy } from "./request-management.schema"; + +/** CAR_BODY only: mocked insurance inquiry result (legacy top-level; prefer parties[].insurance.carBodyInsurance) */ +@Schema({ _id: false }) +export class CarBodyInsuranceDetail { + @Prop() policyNumber?: string; + @Prop() startDate?: string; + @Prop() endDate?: string; + @Prop() insurerCompany?: string; + @Prop({ type: [String] }) coverages?: string[]; +} +export const CarBodyInsuranceDetailSchema = SchemaFactory.createForClass(CarBodyInsuranceDetail); @Schema({ _id: false }) export class BlameRequestSnapshot { - @Prop({ type: AccidentInfoSchema }) - accident?: AccidentInfo; - @Prop({ type: [PartySchema], default: [] }) parties?: Party[]; } @@ -44,9 +52,6 @@ export class BlameRequest { @Prop({ type: WorkflowSchema }) workflow?: Workflow; - - @Prop({ type: AccidentInfoSchema }) - accident?: AccidentInfo; @Prop({ type: [PartySchema], default: [] }) parties: Party[]; @@ -57,12 +62,32 @@ export class BlameRequest { @Prop({ type: [HistoryEventSchema], default: [] }) history: HistoryEvent[]; + /** CAR_BODY only: first party car-body insurance (mocked inquiry) – legacy; prefer parties[0].insurance.carBodyInsurance */ + @Prop({ type: CarBodyInsuranceDetailSchema }) + carBodyInsuranceDetail?: CarBodyInsuranceDetail; + /** * Optional snapshot structure (kept for future use / read-optimized copies). * Source of truth remains the top-level fields of this document. */ @Prop({ type: BlameRequestSnapshotSchema, required: false }) snapshot?: BlameRequestSnapshot; + + /** True when this blame was created by a field expert (independent expert); only that expert can see/review it. */ + @Prop({ default: false }) + expertInitiated?: boolean; + + /** Field expert who created this file (for expert-initiated flows). */ + @Prop({ type: Types.ObjectId }) + initiatedByFieldExpertId?: Types.ObjectId; + + /** LINK = expert sends link to user(s); IN_PERSON = expert fills form on-site. */ + @Prop({ type: String, enum: CreationMethod }) + creationMethod?: CreationMethod; + + /** Who fills the blame data: CUSTOMER (LINK) or EXPERT (IN_PERSON). */ + @Prop({ type: String, enum: FilledBy }) + filledBy?: FilledBy; } export type BlameRequestDocument = HydratedDocument; diff --git a/src/request-management/entities/schema/partyRole.enum.ts b/src/request-management/entities/schema/partyRole.enum.ts index 4021176..38e5fff 100644 --- a/src/request-management/entities/schema/partyRole.enum.ts +++ b/src/request-management/entities/schema/partyRole.enum.ts @@ -70,6 +70,16 @@ export class Insurance { @Prop() financialCeiling?: string; @Prop({ type: [String] }) coverages?: string[]; + + /** CAR_BODY only: mocked car-body insurance inquiry result */ + @Prop({ type: MongooseSchema.Types.Mixed }) + carBodyInsurance?: { + policyNumber?: string; + startDate?: string; + endDate?: string; + insurerCompany?: string; + coverages?: string[]; + }; } export const InsuranceSchema = SchemaFactory.createForClass(Insurance); @@ -87,6 +97,13 @@ export class PartyStatement { @Prop({ type: String }) description?: string; + + /** CAR_BODY: accident conditions from description step */ + @Prop() accidentDate?: Date; + @Prop() accidentTime?: string; + @Prop() weatherCondition?: string; + @Prop() roadCondition?: string; + @Prop() lightCondition?: string; } export const PartyStatementSchema = SchemaFactory.createForClass(PartyStatement); @@ -130,6 +147,13 @@ export class Party { @Prop({ type: PersonSchema }) person: Person; + /** + * CAR_BODY only: first form – accident with car vs object. + * Second form (guilty/damaged) may be added later as carBodySecondForm. + */ + @Prop({ type: MongooseSchema.Types.Mixed }) + carBodyFirstForm?: { car?: boolean; object?: boolean }; + /** * Party-submitted location (step-driven: FIRST_LOCATION / SECOND_LOCATION). */ diff --git a/src/request-management/expert-initiated.v2.controller.ts b/src/request-management/expert-initiated.v2.controller.ts new file mode 100644 index 0000000..c213229 --- /dev/null +++ b/src/request-management/expert-initiated.v2.controller.ts @@ -0,0 +1,244 @@ +import { extname } from "node:path"; +import { + Controller, + Post, + Body, + Param, + UseGuards, + Get, + UseInterceptors, + UploadedFile, +} from "@nestjs/common"; +import { FileInterceptor } from "@nestjs/platform-express"; +import { diskStorage } from "multer"; +import { + ApiBearerAuth, + ApiBody, + ApiParam, + ApiTags, + ApiOperation, + ApiResponse, + ApiConsumes, +} from "@nestjs/swagger"; +import { LocalActorAuthGuard } from "src/auth/guards/actor-local.guard"; +import { RolesGuard } from "src/auth/guards/role.guard"; +import { CurrentUser } from "src/decorators/user.decorator"; +import { Roles } from "src/decorators/roles.decorator"; +import { RoleEnum } from "src/Types&Enums/role.enum"; +import { RequestManagementService } from "./request-management.service"; +import { CreateExpertInitiatedFileDto } from "./dto/expert-initiated.dto"; +import { ExpertCompleteThirdPartyFormDto } from "./dto/expert-complete-third-party-form.dto"; +import { ExpertCompleteCarBodyFormDto } from "./dto/expert-complete-car-body-form.dto"; +import { ExpertAccidentFieldsDto } from "./dto/expert-accident-fields.dto"; +import { ExpertCompleteClaimDataDto } from "./dto/expert-complete-claim-data.dto"; +import { ClaimRequestManagementService } from "src/claim-request-management/claim-request-management.service"; + +/** + * V2 expert-initiated blame API: uses BlameRequest (workflow) model. + * Field experts create files via LINK (send link to user) or IN_PERSON (expert fills on-site). + * Only the initiating field expert can see/review these files. + */ +@ApiTags("expert-initiated-blame (v2)") +@Controller("v2/expert-initiated-blame") +@ApiBearerAuth() +@UseGuards(LocalActorAuthGuard, RolesGuard) +@Roles(RoleEnum.FIELD_EXPERT) +export class ExpertInitiatedV2Controller { + constructor( + private readonly requestManagementService: RequestManagementService, + private readonly claimRequestManagementService: ClaimRequestManagementService, + ) {} + + @Get("my-files") + @ApiOperation({ + summary: "[V2] List my expert-initiated blame files", + description: + "Returns all BlameRequest (workflow) files created by the current field expert.", + }) + @ApiResponse({ status: 200, description: "List of expert-initiated files" }) + async getMyFilesV2(@CurrentUser() expert: any) { + return this.requestManagementService.getMyExpertInitiatedFilesV2(expert); + } + + @Get("blame/:requestId") + @ApiOperation({ + summary: "[V2] Get one expert-initiated blame request", + description: "Returns a single blame request. Only the initiating field expert can access.", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiResponse({ status: 200, description: "Blame request" }) + async getBlameRequestV2( + @Param("requestId") requestId: string, + @CurrentUser() expert: any, + ) { + return this.requestManagementService.getBlameRequestV2(requestId, expert); + } + + @Post("create") + @ApiOperation({ + summary: "[V2] Create expert-initiated blame file", + description: + "Creates a BlameRequest with workflow. LINK: parties identified by phone, expert sends link. IN_PERSON: expert fills form later.", + }) + @ApiBody({ type: CreateExpertInitiatedFileDto }) + @ApiResponse({ + status: 201, + description: "File created", + schema: { + type: "object", + properties: { + requestId: { type: "string" }, + publicId: { type: "string" }, + linkUrl: { type: "string", description: "Present for LINK method" }, + }, + }, + }) + async createV2( + @CurrentUser() expert: any, + @Body() dto: CreateExpertInitiatedFileDto, + ) { + return this.requestManagementService.createExpertInitiatedBlameV2( + expert, + dto, + ); + } + + @Post("complete-blame-data/:requestId") + @ApiOperation({ + summary: "[V2] Submit all blame data (IN_PERSON)", + description: + "For IN_PERSON files only. Send THIRD_PARTY or CAR_BODY form; completes the BlameRequest.", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiBody({ + description: + "ExpertCompleteThirdPartyFormDto for THIRD_PARTY or ExpertCompleteCarBodyFormDto for CAR_BODY", + }) + @ApiResponse({ status: 200, description: "Blame form completed" }) + async completeBlameDataV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @Body() formData: any, + ) { + return this.requestManagementService.expertCompleteBlameDataV2( + expert, + requestId, + formData, + ); + } + + @Post("upload-video/:requestId") + @ApiOperation({ + summary: "[V2] Expert uploads video for expert-initiated BlameRequest", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiConsumes("multipart/form-data") + @ApiBody({ + schema: { + type: "object", + properties: { file: { type: "string", format: "binary" } }, + }, + }) + @UseInterceptors( + FileInterceptor("file", { + limits: { fileSize: 20 * 1024 * 1024 }, + storage: diskStorage({ + destination: "./files/video", + filename: (req, file, callback) => { + const unique = Date.now(); + const ex = extname(file.originalname); + callback(null, `expert-${file.originalname}-${unique}${ex}`); + }, + }), + }), + ) + @ApiResponse({ status: 200, description: "Video uploaded" }) + async uploadVideoV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @UploadedFile() file?: Express.Multer.File, + ) { + return this.requestManagementService.expertUploadVideoForBlameV2( + expert, + requestId, + file, + ); + } + + @Post("upload-voice/:requestId") + @ApiOperation({ + summary: "[V2] Expert uploads voice for expert-initiated BlameRequest", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiConsumes("multipart/form-data") + @ApiBody({ + schema: { + type: "object", + properties: { voice: { type: "string", format: "binary" } }, + }, + }) + @UseInterceptors( + FileInterceptor("voice", { + limits: { fileSize: 10 * 1024 * 1024 }, + storage: diskStorage({ + destination: "./files/voice", + filename: (req, file, callback) => { + const unique = Date.now(); + const ex = extname(file.originalname); + const flname = file.originalname.split(".")[0]; + callback(null, `expert-${flname}-${unique}${ex}`); + }, + }), + }), + ) + @ApiResponse({ status: 200, description: "Voice uploaded" }) + async uploadVoiceV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @UploadedFile() voice?: Express.Multer.File, + ) { + return this.requestManagementService.expertUploadVoiceForBlameV2( + expert, + requestId, + voice, + ); + } + + @Post("add-accident-fields/:requestId") + @ApiOperation({ + summary: "[V2] Expert adds accident fields to expert-initiated BlameRequest", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiBody({ type: ExpertAccidentFieldsDto }) + @ApiResponse({ status: 200, description: "Accident fields added" }) + async addAccidentFieldsV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @Body() fields: ExpertAccidentFieldsDto, + ) { + return this.requestManagementService.expertAddAccidentFieldsForBlameV2( + expert, + requestId, + fields, + ); + } + + @Post("complete-claim-data/:claimRequestId") + @ApiOperation({ + summary: "Submit claim-needed data (expert-initiated IN_PERSON)", + }) + @ApiParam({ name: "claimRequestId", description: "Claim file ID" }) + @ApiBody({ type: ExpertCompleteClaimDataDto }) + @ApiResponse({ status: 200, description: "Claim data updated" }) + async completeClaimData( + @CurrentUser() expert: any, + @Param("claimRequestId") claimRequestId: string, + @Body() dto: ExpertCompleteClaimDataDto, + ) { + return this.claimRequestManagementService.expertCompleteClaimData( + claimRequestId, + expert, + dto, + ); + } +} diff --git a/src/request-management/request-management.module.ts b/src/request-management/request-management.module.ts index 4e0ba63..a5e8bb6 100644 --- a/src/request-management/request-management.module.ts +++ b/src/request-management/request-management.module.ts @@ -35,6 +35,7 @@ import { RequestManagementService } from "./request-management.service"; import { RequestManagementController } from "./request-management.controller"; import { RequestManagementV2Controller } from "./request-management.v2.controller"; import { ExpertInitiatedController } from "./expert-initiated.controller"; +import { ExpertInitiatedV2Controller } from "./expert-initiated.v2.controller"; @Module({ imports: [ @@ -63,6 +64,7 @@ import { ExpertInitiatedController } from "./expert-initiated.controller"; RequestManagementController, RequestManagementV2Controller, ExpertInitiatedController, + ExpertInitiatedV2Controller, ], providers: [ RequestManagementService, diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 2e2d8ac..8fa6b4a 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -93,6 +93,25 @@ export class RequestManagementService { } private async advanceWorkflowToNext(req: any, submittedStepKey: WorkflowStep) { + // CAR_BODY: after first-party description there is no second party or expert; go to COMPLETED + if ( + req.type === BlameRequestType.CAR_BODY && + submittedStepKey === WorkflowStep.FIRST_DESCRIPTION + ) { + const completed = Array.isArray(req.workflow.completedSteps) + ? req.workflow.completedSteps + : []; + if (!completed.includes(submittedStepKey)) completed.push(submittedStepKey); + req.workflow.completedSteps = completed; + req.workflow.currentStep = WorkflowStep.COMPLETED; + req.workflow.nextStep = undefined; + req.status = CaseStatus.COMPLETED; + this.logger.debug( + "[WORKFLOW] CAR_BODY: advanced to COMPLETED after FIRST_DESCRIPTION", + ); + return; + } + const submittedStep = await this.getWorkflowStep({ stepKey: submittedStepKey }); this.logger.debug( @@ -164,6 +183,60 @@ export class RequestManagementService { ); } + /** + * Ensures CAR_BODY_ACCIDENT_TYPE step exists in DB (e.g. if initialize was not run after adding CAR_BODY flow). + */ + private async ensureCarBodyAccidentTypeStepExists(): Promise { + const exists = await this.workflowStepDbService.exists( + WorkflowStep.CAR_BODY_ACCIDENT_TYPE as any, + ); + if (exists) return; + + this.logger.log( + "[WORKFLOW] CAR_BODY_ACCIDENT_TYPE step missing; upserting from default definition", + ); + await this.workflowStepDbService.upsertByStepKey( + WorkflowStep.CAR_BODY_ACCIDENT_TYPE as any, + { + stepKey: WorkflowStep.CAR_BODY_ACCIDENT_TYPE, + type: "CAR_BODY", + stepNumber: 2, + isActive: true, + stepName_fa: "نوع حادثه بدنه", + stepName_en: "Car Body Accident Type", + description_fa: "انتخاب اینکه حادثه با خودرو بوده یا با شیء", + description_en: + "Select whether accident was with another car or with an object", + category: "FIRST_PARTY", + requiredPreviousSteps: [WorkflowStep.CREATED], + nextPossibleSteps: [WorkflowStep.FIRST_VIDEO], + allowedRoles: ["user"], + estimatedDuration: 1, + fields: [ + { + id: "507f1f77bcf86cd7994390cb" as any, + name_fa: "نوع حادثه", + name_en: "accidentType", + label_fa: "نوع حادثه", + label_en: "Accident Type", + placeholder_fa: "حادثه با خودرو یا شیء؟", + placeholder_en: "Accident with car or object?", + value: [ + { label_fa: "با خودرو", label_en: "With Car", value: "car" }, + { label_fa: "با شیء", label_en: "With Object", value: "object" }, + ], + dataType: "select", + required: true, + order: 1, + isActive: true, + validation: { enum: ["car", "object"] }, + }, + ], + metadata: { icon: "car", color: "#10B981" }, + } as any, + ); + } + private async getWorkflowStep(params: { stepNumber?: number; stepKey?: WorkflowStep; @@ -235,6 +308,12 @@ export class RequestManagementService { ); } + // CAR_BODY skips confession and goes to accident-type form + const nextStep = + type === BlameRequestType.CAR_BODY + ? (WorkflowStep.CAR_BODY_ACCIDENT_TYPE as WorkflowStep) + : (nextStepFromManager as WorkflowStep); + const publicId = await this.publicIdService.generateRequestPublicId(); const created = await this.blameRequestDbService.create({ @@ -257,7 +336,7 @@ export class RequestManagementService { ], workflow: { currentStep: firstStep.stepKey as WorkflowStep, - nextStep: nextStepFromManager as WorkflowStep, + nextStep, completedSteps: [firstStep.stepKey as WorkflowStep], locked: false, }, @@ -409,6 +488,73 @@ export class RequestManagementService { }; } + /** + * V2 CAR_BODY: Submit accident type form (car vs object). Replaces confession step for CAR_BODY. + */ + async carBodyAccidentTypeFormV2( + requestId: string, + body: { car?: boolean; object?: boolean }, + user: any, + ) { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (req.type !== BlameRequestType.CAR_BODY) { + throw new BadRequestException("This endpoint is only for CAR_BODY type requests"); + } + if (!req.workflow?.nextStep) { + throw new BadRequestException("Request workflow is not initialized"); + } + if (req.workflow.nextStep !== WorkflowStep.CAR_BODY_ACCIDENT_TYPE) { + throw new BadRequestException( + `Invalid step. Expected nextStep=CAR_BODY_ACCIDENT_TYPE but got ${req.workflow.nextStep}`, + ); + } + + const firstPartyIndex = this.getPartyIndex(req, PartyRole.FIRST); + if (firstPartyIndex === -1) throw new BadRequestException("First party not found"); + const firstParty = req.parties[firstPartyIndex]; + this.assertPartyOwner(firstParty, user, "Only first party can submit this step"); + + if (!firstParty.person) firstParty.person = {} as any; + if (!firstParty.person.userId && user?.sub) { + firstParty.person.userId = Types.ObjectId.isValid(user.sub) + ? new Types.ObjectId(user.sub) + : undefined; + } + + const car = !!body?.car; + const object = !!body?.object; + if (!car && !object) { + throw new BadRequestException("Set car or object to true"); + } + + (firstParty as any).carBodyFirstForm = { car, object }; + req.blameStatus = BlameStatus.AGREED; + + await this.ensureCarBodyAccidentTypeStepExists(); + await this.advanceWorkflowToNext(req, WorkflowStep.CAR_BODY_ACCIDENT_TYPE); + + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "CAR_BODY_ACCIDENT_TYPE_SUBMITTED", + actor: { + actorId: Types.ObjectId.isValid(user?.sub) ? new Types.ObjectId(user.sub) : undefined, + actorName: user?.fullName, + actorType: "user", + }, + metadata: { car, object }, + } as any); + + await (req as any).save(); + + return { + requestId: req._id, + publicId: req.publicId, + workflow: req.workflow, + blameStatus: req.blameStatus, + }; + } + async uploadFirstPartyVideoV2( requestId: string, file: Express.Multer.File, @@ -678,6 +824,16 @@ export class RequestManagementService { party.insurance.startDate = inquiryMapped?.IssueDate; party.insurance.endDate = inquiryMapped?.EndDate; + // CAR_BODY: persist mocked car-body insurance in party's insurance (same place as usual inquiry) + if (req.type === BlameRequestType.CAR_BODY && role === PartyRole.FIRST) { + const carBodyInfo = await this.mockCarBodyInsuranceInquiry( + String(req._id), + body.plate, + body.nationalCodeOfInsurer, + ); + (party.insurance as any).carBodyInsurance = carBodyInfo; + } + // Advance workflow await this.advanceWorkflowToNext(req, stepKey); @@ -881,11 +1037,37 @@ export class RequestManagementService { if (!party.statement) party.statement = {} as any; party.statement.description = body.desc; - // Optional: map accident date/time to the request-level accident info (if provided) - if (body.accidentDate || body.accidentTime) { - if (!req.accident) req.accident = {} as any; - if (body.accidentDate) req.accident.date = body.accidentDate as any; - if (body.accidentTime) req.accident.time = body.accidentTime as any; + // THIRD_PARTY: only desc is accepted; reject CAR_BODY-only fields + if (req.type === BlameRequestType.THIRD_PARTY) { + const hasCarBodyFields = + body.accidentDate != null || + body.accidentTime != null || + body.weatherCondition != null || + body.roadCondition != null || + body.lightCondition != null; + if (hasCarBodyFields) { + throw new BadRequestException( + "THIRD_PARTY description step accepts only the desc field. Omit accidentDate, accidentTime, weatherCondition, roadCondition, and lightCondition.", + ); + } + } else if (req.type === BlameRequestType.CAR_BODY) { + // CAR_BODY: require desc + accident date/time and conditions + if ( + body.accidentDate == null || + body.accidentTime == null || + body.weatherCondition == null || + body.roadCondition == null || + body.lightCondition == null + ) { + throw new BadRequestException( + "CAR_BODY description step requires desc, accidentDate, accidentTime, weatherCondition, roadCondition, and lightCondition.", + ); + } + party.statement.accidentDate = body.accidentDate as any; + party.statement.accidentTime = body.accidentTime; + (party.statement as any).weatherCondition = body.weatherCondition; + (party.statement as any).roadCondition = body.roadCondition; + (party.statement as any).lightCondition = body.lightCondition; } // If second party finished description, we’re ready for expert flow. @@ -2988,6 +3170,22 @@ export class RequestManagementService { } } + /** + * Verify the current user (field expert) can access this BlameRequest (v2). + */ + private verifyExpertAccessForBlameV2(req: any, expert: any): void { + if (!req?.expertInitiated || !req?.initiatedByFieldExpertId) { + throw new ForbiddenException( + "This file is not expert-initiated or has no initiating expert", + ); + } + if (String(req.initiatedByFieldExpertId) !== String(expert?.sub)) { + throw new ForbiddenException( + "You can only access files that you have initiated", + ); + } + } + /** * Helper method to add history event to a request */ @@ -3120,6 +3318,151 @@ export class RequestManagementService { }; } + /** + * V2: Field expert creates an expert-initiated blame file (BlameRequest with workflow). + * LINK: creates request with parties identified by phone; expert sends link to user(s) who then fill via normal v2 flow. + * IN_PERSON: creates minimal request; expert fills everything via complete-blame-data v2. + */ + async createExpertInitiatedBlameV2( + expert: any, + dto: CreateExpertInitiatedFileDto, + ): Promise<{ requestId: string; publicId: string; linkUrl?: string }> { + const expertId = new Types.ObjectId(expert.sub); + const type = + dto.type === "CAR_BODY" + ? BlameRequestType.CAR_BODY + : BlameRequestType.THIRD_PARTY; + + if (dto.creationMethod === CreationMethod.LINK) { + if (!dto.firstPartyPhoneNumber) { + throw new BadRequestException( + "First party phone number is required for LINK method", + ); + } + if ( + type === BlameRequestType.THIRD_PARTY && + !dto.secondPartyPhoneNumber + ) { + throw new BadRequestException( + "Second party phone number is required for LINK method with THIRD_PARTY type", + ); + } + if ( + type === BlameRequestType.THIRD_PARTY && + dto.firstPartyPhoneNumber === dto.secondPartyPhoneNumber + ) { + throw new BadRequestException( + "First and second party phone numbers must be different", + ); + } + } + + const firstStep = await this.getWorkflowStep({ stepNumber: 1 }); + if (!firstStep?.stepKey) { + throw new InternalServerErrorException( + "Workflow stepNumber=1 not configured in step manager", + ); + } + const nextStepFromManager = firstStep.nextPossibleSteps?.[0]; + const nextStep = + type === BlameRequestType.CAR_BODY + ? (WorkflowStep.CAR_BODY_ACCIDENT_TYPE as WorkflowStep) + : (nextStepFromManager as WorkflowStep); + if (!nextStep) { + throw new InternalServerErrorException( + "Workflow stepNumber=1 has no nextPossibleSteps configured", + ); + } + + const publicId = await this.publicIdService.generateRequestPublicId(); + + const parties: any[] = []; + + if (dto.creationMethod === CreationMethod.LINK) { + const firstUserId = await this.getOrCreateUserByPhoneNumber( + dto.firstPartyPhoneNumber, + ); + parties.push({ + role: PartyRole.FIRST, + person: { + userId: firstUserId, + phoneNumber: dto.firstPartyPhoneNumber, + }, + }); + if ( + type === BlameRequestType.THIRD_PARTY && + dto.secondPartyPhoneNumber + ) { + const secondUserId = await this.getOrCreateUserByPhoneNumber( + dto.secondPartyPhoneNumber, + ); + parties.push({ + role: PartyRole.SECOND, + person: { + userId: secondUserId, + phoneNumber: dto.secondPartyPhoneNumber, + }, + }); + } + } else { + parties.push({ + role: PartyRole.FIRST, + person: {}, + }); + } + + const created = await this.blameRequestDbService.create({ + publicId, + requestNo: publicId, + type, + parties, + workflow: { + currentStep: firstStep.stepKey as WorkflowStep, + nextStep, + completedSteps: [firstStep.stepKey as WorkflowStep], + locked: false, + }, + history: [], + expertInitiated: true, + initiatedByFieldExpertId: expertId, + creationMethod: dto.creationMethod, + filledBy: + dto.creationMethod === CreationMethod.IN_PERSON + ? FilledBy.EXPERT + : FilledBy.CUSTOMER, + }); + + const requestId = String((created as any)._id); + if (!Array.isArray((created as any).history)) (created as any).history = []; + (created as any).history.push({ + type: "FILE_CREATED_BY_FIELD_EXPERT", + actor: { + actorId: expertId, + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + metadata: { creationMethod: dto.creationMethod, type: dto.type }, + }); + await (created as any).save(); + + const result: { + requestId: string; + publicId: string; + linkUrl?: string; + } = { + requestId, + publicId: (created as any).publicId, + }; + if (dto.creationMethod === CreationMethod.LINK) { + const baseUrl = + process.env.FRONTEND_BASE_URL || process.env.APP_URL || ""; + result.linkUrl = baseUrl + ? `${baseUrl.replace(/\/$/, "")}/blame/${requestId}` + : undefined; + } + return result; + } + /** * List all expert-initiated blame files for the current field expert (their panel). * Only files where initiatedBy === current user are returned. @@ -3143,6 +3486,72 @@ export class RequestManagementService { })); } + /** + * V2: List expert-initiated blame files (BlameRequest) for the current field expert. + * Only files where initiatedByFieldExpertId === current expert are returned. + */ + async getMyExpertInitiatedFilesV2(expert: any): Promise { + const expertId = new Types.ObjectId(expert.sub); + const files = await this.blameRequestDbService.find({ + expertInitiated: true, + initiatedByFieldExpertId: expertId, + }); + return (files || []).map((f: any) => ({ + _id: f._id, + publicId: f.publicId, + requestNo: f.requestNo, + type: f.type, + creationMethod: f.creationMethod, + filledBy: f.filledBy, + status: f.status, + blameStatus: f.blameStatus, + workflow: f.workflow, + partiesCount: Array.isArray(f.parties) ? f.parties.length : 0, + createdAt: f.createdAt, + })); + } + + /** + * V2: Get one blame request by id. Access allowed if current user is a party (by userId or phone) + * or the initiating field expert. For expert-initiated LINK, party access by phone is sufficient. + */ + async getBlameRequestV2(requestId: string, user: any): Promise { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) { + throw new NotFoundException("Request not found"); + } + const isFieldExpertOwner = + req.expertInitiated && + req.initiatedByFieldExpertId && + String(req.initiatedByFieldExpertId) === String(user?.sub); + const isParty = Array.isArray(req.parties) && req.parties.some((p: any) => { + const pid = p?.person?.userId ? String(p.person.userId) : null; + const phone = p?.person?.phoneNumber; + return (pid && pid === String(user?.sub)) || (phone && phone === user?.username); + }); + if (!isFieldExpertOwner && !isParty) { + throw new ForbiddenException("You do not have access to this request"); + } + // Optionally bind userId to party when user opens via LINK (phone match, no userId yet) + if (!isFieldExpertOwner && user?.sub && Types.ObjectId.isValid(user.sub)) { + let updated = false; + for (const p of req.parties || []) { + if ( + p?.person?.phoneNumber === user?.username && + !p.person?.userId + ) { + p.person = p.person || {}; + (p.person as any).userId = new Types.ObjectId(user.sub); + updated = true; + } + } + if (updated) { + await (req as any).save(); + } + } + return req; + } + /** * Single endpoint handler: complete all blame-needed data. * Routes to THIRD_PARTY or CAR_BODY completion based on request type. @@ -3174,6 +3583,459 @@ export class RequestManagementService { ); } + /** + * V2: Expert completes blame data for IN_PERSON BlameRequest. + * Delegates to expertCompleteThirdPartyFormV2 or expertCompleteCarBodyFormV2. + */ + async expertCompleteBlameDataV2( + expert: any, + requestId: string, + formData: any, + ): Promise { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) { + throw new NotFoundException("Request not found"); + } + if (!req.expertInitiated || req.creationMethod !== CreationMethod.IN_PERSON) { + throw new BadRequestException( + "This endpoint is only for expert-initiated IN_PERSON BlameRequest files.", + ); + } + this.verifyExpertAccessForBlameV2(req, expert); + + if (req.type === BlameRequestType.THIRD_PARTY) { + return this.expertCompleteThirdPartyFormV2(expert, requestId, formData); + } + if (req.type === BlameRequestType.CAR_BODY) { + return this.expertCompleteCarBodyFormV2(expert, requestId, formData); + } + throw new BadRequestException( + "Unknown file type. Must be THIRD_PARTY or CAR_BODY.", + ); + } + + /** + * V2: Expert completes IN_PERSON CAR_BODY BlameRequest in one go. + */ + async expertCompleteCarBodyFormV2( + expert: any, + requestId: string, + formData: any, + ): Promise { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated || req.creationMethod !== CreationMethod.IN_PERSON) { + throw new BadRequestException("Only expert-initiated IN_PERSON CAR_BODY files."); + } + if (req.type !== BlameRequestType.CAR_BODY) { + throw new BadRequestException("File type is not CAR_BODY."); + } + this.verifyExpertAccessForBlameV2(req, expert); + + if (!formData.carBodyForm) { + throw new BadRequestException("carBodyForm is required."); + } + + const firstPartyUserId = await this.getOrCreateUserByPhoneNumber( + formData.firstPartyPhoneNumber, + ); + + const firstPartyPlate = formData.firstPartyPlate; + let sandHubReport: any; + try { + const sandHubResponse = await this.sandHubService.getSandHubResponse({ + plate: firstPartyPlate.plate, + nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, + }); + sandHubReport = sandHubResponse["_doc"] || sandHubResponse; + } catch (e) { + this.logger.error("SandHub error in expertCompleteCarBodyFormV2:", e); + throw new InternalServerErrorException("Failed to process plate information."); + } + + const clientName = sandHubReport?.CompanyName || sandHubReport?.LastCompanyName; + const companyCode = sandHubReport?.CompanyCode; + const client = companyCode + ? await this.clientService.findClientWithCompanyCode(+companyCode) + : await this.clientService.findOne({ clientName }); + if (!client) { + throw new NotFoundException(`Client not found for company: ${clientName}`); + } + + const carBodyInfo = await this.mockCarBodyInsuranceInquiry( + requestId, + firstPartyPlate.plate, + firstPartyPlate.nationalCodeOfInsurer, + ); + + const firstParty: any = { + role: PartyRole.FIRST, + person: { + userId: firstPartyUserId, + phoneNumber: formData.firstPartyPhoneNumber, + nationalCodeOfInsurer: firstPartyPlate.nationalCodeOfInsurer, + nationalCodeOfDriver: firstPartyPlate.nationalCodeOfDriver, + insurerLicense: firstPartyPlate.insurerLicense, + driverLicense: firstPartyPlate.driverLicense, + driverIsInsurer: firstPartyPlate.driverIsInsurer, + isNewCar: firstPartyPlate.isNewCar, + userNoCertificate: firstPartyPlate.userNoCertificate, + insurerBirthday: firstPartyPlate.insurerBirthday, + driverBirthday: firstPartyPlate.driverBirthday, + }, + vehicle: { + plateId: firstPartyPlate.plate, + name: sandHubReport?.MapTypNam || sandHubReport?.CarName, + model: sandHubReport?.MapTypNam, + type: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`, + isNew: firstPartyPlate.isNewCar, + inquiry: sandHubReport, + }, + insurance: { + policyNumber: sandHubReport?.LastCompanyDocumentNumber || sandHubReport?.DocumentNumber, + company: clientName, + startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate, + endDate: sandHubReport?.EndDate, + financialCeiling: sandHubReport?.FinancialCvrCptl || sandHubReport?.FinancialCommitment, + carBodyInsurance: { + policyNumber: carBodyInfo.policyNumber, + startDate: carBodyInfo.startDate, + endDate: carBodyInfo.endDate, + insurerCompany: carBodyInfo.insurerCompany, + coverages: carBodyInfo.coverages, + }, + }, + statement: { + description: formData.firstPartyDescription?.desc, + accidentDate: formData.firstPartyDescription?.accidentDate, + accidentTime: formData.firstPartyDescription?.accidentTime, + weatherCondition: formData.firstPartyDescription?.weatherCondition, + roadCondition: formData.firstPartyDescription?.roadCondition, + lightCondition: formData.firstPartyDescription?.lightCondition, + }, + location: formData.firstPartyLocation, + carBodyFirstForm: { + car: !!formData.carBodyForm.car, + object: !!formData.carBodyForm.object, + }, + evidence: req.parties?.[0]?.evidence ? { ...req.parties[0].evidence } : {}, + }; + + req.parties = [firstParty]; + req.workflow = { + currentStep: WorkflowStep.COMPLETED, + nextStep: undefined, + completedSteps: [ + WorkflowStep.CREATED, + WorkflowStep.CAR_BODY_ACCIDENT_TYPE, + WorkflowStep.FIRST_VIDEO, + WorkflowStep.FIRST_INITIAL_FORM, + WorkflowStep.FIRST_LOCATION, + WorkflowStep.FIRST_VOICE, + WorkflowStep.FIRST_DESCRIPTION, + ].filter((s) => s), + locked: false, + }; + req.status = CaseStatus.COMPLETED; + req.blameStatus = BlameStatus.AGREED; + (req as any).filledBy = FilledBy.EXPERT; + + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "EXPERT_COMPLETED_CAR_BODY_FORM_V2", + actor: { + actorId: new Types.ObjectId(expert.sub), + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + metadata: {}, + } as any); + await (req as any).save(); + + return { + requestId: req._id, + publicId: req.publicId, + workflow: req.workflow, + status: req.status, + }; + } + + /** + * V2: Expert completes IN_PERSON THIRD_PARTY BlameRequest in one go. + */ + async expertCompleteThirdPartyFormV2( + expert: any, + requestId: string, + formData: any, + ): Promise { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated || req.creationMethod !== CreationMethod.IN_PERSON) { + throw new BadRequestException("Only expert-initiated IN_PERSON THIRD_PARTY files."); + } + if (req.type !== BlameRequestType.THIRD_PARTY) { + throw new BadRequestException("File type is not THIRD_PARTY."); + } + this.verifyExpertAccessForBlameV2(req, expert); + + if (!formData.secondParty || !formData.guiltyPartyPhoneNumber) { + throw new BadRequestException("secondParty and guiltyPartyPhoneNumber are required."); + } + + const firstPartyUserId = await this.getOrCreateUserByPhoneNumber( + formData.firstPartyPhoneNumber, + ); + const secondPartyUserId = await this.getOrCreateUserByPhoneNumber( + formData.secondParty.phoneNumber, + ); + + const buildPartyFromForm = async ( + phoneNumber: string, + userId: Types.ObjectId, + initialForm: any, + plateDto: any, + locationDto: any, + desc: string, + role: PartyRole, + ) => { + const sandHubResponse = await this.sandHubService.getSandHubResponse({ + plate: plateDto.plate, + nationalCodeOfInsurer: plateDto.nationalCodeOfInsurer, + }); + const sandHubReport = (sandHubResponse["_doc"] || sandHubResponse) as any; + const clientName = sandHubReport?.CompanyName || sandHubReport?.LastCompanyName; + const companyCode = sandHubReport?.CompanyCode; + const client = companyCode + ? await this.clientService.findClientWithCompanyCode(+companyCode) + : await this.clientService.findOne({ clientName }); + if (!client) { + throw new NotFoundException(`Client not found for company: ${clientName}`); + } + return { + role, + person: { + userId, + phoneNumber, + nationalCodeOfInsurer: plateDto.nationalCodeOfInsurer, + nationalCodeOfDriver: plateDto.nationalCodeOfDriver, + insurerLicense: plateDto.insurerLicense, + driverLicense: plateDto.driverLicense, + driverIsInsurer: plateDto.driverIsInsurer, + isNewCar: plateDto.isNewCar, + userNoCertificate: plateDto.userNoCertificate, + insurerBirthday: plateDto.insurerBirthday, + driverBirthday: plateDto.driverBirthday, + }, + vehicle: { + plateId: plateDto.plate, + name: sandHubReport?.MapTypNam || sandHubReport?.CarName, + model: sandHubReport?.MapTypNam, + type: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`, + isNew: plateDto.isNewCar, + inquiry: sandHubReport, + }, + insurance: { + policyNumber: sandHubReport?.LastCompanyDocumentNumber || sandHubReport?.DocumentNumber, + company: clientName, + startDate: sandHubReport?.IssueDate || sandHubReport?.StartDate, + endDate: sandHubReport?.EndDate, + financialCeiling: sandHubReport?.FinancialCvrCptl || sandHubReport?.FinancialCommitment, + }, + statement: { description: desc }, + location: locationDto, + evidence: {}, + }; + }; + + const firstParty = await buildPartyFromForm( + formData.firstPartyPhoneNumber, + firstPartyUserId, + formData.firstPartyInitialForm, + formData.firstPartyPlate, + formData.firstPartyLocation, + formData.firstPartyDescription?.desc || "", + PartyRole.FIRST, + ); + const secondParty = await buildPartyFromForm( + formData.secondParty.phoneNumber, + secondPartyUserId, + formData.secondParty.initialForm, + formData.secondParty.plate, + formData.secondParty.location, + formData.secondParty.description?.desc || "", + PartyRole.SECOND, + ); + + req.parties = [firstParty, secondParty]; + req.workflow = { + currentStep: WorkflowStep.COMPLETED, + nextStep: undefined, + completedSteps: [ + WorkflowStep.CREATED, + WorkflowStep.FIRST_BLAME_CONFESSION, + WorkflowStep.FIRST_VIDEO, + WorkflowStep.FIRST_INITIAL_FORM, + WorkflowStep.FIRST_LOCATION, + WorkflowStep.FIRST_VOICE, + WorkflowStep.FIRST_DESCRIPTION, + WorkflowStep.SECOND_INITIAL_FORM, + WorkflowStep.SECOND_LOCATION, + WorkflowStep.SECOND_VOICE, + WorkflowStep.SECOND_DESCRIPTION, + ].filter((s) => s), + locked: false, + }; + req.status = CaseStatus.COMPLETED; + req.blameStatus = BlameStatus.AGREED; + (req as any).filledBy = FilledBy.EXPERT; + + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "EXPERT_COMPLETED_THIRD_PARTY_FORM_V2", + actor: { + actorId: new Types.ObjectId(expert.sub), + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + metadata: { guiltyPartyPhoneNumber: formData.guiltyPartyPhoneNumber }, + } as any); + await (req as any).save(); + + return { + requestId: req._id, + publicId: req.publicId, + workflow: req.workflow, + status: req.status, + }; + } + + /** + * V2: Expert uploads video for expert-initiated BlameRequest (first party). + */ + async expertUploadVideoForBlameV2( + expert: any, + requestId: string, + file: Express.Multer.File, + ): Promise { + if (!file) throw new BadRequestException("Video file is required"); + + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated) { + throw new BadRequestException("This endpoint is only for expert-initiated files."); + } + this.verifyExpertAccessForBlameV2(req, expert); + + const firstPartyIndex = this.getPartyIndex(req, PartyRole.FIRST); + if (firstPartyIndex === -1) throw new BadRequestException("First party not found"); + const firstParty = req.parties[firstPartyIndex]; + + if (firstParty?.evidence?.videoId) { + throw new ConflictException("Video already uploaded for this file"); + } + + const videoDocument = await this.blameVideoDbService.create({ + fileName: file.filename, + path: file.path, + requestId: new Types.ObjectId(requestId), + } as any); + + if (!firstParty.evidence) firstParty.evidence = {} as any; + firstParty.evidence.videoId = String((videoDocument as any)._id); + await (req as any).save(); + + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "EXPERT_UPLOADED_VIDEO_V2", + actor: { + actorId: new Types.ObjectId(expert.sub), + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + metadata: { videoId: firstParty.evidence.videoId }, + } as any); + await (req as any).save(); + + return { requestId: req._id, videoId: firstParty.evidence.videoId }; + } + + /** + * V2: Expert uploads voice for expert-initiated BlameRequest (first party). + */ + async expertUploadVoiceForBlameV2( + expert: any, + requestId: string, + voiceFile: Express.Multer.File, + ): Promise { + if (!voiceFile) throw new BadRequestException("Voice file is required"); + + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated) { + throw new BadRequestException("This endpoint is only for expert-initiated files."); + } + this.verifyExpertAccessForBlameV2(req, expert); + + const firstPartyIndex = this.getPartyIndex(req, PartyRole.FIRST); + if (firstPartyIndex === -1) throw new BadRequestException("First party not found"); + const firstParty = req.parties[firstPartyIndex]; + + const voiceDocument = await this.blameVoiceDbService.create({ + fileName: voiceFile.filename, + path: voiceFile.path, + requestId: new Types.ObjectId(requestId), + } as any); + + if (!firstParty.evidence) firstParty.evidence = {} as any; + if (!Array.isArray(firstParty.evidence.voices)) firstParty.evidence.voices = []; + firstParty.evidence.voices.push(String((voiceDocument as any)._id)); + await (req as any).save(); + + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "EXPERT_UPLOADED_VOICE_V2", + actor: { + actorId: new Types.ObjectId(expert.sub), + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + metadata: {}, + } as any); + await (req as any).save(); + + return { requestId: req._id }; + } + + /** + * V2: Expert adds accident fields to expert-initiated BlameRequest. + */ + async expertAddAccidentFieldsForBlameV2( + expert: any, + requestId: string, + fields: any, + ): Promise { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated) { + throw new BadRequestException("This endpoint is only for expert-initiated files."); + } + this.verifyExpertAccessForBlameV2(req, expert); + + if (!req.expert) req.expert = {} as any; + if (!req.expert.decision) req.expert.decision = {} as any; + (req.expert as any).decision = { + ...(req.expert as any).decision, + fields: { + accidentWay: fields.accidentWay, + accidentReason: fields.accidentReason, + accidentType: fields.accidentType, + }, + }; + await (req as any).save(); + + return { requestId: req._id }; + } + /** * Expert completes all information for IN_PERSON THIRD_PARTY file at once * This replaces the step-by-step flow for experts filling files on-site diff --git a/src/request-management/request-management.v2.controller.ts b/src/request-management/request-management.v2.controller.ts index 2bbd3de..25c541e 100644 --- a/src/request-management/request-management.v2.controller.ts +++ b/src/request-management/request-management.v2.controller.ts @@ -33,6 +33,7 @@ import { CreateBlameRequestDtoV2, DescriptionDto, LocationDto, + CarBodyFormDto, } from "./dto/create-request-management.dto"; import { RequestManagementService } from "./request-management.service"; @@ -64,6 +65,19 @@ export class RequestManagementV2Controller { ); } + /** + * Get one blame request by id. Allowed for the request owner (party) or the initiating field expert. + */ + @Get(":requestId") + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @Roles(RoleEnum.USER, RoleEnum.FIELD_EXPERT) + async getBlameRequestV2( + @Param("requestId") requestId: string, + @CurrentUser() user: any, + ) { + return this.requestManagementService.getBlameRequestV2(requestId, user); + } + @Post("/blame-confession/:requestId") @ApiParam({ name: "requestId" }) @ApiBody({ type: BlameConfessionDtoV2 }) @@ -76,6 +90,19 @@ export class RequestManagementV2Controller { return this.requestManagementService.blameConfessionV2(requestId, body, user); } + /** CAR_BODY only: submit accident type (car vs object). Call this when nextStep is CAR_BODY_ACCIDENT_TYPE. */ + @Post("/car-body-form/:requestId") + @ApiParam({ name: "requestId" }) + @ApiBody({ type: CarBodyFormDto }) + @UseGuards(GlobalGuard) + async carBodyFormV2( + @Param("requestId") requestId: string, + @Body() body: CarBodyFormDto, + @CurrentUser() user, + ) { + return this.requestManagementService.carBodyAccidentTypeFormV2(requestId, body, user); + } + @ApiBody({ schema: { type: "object", @@ -185,7 +212,28 @@ export class RequestManagementV2Controller { @Post("/add-detail-description/:requestId") @ApiParam({ name: "requestId" }) - @ApiBody({ type: DescriptionDto }) + @ApiBody({ + description: + "THIRD_PARTY: send only desc. CAR_BODY: send desc + accidentDate, accidentTime, weatherCondition, roadCondition, lightCondition (all required).", + type: DescriptionDto, + examples: { + thirdParty: { + summary: "THIRD_PARTY (only desc)", + value: { desc: "Accident description text" }, + }, + carBody: { + summary: "CAR_BODY (desc + conditions)", + value: { + desc: "Accident description", + accidentDate: "2025-12-08", + accidentTime: "14:30", + weatherCondition: "صاف", + roadCondition: "خشک", + lightCondition: "روز", + }, + }, + }, + }) @UseGuards(GlobalGuard) async addDescriptionV2( @Param("requestId") requestId: string, diff --git a/src/workflow-step-management/dto/create-workflow-step.dto.ts b/src/workflow-step-management/dto/create-workflow-step.dto.ts index 232c641..c8353f9 100644 --- a/src/workflow-step-management/dto/create-workflow-step.dto.ts +++ b/src/workflow-step-management/dto/create-workflow-step.dto.ts @@ -128,9 +128,9 @@ export class CreateWorkflowStepDto { stepKey: WorkflowStep | ClaimWorkflowStep; @ApiProperty({ - description: 'Workflow type: THIRD_PARTY (blame) or CLAIM (claim workflow)', + description: 'Workflow type: THIRD_PARTY (blame), CAR_BODY (blame), or CLAIM (claim workflow)', example: 'THIRD_PARTY', - enum: ['THIRD_PARTY', 'CLAIM'] + enum: ['THIRD_PARTY', 'CAR_BODY', 'CLAIM'] }) @IsNotEmpty() @IsString() diff --git a/src/workflow-step-management/workflow-step-management.service.ts b/src/workflow-step-management/workflow-step-management.service.ts index 7628c41..f30f3f9 100644 --- a/src/workflow-step-management/workflow-step-management.service.ts +++ b/src/workflow-step-management/workflow-step-management.service.ts @@ -1123,6 +1123,43 @@ export class WorkflowStepManagementService { party: 'second' } }, + // CAR_BODY workflow: accident type form (replaces confession for CAR_BODY) + { + stepKey: WorkflowStep.CAR_BODY_ACCIDENT_TYPE, + type: 'CAR_BODY', + stepNumber: 2, + isActive: true, + stepName_fa: 'نوع حادثه بدنه', + stepName_en: 'Car Body Accident Type', + description_fa: 'انتخاب اینکه حادثه با خودرو بوده یا با شیء', + description_en: 'Select whether accident was with another car or with an object', + category: 'FIRST_PARTY', + requiredPreviousSteps: [WorkflowStep.CREATED], + nextPossibleSteps: [WorkflowStep.FIRST_VIDEO], + allowedRoles: ['user'], + estimatedDuration: 1, + fields: [ + { + id: '507f1f77bcf86cd7994390cb' as any, + name_fa: 'نوع حادثه', + name_en: 'accidentType', + label_fa: 'نوع حادثه', + label_en: 'Accident Type', + placeholder_fa: 'حادثه با خودرو یا شیء؟', + placeholder_en: 'Accident with car or object?', + value: [ + { label_fa: 'با خودرو', label_en: 'With Car', value: 'car' }, + { label_fa: 'با شیء', label_en: 'With Object', value: 'object' } + ], + dataType: 'select', + required: true, + order: 1, + isActive: true, + validation: { enum: ['car', 'object'] } + } + ], + metadata: { icon: 'car', color: '#10B981' } + }, // Add more default steps as needed... ]; From fc599acf4ac58db19a15288fe0e957b5df076269 Mon Sep 17 00:00:00 2001 From: "s.yahyaee" Date: Mon, 16 Mar 2026 15:39:39 +0330 Subject: [PATCH 2/2] Added Field Expert flows, and deactivated inquiry --- .../claim-request-management.service.ts | 263 +++++++++- .../claim-request-management.v2.controller.ts | 22 +- src/expert-blame/expert-blame.service.ts | 35 +- .../expert-blame.v2.controller.ts | 2 +- .../dto/expert-upload-party-signature.dto.ts | 18 + .../dto/send-party-otps.dto.ts | 19 + .../dto/verify-party-otps.dto.ts | 31 ++ .../expert-initiated.v2.controller.ts | 283 ++++++++++- .../request-management.module.ts | 4 + .../request-management.service.ts | 478 ++++++++++++++++-- 10 files changed, 1067 insertions(+), 88 deletions(-) create mode 100644 src/request-management/dto/expert-upload-party-signature.dto.ts create mode 100644 src/request-management/dto/send-party-otps.dto.ts create mode 100644 src/request-management/dto/verify-party-otps.dto.ts diff --git a/src/claim-request-management/claim-request-management.service.ts b/src/claim-request-management/claim-request-management.service.ts index bc95685..65cb8e9 100644 --- a/src/claim-request-management/claim-request-management.service.ts +++ b/src/claim-request-management/claim-request-management.service.ts @@ -2880,6 +2880,141 @@ export class ClaimRequestManagementService { } } + /** + * V2: Field expert creates a claim from an expert-initiated IN_PERSON completed blame. + * The claim owner is set to the damaged party (first for CAR_BODY, non-guilty for THIRD_PARTY). + */ + async createClaimFromBlameForExpertV2( + blameRequestId: string, + expert: { sub: string; firstName?: string; lastName?: string }, + ): Promise { + const blameRequest = await this.blameRequestDbService.findById(blameRequestId); + if (!blameRequest) { + throw new NotFoundException("Blame request not found"); + } + if (blameRequest.status !== BlameCaseStatus.COMPLETED) { + throw new BadRequestException( + `Blame request must be COMPLETED. Current status: ${blameRequest.status}`, + ); + } + if ( + !blameRequest.expertInitiated || + blameRequest.creationMethod !== "IN_PERSON" || + !blameRequest.initiatedByFieldExpertId + ) { + throw new BadRequestException( + "This endpoint is only for expert-initiated IN_PERSON blame files.", + ); + } + if (String(blameRequest.initiatedByFieldExpertId) !== String(expert.sub)) { + throw new ForbiddenException( + "Only the field expert who created this blame file can create the claim.", + ); + } + const parties = blameRequest.parties || []; + const isCarBody = blameRequest.type === BlameRequestType.CAR_BODY; + let damagedUserId: string; + if (isCarBody) { + if (parties.length < 1) throw new BadRequestException("Blame request has no party"); + const first = parties.find((p) => p.role === "FIRST"); + if (!first?.person?.userId) throw new BadRequestException("First party has no userId"); + damagedUserId = String(first.person.userId); + } else { + const guiltyPartyId = blameRequest.expert?.decision?.guiltyPartyId + ? String(blameRequest.expert.decision.guiltyPartyId) + : null; + if (!guiltyPartyId) throw new BadRequestException("Blame request has no guilty party set"); + const damagedParty = parties.find( + (p) => p.person?.userId && String(p.person.userId) !== guiltyPartyId, + ); + if (!damagedParty?.person?.userId) { + throw new BadRequestException("Could not determine damaged party"); + } + damagedUserId = String(damagedParty.person.userId); + } + const existingClaim = await this.claimCaseDbService.findOne({ + blameRequestId: new Types.ObjectId(blameRequestId), + }); + if (existingClaim) { + throw new ConflictException("A claim for this blame case already exists"); + } + const claimNo = await this.generateUniqueClaimNumber(); + const damagedParty = parties.find( + (p) => p.person?.userId && String(p.person.userId) === damagedUserId, + ); + const newClaim = await this.claimCaseDbService.create({ + requestNo: claimNo, + publicId: blameRequest.publicId, + blameRequestId: new Types.ObjectId(blameRequestId), + blameRequestNo: blameRequest.requestNo, + status: ClaimCaseStatus.SELECTING_OUTER_PARTS, + claimStatus: ClaimStatus.PENDING, + workflow: { + currentStep: ClaimWorkflowStep.SELECT_OUTER_PARTS, + nextStep: ClaimWorkflowStep.SELECT_OTHER_PARTS, + completedSteps: [ClaimWorkflowStep.CLAIM_CREATED], + locked: false, + }, + owner: { + userId: new Types.ObjectId(damagedUserId), + userRole: damagedParty?.role as any, + }, + history: [ + { + type: "CLAIM_CREATED", + actor: { + actorId: new Types.ObjectId(expert.sub), + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + timestamp: new Date(), + metadata: { + blameRequestId, + blamePublicId: blameRequest.publicId, + createdByExpert: true, + }, + }, + ], + } as any); + this.logger.log( + `Claim created by field expert: ${newClaim._id} from blame: ${blameRequestId}`, + ); + return { + claimRequestId: String(newClaim._id), + publicId: blameRequest.publicId, + status: ClaimCaseStatus.SELECTING_OUTER_PARTS, + message: "Claim created successfully. You can now fill claim data on behalf of the damaged party.", + }; + } + + /** + * Resolve effective user id for claim operations. + * For FIELD_EXPERT acting on expert-initiated IN_PERSON claim, returns the claim owner's id; otherwise returns currentUserId. + */ + private async resolveClaimEffectiveUserId( + claimCase: any, + currentUserId: string, + actorRole?: string, + ): Promise { + if (actorRole !== RoleEnum.FIELD_EXPERT || !claimCase?.blameRequestId) { + return currentUserId; + } + const blameRequest = await this.blameRequestDbService.findById( + claimCase.blameRequestId.toString(), + ); + if ( + !blameRequest?.expertInitiated || + blameRequest.creationMethod !== "IN_PERSON" || + !blameRequest.initiatedByFieldExpertId + ) { + return currentUserId; + } + if (String(blameRequest.initiatedByFieldExpertId) !== currentUserId) { + return currentUserId; + } + return claimCase.owner?.userId ? String(claimCase.owner.userId) : currentUserId; + } + /** * V2 API: Select damaged outer car parts for claim (Step 2 of claim workflow) * @@ -2899,6 +3034,7 @@ export class ClaimRequestManagementService { claimRequestId: string, body: SelectOuterPartsV2Dto, currentUserId: string, + actor?: { sub: string; role?: string }, ): Promise { try { // 1. Validate claim exists @@ -2910,8 +3046,13 @@ export class ClaimRequestManagementService { ); } - // 2. Validate user is the claim owner (damaged party) - if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== currentUserId) { + const effectiveUserId = await this.resolveClaimEffectiveUserId( + claimCase, + currentUserId, + actor?.role, + ); + // 2. Validate user is the claim owner (or field expert acting for IN_PERSON claim) + if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== effectiveUserId) { throw new ForbiddenException( 'Only the claim owner (damaged party) can select damaged parts' ); @@ -3013,6 +3154,7 @@ export class ClaimRequestManagementService { claimRequestId: string, body: SelectOtherPartsV2Dto, currentUserId: string, + actor?: { sub: string; role?: string }, ): Promise { try { // 1. Validate claim exists @@ -3024,8 +3166,13 @@ export class ClaimRequestManagementService { ); } - // 2. Validate user is the claim owner (damaged party) - if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== currentUserId) { + const effectiveUserId = await this.resolveClaimEffectiveUserId( + claimCase, + currentUserId, + actor?.role, + ); + // 2. Validate user is the claim owner (or field expert for IN_PERSON claim) + if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== effectiveUserId) { throw new ForbiddenException( 'Only the claim owner (damaged party) can submit other parts and bank information' ); @@ -3126,6 +3273,7 @@ export class ClaimRequestManagementService { async getCaptureRequirementsV2( claimRequestId: string, currentUserId: string, + actor?: { sub: string; role?: string }, ): Promise { try { const claimCase = await this.claimCaseDbService.findById(claimRequestId); @@ -3134,7 +3282,12 @@ export class ClaimRequestManagementService { throw new NotFoundException(`Claim case with ID ${claimRequestId} not found`); } - if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== currentUserId) { + const effectiveUserId = await this.resolveClaimEffectiveUserId( + claimCase, + currentUserId, + actor?.role, + ); + if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== effectiveUserId) { throw new ForbiddenException('Only the claim owner can view capture requirements'); } @@ -3158,7 +3311,11 @@ export class ClaimRequestManagementService { return labels[key] || { fa: key, en: key }; }; - // Required documents + // Required documents: CAR_BODY needs 7 (damaged + green card); THIRD_PARTY needs 13 (add guilty_*) + const blameRequest = claimCase.blameRequestId + ? await this.blameRequestDbService.findById(claimCase.blameRequestId.toString()) + : null; + const isCarBody = blameRequest?.type === BlameRequestType.CAR_BODY; const requiredDocsDefinition = [ { key: 'car_green_card', label_fa: 'کارت سبز خودرو', label_en: 'Car Green Card', category: 'general' }, { key: 'damaged_driving_license_front', label_fa: 'گواهینامه طرف آسیب‌دیده - جلو', label_en: 'Damaged Party License - Front', category: 'damaged_party' }, @@ -3168,11 +3325,13 @@ export class ClaimRequestManagementService { { key: 'damaged_car_card_front', label_fa: 'کارت خودرو آسیب‌دیده - جلو', label_en: 'Damaged Car Card - Front', category: 'damaged_party' }, { key: 'damaged_car_card_back', label_fa: 'کارت خودرو آسیب‌دیده - پشت', label_en: 'Damaged Car Card - Back', category: 'damaged_party' }, { key: 'damaged_metal_plate', label_fa: 'پلاک فلزی آسیب‌دیده', label_en: 'Damaged Metal Plate', category: 'damaged_party' }, - { key: 'guilty_driving_license_front', label_fa: 'گواهینامه طرف مقصر - جلو', label_en: 'Guilty Party License - Front', category: 'guilty_party' }, - { key: 'guilty_driving_license_back', label_fa: 'گواهینامه طرف مقصر - پشت', label_en: 'Guilty Party License - Back', category: 'guilty_party' }, - { key: 'guilty_car_card_front', label_fa: 'کارت خودرو مقصر - جلو', label_en: 'Guilty Car Card - Front', category: 'guilty_party' }, - { key: 'guilty_car_card_back', label_fa: 'کارت خودرو مقصر - پشت', label_en: 'Guilty Car Card - Back', category: 'guilty_party' }, - { key: 'guilty_metal_plate', label_fa: 'پلاک فلزی مقصر', label_en: 'Guilty Metal Plate', category: 'guilty_party' }, + ...(isCarBody ? [] : [ + { key: 'guilty_driving_license_front', label_fa: 'گواهینامه طرف مقصر - جلو', label_en: 'Guilty Party License - Front', category: 'guilty_party' }, + { key: 'guilty_driving_license_back', label_fa: 'گواهینامه طرف مقصر - پشت', label_en: 'Guilty Party License - Back', category: 'guilty_party' }, + { key: 'guilty_car_card_front', label_fa: 'کارت خودرو مقصر - جلو', label_en: 'Guilty Car Card - Front', category: 'guilty_party' }, + { key: 'guilty_car_card_back', label_fa: 'کارت خودرو مقصر - پشت', label_en: 'Guilty Car Card - Back', category: 'guilty_party' }, + { key: 'guilty_metal_plate', label_fa: 'پلاک فلزی مقصر', label_en: 'Guilty Metal Plate', category: 'guilty_party' }, + ]), ]; const requiredDocuments = requiredDocsDefinition.map(doc => { @@ -3256,6 +3415,7 @@ export class ClaimRequestManagementService { body: UploadRequiredDocumentV2Dto, file: Express.Multer.File, currentUserId: string, + actor?: { sub: string; role?: string }, ): Promise { try { const claimCase = await this.claimCaseDbService.findById(claimRequestId); @@ -3264,7 +3424,12 @@ export class ClaimRequestManagementService { throw new NotFoundException(`Claim case with ID ${claimRequestId} not found`); } - if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== currentUserId) { + const effectiveUserId = await this.resolveClaimEffectiveUserId( + claimCase, + currentUserId, + actor?.role, + ); + if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== effectiveUserId) { throw new ForbiddenException('Only the claim owner can upload documents'); } @@ -3274,6 +3439,16 @@ export class ClaimRequestManagementService { ); } + // CAR_BODY claims only allow 7 document types (no guilty_*) + const blameForUpload = claimCase.blameRequestId + ? await this.blameRequestDbService.findById(claimCase.blameRequestId.toString()) + : null; + const isCarBodyUpload = blameForUpload?.type === BlameRequestType.CAR_BODY; + const guiltyKeys = ['guilty_driving_license_front', 'guilty_driving_license_back', 'guilty_car_card_front', 'guilty_car_card_back', 'guilty_metal_plate']; + if (isCarBodyUpload && guiltyKeys.includes(body.documentKey)) { + throw new BadRequestException(`Document type ${body.documentKey} is not required for CAR_BODY claims`); + } + // Check if document already uploaded const existingDoc = (claimCase.requiredDocuments as any)?.get?.(body.documentKey); if (existingDoc?.uploaded) { @@ -3318,11 +3493,11 @@ export class ClaimRequestManagementService { }, }; - // Check if all documents are uploaded - const totalDocs = 13; + // Check if all documents are uploaded (7 for CAR_BODY, 13 for THIRD_PARTY) + const totalDocsRequired = isCarBodyUpload ? 7 : 13; const currentDocs = claimCase.requiredDocuments || new Map(); const uploadedCount = (currentDocs instanceof Map ? currentDocs.size : Object.keys(currentDocs).length) + 1; - const allDocumentsUploaded = uploadedCount >= totalDocs; + const allDocumentsUploaded = uploadedCount >= totalDocsRequired; // If all documents uploaded, move to next step if (allDocumentsUploaded) { @@ -3350,7 +3525,7 @@ export class ClaimRequestManagementService { await this.claimCaseDbService.findByIdAndUpdate(claimRequestId, updateData); - const remaining = totalDocs - uploadedCount; + const remaining = totalDocsRequired - uploadedCount; const message = allDocumentsUploaded ? 'All documents uploaded successfully. Please proceed to capture car angles and damaged parts.' : `Document uploaded successfully. ${remaining} documents remaining.`; @@ -3378,6 +3553,7 @@ export class ClaimRequestManagementService { body: CapturePartV2Dto, file: Express.Multer.File, currentUserId: string, + actor?: { sub: string; role?: string }, ): Promise { try { const claimCase = await this.claimCaseDbService.findById(claimRequestId); @@ -3386,7 +3562,12 @@ export class ClaimRequestManagementService { throw new NotFoundException(`Claim case with ID ${claimRequestId} not found`); } - if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== currentUserId) { + const effectiveUserId = await this.resolveClaimEffectiveUserId( + claimCase, + currentUserId, + actor?.role, + ); + if (!claimCase.owner?.userId || claimCase.owner.userId.toString() !== effectiveUserId) { throw new ForbiddenException('Only the claim owner can capture parts'); } @@ -3498,14 +3679,42 @@ export class ClaimRequestManagementService { } /** - * V2 API: Get list of claims for current user + * V2 API: Get list of claims for current user (or for FIELD_EXPERT: claims from their expert-initiated IN_PERSON blame files). */ - async getMyClaimsV2(currentUserId: string): Promise { + async getMyClaimsV2( + currentUserId: string, + actor?: { sub: string; role?: string }, + ): Promise { try { - const claims = await this.claimCaseDbService.find( - { 'owner.userId': new Types.ObjectId(currentUserId) }, - { lean: true }, - ); + let claims: any[]; + if (actor?.role === RoleEnum.FIELD_EXPERT) { + const expertBlameIds = await this.blameRequestDbService + .find( + { + expertInitiated: true, + creationMethod: 'IN_PERSON', + initiatedByFieldExpertId: new Types.ObjectId(currentUserId), + }, + { select: '_id', lean: true }, + ) + .then((docs) => docs.map((d) => (d as any)._id)); + claims = await this.claimCaseDbService.find( + { + $or: [ + { 'owner.userId': new Types.ObjectId(currentUserId) }, + ...(expertBlameIds.length + ? [{ blameRequestId: { $in: expertBlameIds } }] + : []), + ], + }, + { lean: true }, + ); + } else { + claims = await this.claimCaseDbService.find( + { 'owner.userId': new Types.ObjectId(currentUserId) }, + { lean: true }, + ); + } const list = (claims as any[]).map((c) => ({ claimRequestId: c._id.toString(), publicId: c.publicId, @@ -3530,13 +3739,19 @@ export class ClaimRequestManagementService { async getClaimDetailsV2( claimRequestId: string, currentUserId: string, + actor?: { sub: string; role?: string }, ): Promise { try { const claim = await this.claimCaseDbService.findById(claimRequestId); if (!claim) { throw new NotFoundException('Claim request not found'); } - if (!claim.owner?.userId || claim.owner.userId.toString() !== currentUserId) { + const effectiveUserId = await this.resolveClaimEffectiveUserId( + claim, + currentUserId, + actor?.role, + ); + if (!claim.owner?.userId || claim.owner.userId.toString() !== effectiveUserId) { throw new ForbiddenException('You do not have access to this claim'); } diff --git a/src/claim-request-management/claim-request-management.v2.controller.ts b/src/claim-request-management/claim-request-management.v2.controller.ts index 349b801..765751d 100644 --- a/src/claim-request-management/claim-request-management.v2.controller.ts +++ b/src/claim-request-management/claim-request-management.v2.controller.ts @@ -33,7 +33,7 @@ import { ClaimDetailsV2ResponseDto } from "./dto/claim-details-v2.dto"; @Controller("v2/claim-request-management") @ApiBearerAuth() @UseGuards(GlobalGuard, RolesGuard) -@Roles(RoleEnum.USER) +@Roles(RoleEnum.USER, RoleEnum.FIELD_EXPERT) export class ClaimRequestManagementV2Controller { constructor( private readonly claimRequestManagementService: ClaimRequestManagementService, @@ -51,7 +51,7 @@ export class ClaimRequestManagementV2Controller { }) async getMyClaims(@CurrentUser() user: any): Promise { try { - return await this.claimRequestManagementService.getMyClaimsV2(user.sub); + return await this.claimRequestManagementService.getMyClaimsV2(user.sub, user); } catch (error) { if (error instanceof HttpException) throw error; throw new InternalServerErrorException( @@ -91,6 +91,7 @@ export class ClaimRequestManagementV2Controller { return await this.claimRequestManagementService.getClaimDetailsV2( claimRequestId, user.sub, + user, ); } catch (error) { if (error instanceof HttpException) throw error; @@ -231,6 +232,7 @@ export class ClaimRequestManagementV2Controller { claimRequestId, body, user.sub, + user, ); } catch (error) { if (error instanceof HttpException) throw error; @@ -345,6 +347,7 @@ export class ClaimRequestManagementV2Controller { claimRequestId, body, user.sub, + user, ); } catch (error) { if (error instanceof HttpException) throw error; @@ -397,6 +400,7 @@ Returns status of each item (uploaded/captured or not). return await this.claimRequestManagementService.getCaptureRequirementsV2( claimRequestId, user.sub, + user, ); } catch (error) { if (error instanceof HttpException) throw error; @@ -434,16 +438,16 @@ Returns status of each item (uploaded/captured or not). description: ` **Workflow Step:** UPLOAD_REQUIRED_DOCUMENTS (Step 4 of Claim) -**Upload one of the 13 required documents:** +**Upload one of the required documents** (13 for THIRD_PARTY; CAR_BODY may require fewer — see capture-requirements): - car_green_card - damaged_driving_license_front/back - damaged_chassis_number, damaged_engine_photo - damaged_car_card_front/back, damaged_metal_plate -- guilty_driving_license_front/back -- guilty_car_card_front/back, guilty_metal_plate +- guilty_driving_license_front/back, guilty_car_card_front/back, guilty_metal_plate (THIRD_PARTY) -**When all 13 documents are uploaded:** -- Workflow automatically moves to: CAPTURE_PART_DAMAGES (Step 5) +**When all required documents are uploaded:** Workflow moves to CAPTURE_PART_DAMAGES (Step 5). + +**Field expert IN_PERSON:** Same endpoint; use with claim created from expert-initiated IN_PERSON blame to upload documents on behalf of the damaged party. `, }) @ApiParam({ @@ -507,6 +511,7 @@ Returns status of each item (uploaded/captured or not). body, file, user.sub, + user, ); } catch (error) { if (error instanceof HttpException) throw error; @@ -547,6 +552,8 @@ Returns status of each item (uploaded/captured or not). 2. **part**: Damaged parts based on selectedParts from Step 2 **All captures must be completed before user can submit claim.** + +**Field expert IN_PERSON:** Same endpoint; use with claim created from expert-initiated IN_PERSON blame to capture photos on behalf of the damaged party. `, }) @ApiParam({ @@ -598,6 +605,7 @@ Returns status of each item (uploaded/captured or not). body, file, user.sub, + user, ); } catch (error) { if (error instanceof HttpException) throw error; diff --git a/src/expert-blame/expert-blame.service.ts b/src/expert-blame/expert-blame.service.ts index dd14c80..4442d07 100644 --- a/src/expert-blame/expert-blame.service.ts +++ b/src/expert-blame/expert-blame.service.ts @@ -198,7 +198,18 @@ export class ExpertBlameService { // Filter to show only: // 1. Fresh requests (WAITING_FOR_EXPERT and no decision) // 2. Requests decided by current expert + // 3. Expert-initiated: only the initiating field expert sees them const visibleCases = (allCases as Record[]).filter((doc) => { + const expertInitiated = doc.expertInitiated === true; + const initiatedByFieldExpertId = doc.initiatedByFieldExpertId; + + if (expertInitiated && initiatedByFieldExpertId) { + if (String(initiatedByFieldExpertId) !== expertId) { + return false; // Only the initiating field expert can see this file + } + return true; // Initiating expert can see their expert-initiated file + } + const status = doc.status as string; const decision = doc.expert as any; const decidedByExpertId = decision?.decision?.decidedByExpertId; @@ -522,13 +533,20 @@ export class ExpertBlameService { ); } - // Access control: Check if expert has permission to view this request - const decision = (doc.expert as any)?.decision; - const decidedByExpertId = decision?.decidedByExpertId; + // Access control: Expert-initiated files only visible to the initiating field expert + const expertInitiated = doc.expertInitiated === true; + const initiatedByFieldExpertId = doc.initiatedByFieldExpertId; + if (expertInitiated && initiatedByFieldExpertId && String(initiatedByFieldExpertId) !== actorId) { + throw new ForbiddenException( + "Only the field expert who created this file can view and review it.", + ); + } // Allow if: // 1. No decision yet (fresh request) // 2. Decision made by current expert + const decision = (doc.expert as any)?.decision; + const decidedByExpertId = decision?.decidedByExpertId; if (decidedByExpertId && String(decidedByExpertId) !== actorId) { throw new ForbiddenException( "You do not have permission to view this request. It has been handled by another expert.", @@ -660,6 +678,17 @@ export class ExpertBlameService { ); } + // Expert-initiated: only the initiating field expert can lock and review + if ( + request.expertInitiated && + request.initiatedByFieldExpertId && + String(request.initiatedByFieldExpertId) !== actorDetail.sub + ) { + throw new ForbiddenException( + "Only the field expert who created this file can lock and review it.", + ); + } + // Check if locked and not expired if (request.workflow?.locked) { const lockedAt = request.workflow.lockedAt; diff --git a/src/expert-blame/expert-blame.v2.controller.ts b/src/expert-blame/expert-blame.v2.controller.ts index b89afca..ce42b7f 100644 --- a/src/expert-blame/expert-blame.v2.controller.ts +++ b/src/expert-blame/expert-blame.v2.controller.ts @@ -22,7 +22,7 @@ import { ResendRequestDto } from "./dto/resend.dto"; @Controller("v2/expert-blame") @ApiBearerAuth() @UseGuards(LocalActorAuthGuard, RolesGuard) -@Roles(RoleEnum.EXPERT) +@Roles(RoleEnum.EXPERT, RoleEnum.FIELD_EXPERT) export class ExpertBlameV2Controller { constructor(private readonly expertBlameService: ExpertBlameService) {} diff --git a/src/request-management/dto/expert-upload-party-signature.dto.ts b/src/request-management/dto/expert-upload-party-signature.dto.ts new file mode 100644 index 0000000..cfe7098 --- /dev/null +++ b/src/request-management/dto/expert-upload-party-signature.dto.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from "@nestjs/swagger"; + +/** + * Body for field expert uploading a party's signature for expert-initiated IN_PERSON blame. + */ +export class ExpertUploadPartySignatureDto { + @ApiProperty({ + enum: ["FIRST", "SECOND"], + description: "Which party's signature is being uploaded. CAR_BODY: use FIRST only. THIRD_PARTY: FIRST and SECOND.", + }) + partyRole: "FIRST" | "SECOND"; + + @ApiProperty({ + default: true, + description: "Party accepts the blame agreement (true). Set false if party rejects.", + }) + isAccept: boolean; +} diff --git a/src/request-management/dto/send-party-otps.dto.ts b/src/request-management/dto/send-party-otps.dto.ts new file mode 100644 index 0000000..cc7b757 --- /dev/null +++ b/src/request-management/dto/send-party-otps.dto.ts @@ -0,0 +1,19 @@ +import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; + +/** + * Body for field expert to request OTP send to one or two parties for expert-initiated IN_PERSON blame. + * Uses the same SMS flow as /user/send-otp. After this, parties receive SMS with OTP; expert collects and calls verify-party-otps. + */ +export class SendPartyOtpsDto { + @ApiProperty({ + description: "First party phone number (e.g. 09123456789). SMS with OTP will be sent to this number.", + example: "09123456789", + }) + firstPartyPhoneNumber: string; + + @ApiPropertyOptional({ + description: "Second party phone number. Required when blame type is THIRD_PARTY. SMS with OTP will be sent to this number.", + example: "09187654321", + }) + secondPartyPhoneNumber?: string; +} diff --git a/src/request-management/dto/verify-party-otps.dto.ts b/src/request-management/dto/verify-party-otps.dto.ts new file mode 100644 index 0000000..fe5eaf5 --- /dev/null +++ b/src/request-management/dto/verify-party-otps.dto.ts @@ -0,0 +1,31 @@ +import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; + +/** + * Body for field expert to verify one or two party OTPs for expert-initiated IN_PERSON blame. + * First party must verify; second party required only when type is THIRD_PARTY. + */ +export class VerifyPartyOtpsDto { + @ApiProperty({ + description: "First party phone number (must have requested OTP via /user/send-otp)", + example: "09123456789", + }) + firstPartyPhoneNumber: string; + + @ApiProperty({ + description: "OTP received by first party", + example: "258567", + }) + firstPartyOtp: string; + + @ApiPropertyOptional({ + description: "Second party phone number. Required when blame type is THIRD_PARTY.", + example: "09187654321", + }) + secondPartyPhoneNumber?: string; + + @ApiPropertyOptional({ + description: "OTP received by second party. Required when secondPartyPhoneNumber is provided.", + example: "123456", + }) + secondPartyOtp?: string; +} diff --git a/src/request-management/expert-initiated.v2.controller.ts b/src/request-management/expert-initiated.v2.controller.ts index c213229..4b7a392 100644 --- a/src/request-management/expert-initiated.v2.controller.ts +++ b/src/request-management/expert-initiated.v2.controller.ts @@ -31,7 +31,11 @@ import { ExpertCompleteThirdPartyFormDto } from "./dto/expert-complete-third-par import { ExpertCompleteCarBodyFormDto } from "./dto/expert-complete-car-body-form.dto"; import { ExpertAccidentFieldsDto } from "./dto/expert-accident-fields.dto"; import { ExpertCompleteClaimDataDto } from "./dto/expert-complete-claim-data.dto"; +import { ExpertUploadPartySignatureDto } from "./dto/expert-upload-party-signature.dto"; +import { VerifyPartyOtpsDto } from "./dto/verify-party-otps.dto"; +import { SendPartyOtpsDto } from "./dto/send-party-otps.dto"; import { ClaimRequestManagementService } from "src/claim-request-management/claim-request-management.service"; +import { PartyRole } from "./entities/schema/partyRole.enum"; /** * V2 expert-initiated blame API: uses BlameRequest (workflow) model. @@ -80,7 +84,51 @@ export class ExpertInitiatedV2Controller { description: "Creates a BlameRequest with workflow. LINK: parties identified by phone, expert sends link. IN_PERSON: expert fills form later.", }) - @ApiBody({ type: CreateExpertInitiatedFileDto }) + @ApiBody({ + type: CreateExpertInitiatedFileDto, + examples: { + thirdPartyInPerson: { + summary: "Third-party, IN_PERSON (both parties)", + description: + "Expert fills form on-site for both parties.", + value: { + type: "THIRD_PARTY", + creationMethod: "IN_PERSON", + firstPartyPhoneNumber: "09123456789", + secondPartyPhoneNumber: "09187654321", + }, + }, + thirdPartyLink: { + summary: "Third-party, LINK", + description: + "Expert sends link to first and second party by phone.", + value: { + type: "THIRD_PARTY", + creationMethod: "LINK", + firstPartyPhoneNumber: "09123456789", + }, + }, + carBodyInPerson: { + summary: "Car-body, IN_PERSON", + description: "Expert fills form on-site for single party (car body).", + value: { + type: "CAR_BODY", + creationMethod: "IN_PERSON", + firstPartyPhoneNumber: "09123456789", + }, + }, + carBodyLink: { + summary: "Car-body, LINK", + description: + "Expert sends link to party by phone. Only first party phone needed.", + value: { + type: "CAR_BODY", + creationMethod: "LINK", + firstPartyPhoneNumber: "09123456789", + }, + }, + }, + }) @ApiResponse({ status: 201, description: "File created", @@ -103,18 +151,173 @@ export class ExpertInitiatedV2Controller { ); } + @Post("send-link/:requestId") + @ApiOperation({ + summary: "[V2] Send blame link to party/parties (LINK)", + description: + "For expert-initiated LINK files only. Sends the blame link to the first party (and second party for THIRD_PARTY). SMS delivery is mocked for now; first party opens the link and fills the form via the normal flow. Call after create when creationMethod is LINK.", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiResponse({ + status: 200, + description: "Link sent (mocked); recipients can open the link to fill the form", + schema: { + type: "object", + properties: { + sent: { type: "boolean" }, + linkUrl: { type: "string" }, + sentTo: { + type: "array", + items: { + type: "object", + properties: { + role: { type: "string", enum: ["FIRST", "SECOND"] }, + phoneNumber: { type: "string" }, + }, + }, + }, + }, + }, + }) + async sendLinkV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + ) { + return this.requestManagementService.sendLinkV2(expert, requestId); + } + + @Post("send-party-otps/:requestId") + @ApiOperation({ + summary: "[V2] Send OTP to party/parties (IN_PERSON)", + description: + "Sends OTP via SMS to first party (and second party for THIRD_PARTY) using the same flow as /user/send-otp. Parties receive the code; collect it from them and call verify-party-otps. Call this before filling the blame form.", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiBody({ type: SendPartyOtpsDto }) + @ApiResponse({ status: 200, description: "OTP(s) sent; collect codes and call verify-party-otps" }) + async sendPartyOtpsV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @Body() dto: SendPartyOtpsDto, + ) { + return this.requestManagementService.sendPartyOtpsV2(expert, requestId, dto); + } + + @Post("verify-party-otps/:requestId") + @ApiOperation({ + summary: "[V2] Verify party OTPs (IN_PERSON)", + description: + "After send-party-otps, parties receive SMS. They tell you the code; submit it here. Required before complete-blame-data.", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiBody({ type: VerifyPartyOtpsDto }) + @ApiResponse({ status: 200, description: "OTPs verified; expert can proceed to complete-blame-data" }) + async verifyPartyOtpsV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @Body() dto: VerifyPartyOtpsDto, + ) { + return this.requestManagementService.verifyPartyOtpsV2(expert, requestId, dto); + } + @Post("complete-blame-data/:requestId") @ApiOperation({ summary: "[V2] Submit all blame data (IN_PERSON)", description: - "For IN_PERSON files only. Send THIRD_PARTY or CAR_BODY form; completes the BlameRequest.", + "For IN_PERSON files only. Send THIRD_PARTY or CAR_BODY form. After this, status becomes WAITING_FOR_SIGNATURES; use upload-party-signature to collect party signatures.", }) @ApiParam({ name: "requestId", description: "Blame request ID" }) @ApiBody({ - description: - "ExpertCompleteThirdPartyFormDto for THIRD_PARTY or ExpertCompleteCarBodyFormDto for CAR_BODY", + description: "Choose THIRD_PARTY or CAR_BODY example according to the file type. All nested fields are listed so you can fill or test without guessing property names.", + examples: { + THIRD_PARTY: { + summary: "THIRD_PARTY", + description: "Use when the blame file type is THIRD_PARTY", + value: { + firstPartyPhoneNumber: "09123456789", + firstPartyInitialForm: { + expertOpinion: false, + imDamaged: false, + imGuilty: true, + }, + firstPartyPlate: { + nationalCodeOfInsurer: "", + nationalCodeOfDriver: "", + insurerLicense: "", + driverLicense: "", + plate: { leftDigits: 12, centerAlphabet: "الف", centerDigits: 345, ir: 22 }, + driverIsInsurer: true, + isNewCar: false, + userNoCertificate: false, + insurerBirthday: 13770624, + driverBirthday: "1370-01-01", + }, + firstPartyLocation: { lat: 35.6892, lon: 51.389 }, + firstPartyDescription: { desc: "توضیح حادثه طرف اول" }, + secondParty: { + phoneNumber: "09187654321", + initialForm: { + expertOpinion: false, + imDamaged: true, + imGuilty: false, + }, + plate: { + nationalCodeOfInsurer: "", + nationalCodeOfDriver: "", + insurerLicense: "", + driverLicense: "", + plate: { leftDigits: 91, centerAlphabet: "ن", centerDigits: 174, ir: 79 }, + driverIsInsurer: true, + isNewCar: false, + userNoCertificate: false, + insurerBirthday: 13700720, + driverBirthday: "1370-01-01", + }, + location: { lat: 35.6892, lon: 51.389 }, + description: { desc: "توضیح حادثه طرف دوم" }, + }, + guiltyPartyPhoneNumber: "09123456789", + }, + }, + CAR_BODY: { + summary: "CAR_BODY", + description: "Use when the blame file type is CAR_BODY", + value: { + firstPartyPhoneNumber: "09123456789", + firstPartyInitialForm: { + expertOpinion: false, + imDamaged: false, + imGuilty: true, + }, + carBodyForm: { car: true, object: false }, + firstPartyPlate: { + plateId: "", + nationalCodeOfInsurer: "", + nationalCodeOfDriver: "", + insurerLicense: "", + driverLicense: "", + plate: { leftDigits: 12, centerAlphabet: "الف", centerDigits: 345, ir: 22 }, + driverIsInsurer: true, + isNewCar: false, + userNoCertificate: false, + insurerBirthday: 1370, + driverBirthday: "1370-01-01", + }, + firstPartyLocation: { lat: 35.6892, lon: 51.389 }, + firstPartyDescription: { + desc: "توضیح حادثه", + accidentDate: "2025-01-15", + accidentTime: "14:30", + weatherCondition: "صاف", + roadCondition: "خشک", + lightCondition: "روز", + }, + }, + }, + }, + schema: { type: "object" }, }) - @ApiResponse({ status: 200, description: "Blame form completed" }) + @ApiResponse({ status: 200, description: "Blame form completed; next: upload party signature(s)" }) async completeBlameDataV2( @CurrentUser() expert: any, @Param("requestId") requestId: string, @@ -223,6 +426,76 @@ export class ExpertInitiatedV2Controller { ); } + @Post("upload-party-signature/:requestId") + @ApiOperation({ + summary: "[V2] Expert uploads party signature (IN_PERSON)", + description: + "For IN_PERSON only. Upload a party's signature collected on-site. CAR_BODY: use partyRole FIRST once. THIRD_PARTY: upload FIRST then SECOND. When all required parties have signed, blame case completes.", + }) + @ApiParam({ name: "requestId", description: "Blame request ID" }) + @ApiConsumes("multipart/form-data") + @ApiBody({ + schema: { + type: "object", + required: ["partyRole", "sign"], + properties: { + partyRole: { type: "string", enum: ["FIRST", "SECOND"] }, + isAccept: { type: "boolean", default: true }, + sign: { type: "string", format: "binary" }, + }, + }, + }) + @UseInterceptors( + FileInterceptor("sign", { + limits: { fileSize: 10 * 1024 * 1024 }, + storage: diskStorage({ + destination: "./files/signs", + filename: (req, file, callback) => { + const unique = Date.now(); + const ex = extname(file.originalname); + callback(null, `expert-party-${unique}${ex}`); + }, + }), + }), + ) + @ApiResponse({ status: 200, description: "Signature recorded" }) + async uploadPartySignatureV2( + @CurrentUser() expert: any, + @Param("requestId") requestId: string, + @Body() body: { partyRole?: string; isAccept?: string | boolean }, + @UploadedFile() sign?: Express.Multer.File, + ) { + const partyRole = (body.partyRole === "FIRST" || body.partyRole === "SECOND") + ? body.partyRole + : ("FIRST" as const); + const isAccept = body.isAccept === false || body.isAccept === "false" ? false : true; + return this.requestManagementService.expertUploadPartySignatureV2( + expert, + requestId, + partyRole as PartyRole, + isAccept, + sign!, + ); + } + + @Post("create-claim-from-blame/:blameRequestId") + @ApiOperation({ + summary: "[V2] Create claim from expert-initiated IN_PERSON blame", + description: + "Field expert creates a claim on behalf of the damaged party. Blame must be COMPLETED (signatures collected). Then use claim v2 endpoints to fill parts, documents, and captures.", + }) + @ApiParam({ name: "blameRequestId", description: "Completed blame request ID" }) + @ApiResponse({ status: 201, description: "Claim created" }) + async createClaimFromBlame( + @CurrentUser() expert: any, + @Param("blameRequestId") blameRequestId: string, + ) { + return this.claimRequestManagementService.createClaimFromBlameForExpertV2( + blameRequestId, + expert, + ); + } + @Post("complete-claim-data/:claimRequestId") @ApiOperation({ summary: "Submit claim-needed data (expert-initiated IN_PERSON)", diff --git a/src/request-management/request-management.module.ts b/src/request-management/request-management.module.ts index a5e8bb6..ae14395 100644 --- a/src/request-management/request-management.module.ts +++ b/src/request-management/request-management.module.ts @@ -12,7 +12,9 @@ import { UsersModule } from "src/users/users.module"; import { CronModule } from "src/utils/cron/cron.module"; import { SmsManagerModule } from "src/utils/sms-manager/sms-manager.module"; import { PublicIdModule } from "src/utils/public-id/public-id.module"; +import { HashModule } from "src/utils/hash/hash.module"; import { WorkflowStepManagementModule } from "src/workflow-step-management/workflow-step-management.module"; +import { AuthModule } from "src/auth/auth.module"; import { BlameDocumentDbService } from "./entities/db-service/blame-document.db.service"; import { BlameVoiceDbService } from "./entities/db-service/blame.voice.db.service"; import { UserSignDbService } from "./entities/db-service/sign.db.service"; @@ -44,6 +46,7 @@ import { ExpertInitiatedV2Controller } from "./expert-initiated.v2.controller"; SandHubModule, SmsManagerModule, PublicIdModule, + HashModule, WorkflowStepManagementModule, PlatesModule, MulterModule.register({ @@ -59,6 +62,7 @@ import { ExpertInitiatedV2Controller } from "./expert-initiated.v2.controller"; ]), forwardRef(() => ClaimRequestManagementModule), CronModule, + AuthModule, ], controllers: [ RequestManagementController, diff --git a/src/request-management/request-management.service.ts b/src/request-management/request-management.service.ts index 8fa6b4a..ce82201 100644 --- a/src/request-management/request-management.service.ts +++ b/src/request-management/request-management.service.ts @@ -65,6 +65,8 @@ import { WorkflowStepModel } from "src/workflow-step-management/entities/schema/ import { BlameStatus } from "src/Types&Enums/blame-request-management/blameStatus.enum"; import { CaseStatus } from "src/Types&Enums/blame-request-management/caseStatus.enum"; import { UploadContext } from "./entities/schema/blame-voice.schema"; +import { HashService } from "src/utils/hash/hash.service"; +import { UserAuthService } from "src/auth/auth-services/user.auth.service"; @Injectable() export class RequestManagementService { @@ -78,6 +80,14 @@ export class RequestManagementService { ); } + /** Convert plate (string or { ir, leftDigits, centerAlphabet, centerDigits }) to string for vehicle.plateId */ + private plateToPlateIdString(plate: any): string { + if (plate == null) return ""; + if (typeof plate === "string") return plate; + const p = plate as { ir?: number; leftDigits?: number; centerAlphabet?: string; centerDigits?: number }; + return [p.ir, p.leftDigits, p.centerAlphabet, p.centerDigits].filter((x) => x != null).join("-"); + } + private getPartyIndex(req: any, role: PartyRole): number { return Array.isArray(req.parties) ? req.parties.findIndex((p) => p?.role === role) @@ -292,6 +302,8 @@ export class RequestManagementService { private readonly claimRequestManagementDbService: ClaimRequestManagementDbService, private readonly publicIdService: PublicIdService, private readonly workflowStepDbService: WorkflowStepDbService, + private readonly hashService: HashService, + private readonly userAuthService: UserAuthService, ) {} async createRequestV2(user: any, type: BlameRequestType) { @@ -738,12 +750,12 @@ export class RequestManagementService { let inquiryRaw: any; let inquiryMapped: any; try { - const inquiry = await this.sandHubService.getTejaratBlockInquiry({ - plate: body.plate, - nationalCodeOfInsurer: body.nationalCodeOfInsurer, - }); - inquiryRaw = inquiry.raw; - inquiryMapped = inquiry.mapped; + // const inquiry = await this.sandHubService.getTejaratBlockInquiry({ + // plate: body.plate, + // nationalCodeOfInsurer: body.nationalCodeOfInsurer, + // }); + // inquiryRaw = inquiry.raw; + // inquiryMapped = inquiry.mapped; this.logger.log( `[TEJARAT] block inquiry raw for request=${req._id}: ${JSON.stringify(inquiryRaw)}`, ); @@ -808,7 +820,10 @@ export class RequestManagementService { if (!party.vehicle) party.vehicle = {} as any; party.vehicle.isNew = body.isNewCar; - party.vehicle.plateId = body.plateId; + party.vehicle.plateId = + typeof body.plateId === "string" + ? body.plateId + : this.plateToPlateIdString(body.plate); party.vehicle.name = inquiryMapped?.MapTypNam; party.vehicle.type = `${inquiryMapped?.UsageField} / ${inquiryMapped?.MapUsageName || "-"}`; party.vehicle.inquiry = { @@ -1140,9 +1155,53 @@ export class RequestManagementService { ); } - // Check if second party already exists + // Check if second party already exists (e.g. expert-initiated LINK: expert already added both parties) const secondPartyIdx = this.getPartyIndex(req, PartyRole.SECOND); if (secondPartyIdx !== -1) { + if ( + req.expertInitiated && + req.creationMethod === CreationMethod.LINK + ) { + // Just advance workflow; second party already in parties. Optionally resend SMS. + const secondPartyPhone = + (req.parties[secondPartyIdx]?.person as any)?.phoneNumber || phoneNumber; + req.status = CaseStatus.WAITING_FOR_SECOND_PARTY; + await this.advanceWorkflowToNext(req, stepKey); + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "SECOND_PARTY_INVITED", + actor: { + actorId: Types.ObjectId.isValid(user?.sub) + ? new Types.ObjectId(user.sub) + : undefined, + actorName: user?.fullName, + actorType: "user", + }, + metadata: { secondPartyPhone, expertInitiatedLink: true }, + } as any); + await (req as any).save(); + const url = `${process.env.URL}/${frontendRoute}?token=${requestId}`; + try { + await this.smsManagerService.verifyLookUp({ + token: url, + template: "yara724-invite-link", + receptor: secondPartyPhone, + }); + this.logger.log( + `[SMS] Invitation resent to ${secondPartyPhone} for expert-initiated request ${req.publicId}`, + ); + } catch (err) { + this.logger.error( + `[SMS] Failed to send invitation to ${secondPartyPhone}: ${err?.message || err}`, + ); + } + return { + requestId: req._id, + publicId: req.publicId, + workflow: req.workflow, + invitationUrl: url, + }; + } throw new ConflictException("Second party already added to this request"); } @@ -1602,47 +1661,48 @@ export class RequestManagementService { } } + // TODO: Activate // --- Proceed with existing logic if the check passes --- // 1) Main third-party/block inquiry (existing behavior) - const sanHubResponse = await this.sandHubService.getSandHubResponse({ - plate: body.plate, - nationalCodeOfInsurer: body.nationalCodeOfInsurer, - }); + // const sanHubResponse = await this.sandHubService.getSandHubResponse({ + // plate: body.plate, + // nationalCodeOfInsurer: body.nationalCodeOfInsurer, + // }); - if (sanHubResponse.Error) { - throw new HttpException( - sanHubResponse.Error.Message, - HttpStatus.BAD_REQUEST, - ); - } + // if (sanHubResponse.Error) { + // throw new HttpException( + // sanHubResponse.Error.Message, + // HttpStatus.BAD_REQUEST, + // ); + // } // 2) Personal inquiry (new shared SandHub API) // This is a best-effort call; if it fails we log and continue. - try { - const personalInquiry = await this.sandHubService.getPersonalInquiry( - body.nationalCodeOfInsurer, - body.insurerBirthday, - ); - this.logger.log( - `[SANDHUB] Personal inquiry succeeded for nationalCode=${body.nationalCodeOfInsurer}: ${JSON.stringify( - personalInquiry, - )}`, - ); - // NOTE: We are not persisting this data yet; once the exact fields - // are finalized, we can map and store them on the request document. - } catch (err) { - this.logger.error( - `[SANDHUB] Personal inquiry failed for nationalCode=${body.nationalCodeOfInsurer}: ${err?.message || err}`, - ); - } + // try { + // const personalInquiry = await this.sandHubService.getPersonalInquiry( + // body.nationalCodeOfInsurer, + // body.insurerBirthday, + // ); + // this.logger.log( + // `[SANDHUB] Personal inquiry succeeded for nationalCode=${body.nationalCodeOfInsurer}: ${JSON.stringify( + // personalInquiry, + // )}`, + // ); + // // NOTE: We are not persisting this data yet; once the exact fields + // // are finalized, we can map and store them on the request document. + // } catch (err) { + // this.logger.error( + // `[SANDHUB] Personal inquiry failed for nationalCode=${body.nationalCodeOfInsurer}: ${err?.message || err}`, + // ); + // } - return await this.addPlate( - sanHubResponse, - request, - user, - body, - isFirstParty ? "firstParty" : "secondParty", - ); + // return await this.addPlate( + // sanHubResponse, + // request, + // user, + // body, + // isFirstParty ? "firstParty" : "secondParty", + // ); } async carBodyFormStep( @@ -3463,6 +3523,212 @@ export class RequestManagementService { return result; } + /** + * V2: Send blame link to first party (and second party for THIRD_PARTY) for expert-initiated LINK method. + * SMS delivery is mocked for now; replace with real SMS provider later. First party opens the link and fills the form via normal v2 flow. + */ + async sendLinkV2( + expert: any, + requestId: string, + ): Promise<{ + sent: boolean; + linkUrl: string; + sentTo: { role: string; phoneNumber: string }[]; + }> { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated || req.creationMethod !== CreationMethod.LINK) { + throw new BadRequestException( + "This endpoint is only for expert-initiated LINK blame files. Create the file with creationMethod LINK first.", + ); + } + this.verifyExpertAccessForBlameV2(req, expert); + + const baseUrl = + process.env.FRONTEND_BASE_URL || process.env.APP_URL || ""; + const linkUrl = baseUrl + ? `${baseUrl.replace(/\/$/, "")}/blame/${requestId}` + : ""; + + const sentTo: { role: string; phoneNumber: string }[] = []; + const firstIdx = this.getPartyIndex(req, PartyRole.FIRST); + if (firstIdx !== -1 && req.parties[firstIdx]?.person?.phoneNumber) { + const phone = req.parties[firstIdx].person.phoneNumber; + this.logger.log( + `[MOCK SMS] Would send link to first party ${phone}: ${linkUrl}`, + ); + sentTo.push({ role: PartyRole.FIRST, phoneNumber: phone }); + } + if (req.type === BlameRequestType.THIRD_PARTY) { + const secondIdx = this.getPartyIndex(req, PartyRole.SECOND); + if (secondIdx !== -1 && req.parties[secondIdx]?.person?.phoneNumber) { + const phone = req.parties[secondIdx].person.phoneNumber; + this.logger.log( + `[MOCK SMS] Would send link to second party ${phone}: ${linkUrl}`, + ); + sentTo.push({ role: PartyRole.SECOND, phoneNumber: phone }); + } + } + + if (!Array.isArray((req as any).history)) (req as any).history = []; + (req as any).history.push({ + type: "LINK_SENT", + actor: { + actorId: new Types.ObjectId(expert.sub), + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + metadata: { linkUrl, sentTo }, + }); + await (req as any).save(); + + return { sent: true, linkUrl, sentTo }; + } + + /** + * V2: Send OTP via SMS to one or two parties for expert-initiated IN_PERSON blame. + * Uses the same flow as /user/send-otp (same template, expiry). After this, parties receive SMS; expert collects OTPs and calls verify-party-otps. + */ + async sendPartyOtpsV2( + expert: any, + requestId: string, + dto: { firstPartyPhoneNumber: string; secondPartyPhoneNumber?: string }, + ): Promise<{ sent: boolean; message: string }> { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated || req.creationMethod !== CreationMethod.IN_PERSON) { + throw new BadRequestException( + "This endpoint is only for expert-initiated IN_PERSON blame files.", + ); + } + this.verifyExpertAccessForBlameV2(req, expert); + if (req.type === BlameRequestType.THIRD_PARTY && !dto.secondPartyPhoneNumber) { + throw new BadRequestException( + "Second party phone number is required for THIRD_PARTY. Provide secondPartyPhoneNumber to send OTP to both parties.", + ); + } + const sent: string[] = []; + try { + await this.userAuthService.sendOtpRequest(dto.firstPartyPhoneNumber); + sent.push(dto.firstPartyPhoneNumber); + } catch (e: any) { + if (e?.message?.includes("Wait for expiry")) { + throw new BadRequestException( + `First party (${dto.firstPartyPhoneNumber}): OTP was recently sent. Wait for the expiry time before requesting again.`, + ); + } + throw e; + } + if (dto.secondPartyPhoneNumber) { + try { + await this.userAuthService.sendOtpRequest(dto.secondPartyPhoneNumber); + sent.push(dto.secondPartyPhoneNumber); + } catch (e: any) { + if (e?.message?.includes("Wait for expiry")) { + throw new BadRequestException( + `Second party (${dto.secondPartyPhoneNumber}): OTP was recently sent. Wait for the expiry time before requesting again.`, + ); + } + throw e; + } + } + return { + sent: true, + message: + sent.length === 2 + ? `OTP sent to both parties (${sent.join(", ")}). Have them tell you the code, then call verify-party-otps.` + : `OTP sent to ${sent[0]}. Have the party tell you the code, then call verify-party-otps.`, + }; + } + + /** + * V2: Verify one or two party OTPs for expert-initiated IN_PERSON blame. + * Call this after send-party-otps (or after parties requested OTP via /user/send-otp). On success, parties are linked to their user ids so the expert can proceed with complete-blame-data. + */ + async verifyPartyOtpsV2( + expert: any, + requestId: string, + dto: { + firstPartyPhoneNumber: string; + firstPartyOtp: string; + secondPartyPhoneNumber?: string; + secondPartyOtp?: string; + }, + ): Promise<{ verified: boolean; message: string }> { + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated || req.creationMethod !== CreationMethod.IN_PERSON) { + throw new BadRequestException( + "This endpoint is only for expert-initiated IN_PERSON blame files.", + ); + } + this.verifyExpertAccessForBlameV2(req, expert); + + const now = Date.now(); + const verifyOne = async (phone: string, otp: string): Promise => { + const user = await this.userDbService.findOne({ + $or: [{ username: phone }, { mobile: phone }], + }); + if (!user) throw new BadRequestException(`User not found for phone: ${phone}`); + const u = user as any; + if (u.otp == null) throw new BadRequestException(`No OTP requested for ${phone}. User must call /user/send-otp first.`); + if (u.otpExpire < now) throw new BadRequestException(`OTP expired for ${phone}. User must request a new OTP.`); + const valid = await this.hashService.compare(otp, u.otp); + if (!valid) throw new BadRequestException(`Invalid OTP for ${phone}`); + return u._id; + }; + + const firstUserId = await verifyOne(dto.firstPartyPhoneNumber, dto.firstPartyOtp); + if (!Array.isArray(req.parties)) req.parties = []; + const firstIdx = req.parties.findIndex((p: any) => p?.role === PartyRole.FIRST); + if (firstIdx === -1) throw new BadRequestException("First party not found on request"); + if (!req.parties[firstIdx].person) req.parties[firstIdx].person = {} as any; + req.parties[firstIdx].person.userId = firstUserId; + req.parties[firstIdx].person.phoneNumber = dto.firstPartyPhoneNumber; + + if (req.type === BlameRequestType.THIRD_PARTY && dto.secondPartyPhoneNumber && dto.secondPartyOtp) { + const secondUserId = await verifyOne(dto.secondPartyPhoneNumber, dto.secondPartyOtp); + let secondIdx = req.parties.findIndex((p: any) => p?.role === PartyRole.SECOND); + if (secondIdx === -1) { + req.parties.push({ + role: PartyRole.SECOND, + person: { + userId: secondUserId, + phoneNumber: dto.secondPartyPhoneNumber, + }, + } as any); + } else { + if (!req.parties[secondIdx].person) req.parties[secondIdx].person = {} as any; + req.parties[secondIdx].person.userId = secondUserId; + req.parties[secondIdx].person.phoneNumber = dto.secondPartyPhoneNumber; + } + } else if (req.type === BlameRequestType.THIRD_PARTY && (dto.secondPartyPhoneNumber || dto.secondPartyOtp)) { + throw new BadRequestException("For THIRD_PARTY both secondPartyPhoneNumber and secondPartyOtp are required."); + } + + if (!Array.isArray(req.history)) req.history = []; + req.history.push({ + type: "PARTY_OTPS_VERIFIED", + actor: { + actorId: new Types.ObjectId(expert.sub), + actorName: `${expert.firstName || ""} ${expert.lastName || ""}`.trim(), + actorType: "field_expert", + }, + metadata: { + firstPartyVerified: true, + secondPartyVerified: req.type === BlameRequestType.THIRD_PARTY && !!dto.secondPartyPhoneNumber, + }, + } as any); + await (req as any).save(); + + return { + verified: true, + message: req.type === BlameRequestType.THIRD_PARTY && dto.secondPartyPhoneNumber + ? "Both parties verified. You can proceed to fill the blame form." + : "First party verified. You can proceed to fill the blame form.", + }; + } + /** * List all expert-initiated blame files for the current field expert (their panel). * Only files where initiatedBy === current user are returned. @@ -3684,7 +3950,7 @@ export class RequestManagementService { driverBirthday: firstPartyPlate.driverBirthday, }, vehicle: { - plateId: firstPartyPlate.plate, + plateId: this.plateToPlateIdString(firstPartyPlate.plate) || (firstPartyPlate as any).plateId, name: sandHubReport?.MapTypNam || sandHubReport?.CarName, model: sandHubReport?.MapTypNam, type: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`, @@ -3723,7 +3989,7 @@ export class RequestManagementService { req.parties = [firstParty]; req.workflow = { - currentStep: WorkflowStep.COMPLETED, + currentStep: WorkflowStep.WAITING_FOR_SIGNATURES as any, nextStep: undefined, completedSteps: [ WorkflowStep.CREATED, @@ -3736,7 +4002,7 @@ export class RequestManagementService { ].filter((s) => s), locked: false, }; - req.status = CaseStatus.COMPLETED; + req.status = CaseStatus.WAITING_FOR_SIGNATURES; req.blameStatus = BlameStatus.AGREED; (req as any).filledBy = FilledBy.EXPERT; @@ -3827,7 +4093,7 @@ export class RequestManagementService { driverBirthday: plateDto.driverBirthday, }, vehicle: { - plateId: plateDto.plate, + plateId: this.plateToPlateIdString(plateDto.plate) || (plateDto as any).plateId, name: sandHubReport?.MapTypNam || sandHubReport?.CarName, model: sandHubReport?.MapTypNam, type: `${sandHubReport?.UsageField || ""} / ${sandHubReport?.MapUsageName || "-"}`, @@ -3867,8 +4133,14 @@ export class RequestManagementService { ); req.parties = [firstParty, secondParty]; + const guiltyPartyId = + formData.guiltyPartyPhoneNumber === formData.firstPartyPhoneNumber + ? String(firstPartyUserId) + : String(secondPartyUserId); + if (!req.expert) req.expert = {} as any; + req.expert.decision = { guiltyPartyId: new Types.ObjectId(guiltyPartyId) } as any; req.workflow = { - currentStep: WorkflowStep.COMPLETED, + currentStep: WorkflowStep.WAITING_FOR_SIGNATURES as any, nextStep: undefined, completedSteps: [ WorkflowStep.CREATED, @@ -3885,7 +4157,7 @@ export class RequestManagementService { ].filter((s) => s), locked: false, }; - req.status = CaseStatus.COMPLETED; + req.status = CaseStatus.WAITING_FOR_SIGNATURES; req.blameStatus = BlameStatus.AGREED; (req as any).filledBy = FilledBy.EXPERT; @@ -4006,6 +4278,116 @@ export class RequestManagementService { return { requestId: req._id }; } + /** + * V2: Expert uploads a party's signature for expert-initiated IN_PERSON blame. + * CAR_BODY: upload FIRST only. THIRD_PARTY: upload FIRST then SECOND. + * When all required parties have signed, status becomes COMPLETED. + */ + async expertUploadPartySignatureV2( + expert: any, + requestId: string, + partyRole: PartyRole, + isAccept: boolean, + signFile: Express.Multer.File, + ): Promise { + if (!signFile) { + throw new BadRequestException("A signature file is required"); + } + const req = await this.blameRequestDbService.findById(requestId); + if (!req) throw new NotFoundException("Request not found"); + if (!req.expertInitiated || req.creationMethod !== CreationMethod.IN_PERSON) { + throw new BadRequestException( + "This endpoint is only for expert-initiated IN_PERSON blame files.", + ); + } + this.verifyExpertAccessForBlameV2(req, expert); + if (req.status !== CaseStatus.WAITING_FOR_SIGNATURES) { + throw new BadRequestException( + "Request is not waiting for signatures. Current status: " + req.status, + ); + } + const partyIndex = this.getPartyIndex(req, partyRole); + if (partyIndex === -1) { + throw new BadRequestException(`Party ${partyRole} not found on this request`); + } + if (req.type === BlameRequestType.CAR_BODY && partyRole === PartyRole.SECOND) { + throw new BadRequestException("CAR_BODY has only first party; use partyRole FIRST."); + } + const party = req.parties[partyIndex]; + if (party.confirmation) { + throw new BadRequestException( + `Party ${partyRole} has already signed.`, + ); + } + const partyUserId = party.person?.userId ? String(party.person.userId) : undefined; + const signDoc = await this.userSign.create({ + fileName: signFile.filename, + userId: partyUserId || expert.sub, + path: signFile.path, + requestId: new Types.ObjectId(requestId), + }); + const signatureData = { + fileId: String((signDoc as any)._id), + fileName: signFile.filename, + fileUrl: signFile.path, + }; + const updatePayload: any = { + $set: { + [`parties.${partyIndex}.confirmation`]: { + partyRole: party.role, + accepted: isAccept, + signature: signatureData, + }, + }, + }; + await this.blameRequestDbService.findByIdAndUpdate(requestId, updatePayload); + const updatedRequest = await this.blameRequestDbService.findById(requestId); + const requiredCount = req.type === BlameRequestType.CAR_BODY ? 1 : 2; + const signedParties = (updatedRequest.parties || []).filter( + (p) => p.confirmation != null && p.confirmation !== undefined, + ); + let finalStatus = CaseStatus.WAITING_FOR_SIGNATURES; + let message = "Signature recorded successfully."; + if (signedParties.length >= requiredCount) { + const allAccepted = updatedRequest.parties + .slice(0, requiredCount) + .every((p) => p.confirmation?.accepted === true); + if (allAccepted) { + finalStatus = CaseStatus.COMPLETED; + message = "All parties have signed. Blame case completed."; + await this.blameRequestDbService.findByIdAndUpdate(requestId, { + $set: { + status: CaseStatus.COMPLETED, + "workflow.currentStep": WorkflowStep.COMPLETED as any, + "workflow.nextStep": null, + }, + $push: { + "workflow.completedSteps": WorkflowStep.WAITING_FOR_SIGNATURES as any, + }, + }); + } else { + finalStatus = CaseStatus.CANCELLED; + message = "One or both parties rejected. Case requires in-person resolution."; + await this.blameRequestDbService.findByIdAndUpdate(requestId, { + $set: { + status: CaseStatus.CANCELLED, + "workflow.currentStep": WorkflowStep.COMPLETED as any, + "workflow.nextStep": null, + }, + $push: { + "workflow.completedSteps": WorkflowStep.WAITING_FOR_SIGNATURES as any, + }, + }); + } + } + return { + requestId: String(req._id), + accepted: isAccept, + status: finalStatus, + message, + }; + } + /** * V2: Expert adds accident fields to expert-initiated BlameRequest. */