commit 83fd5c1a86cddaa68f0a5b5475b7785b1c1c9699 Author: webserver-lab Date: Tue May 26 16:00:09 2026 +0330 first commit diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..5577c3f --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ +JWT_SECRET=a4f6c1f6b9b5c1c7c3a63cce9f9c5b7d6f8e3c7c2a0f7a1d9e0b4c8d2a1f5e6c3b2d9f0a6e7c4b1d8f3a2c5e6d9b7a0 \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 0000000..5577c3f --- /dev/null +++ b/.env.production @@ -0,0 +1 @@ +JWT_SECRET=a4f6c1f6b9b5c1c7c3a63cce9f9c5b7d6f8e3c7c2a0f7a1d9e0b4c8d2a1f5e6c3b2d9f0a6e7c4b1d8f3a2c5e6d9b7a0 \ No newline at end of file diff --git a/.sequelizerc b/.sequelizerc new file mode 100644 index 0000000..463b6b8 --- /dev/null +++ b/.sequelizerc @@ -0,0 +1,8 @@ +const path = require("path"); + +module.exports = { + config: path.resolve("sequelize.config.js"), + "models-path": path.resolve("src/models"), + "seeders-path": path.resolve("seeders"), + "migrations-path": path.resolve("migrations") +}; diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..2c72d56 --- /dev/null +++ b/index.ts @@ -0,0 +1,2 @@ +import ServerApplication from "./src/app"; +new ServerApplication(); diff --git a/migrations/20260520050834-create-tables.js b/migrations/20260520050834-create-tables.js new file mode 100644 index 0000000..b6e01de --- /dev/null +++ b/migrations/20260520050834-create-tables.js @@ -0,0 +1,22 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up (queryInterface, Sequelize) { + /** + * Add altering commands here. + * + * Example: + * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + }, + + async down (queryInterface, Sequelize) { + /** + * Add reverting commands here. + * + * Example: + * await queryInterface.dropTable('users'); + */ + } +}; diff --git a/migrations/20260526040515-create-tables.js b/migrations/20260526040515-create-tables.js new file mode 100644 index 0000000..b6e01de --- /dev/null +++ b/migrations/20260526040515-create-tables.js @@ -0,0 +1,22 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up (queryInterface, Sequelize) { + /** + * Add altering commands here. + * + * Example: + * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + }, + + async down (queryInterface, Sequelize) { + /** + * Add reverting commands here. + * + * Example: + * await queryInterface.dropTable('users'); + */ + } +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6647e23 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3496 @@ +{ + "name": "backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "backend", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "auto-bind": "^4.0.0", + "bcryptjs": "^3.0.3", + "cookie-parser": "^1.4.7", + "cors": "^2.8.6", + "csurf": "^1.11.0", + "express": "^5.2.1", + "express-rate-limit": "^8.5.2", + "helmet": "^8.1.0", + "hpp": "^0.2.3", + "http-errors": "^2.0.1", + "jsonwebtoken": "^9.0.3", + "multer": "^2.1.1", + "pg": "^8.20.0", + "pg-hstore": "^2.3.4", + "sequelize": "^6.37.8" + }, + "devDependencies": { + "@types/cookie-parser": "^1.4.10", + "@types/cors": "^2.8.19", + "@types/csurf": "^1.11.5", + "@types/express": "^5.0.6", + "@types/hpp": "^0.2.7", + "@types/jsonwebtoken": "^9.0.10", + "@types/node": "^25.9.0", + "dotenv": "^17.4.2", + "nodemon": "^3.1.14", + "sequelize-cli": "^6.6.5", + "ts-node": "^10.9.2", + "typescript": "^6.0.3" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://package-mirror.liara.ir/repository/npm/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.12", + "resolved": "https://package-mirror.liara.ir/repository/npm/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://package-mirror.liara.ir/repository/npm/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cookie-parser": { + "version": "1.4.10", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/cookie-parser/-/cookie-parser-1.4.10.tgz", + "integrity": "sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/csurf": { + "version": "1.11.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/csurf/-/csurf-1.11.5.tgz", + "integrity": "sha512-5rw87+5YGixyL2W8wblSUl5DSZi5YOlXE6Awwn2ofLvqKr/1LruKffrQipeJKUX44VaxKj8m5es3vfhltJTOoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/hpp": { + "version": "0.2.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/hpp/-/hpp-0.2.7.tgz", + "integrity": "sha512-YSQBkTwZepklRez0wgsljeewMytGNKgBAZR1YbmE0X49+elqkZ+fr/gvB407wL9Dl7a/Kv3W04yJueRmEHytBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/node/-/node-25.9.0.tgz", + "integrity": "sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/@types/validator": { + "version": "13.15.10", + "resolved": "https://package-mirror.liara.ir/repository/npm/@types/validator/-/validator-13.15.10.tgz", + "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==", + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/auto-bind": { + "version": "4.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/auto-bind/-/auto-bind-4.0.0.tgz", + "integrity": "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bcryptjs": { + "version": "3.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/bcryptjs/-/bcryptjs-3.0.3.tgz", + "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://package-mirror.liara.ir/repository/npm/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-parser": { + "version": "1.4.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", + "license": "MIT", + "dependencies": { + "cookie": "0.7.2", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csrf": { + "version": "3.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/csrf/-/csrf-3.1.0.tgz", + "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", + "license": "MIT", + "dependencies": { + "rndm": "1.2.0", + "tsscmp": "1.0.6", + "uid-safe": "2.1.5" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/csurf": { + "version": "1.11.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/csurf/-/csurf-1.11.0.tgz", + "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", + "deprecated": "This package is archived and no longer maintained. For support, visit https://github.com/expressjs/express/discussions", + "license": "MIT", + "dependencies": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "csrf": "3.1.0", + "http-errors": "~1.7.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/csurf/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/csurf/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "license": "ISC" + }, + "node_modules/csurf/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dottie": { + "version": "2.0.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/dottie/-/dottie-2.0.7.tgz", + "integrity": "sha512-7lAK2A0b3zZr3UC5aE69CPdCFR4RHW1o2Dr74TqFykxkUCBXSRJum/yPc7g8zRHJqWKomPLHwFLLoUnn8PXXRg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://package-mirror.liara.ir/repository/npm/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editorconfig": { + "version": "1.0.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/editorconfig/-/editorconfig-1.0.7.tgz", + "integrity": "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "^9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://package-mirror.liara.ir/repository/npm/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.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" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.5.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "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", + "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/glob-parent": { + "version": "5.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://package-mirror.liara.ir/repository/npm/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://package-mirror.liara.ir/repository/npm/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "8.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/helmet/-/helmet-8.1.0.tgz", + "integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/hpp": { + "version": "0.2.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/hpp/-/hpp-0.2.3.tgz", + "integrity": "sha512-4zDZypjQcxK/8pfFNR7jaON7zEUpXZxz4viyFmqjb3kWNWAHsLEUmWXcdn25c5l76ISvnD6hbOGO97cXUI3Ryw==", + "license": "ISC", + "dependencies": { + "lodash": "^4.17.12", + "type-is": "^1.6.12" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hpp/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/hpp/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/hpp/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://package-mirror.liara.ir/repository/npm/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/hpp/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://package-mirror.liara.ir/repository/npm/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "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/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true, + "license": "ISC" + }, + "node_modules/inflection": { + "version": "1.13.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==", + "engines": [ + "node >= 0.4.0" + ], + "license": "MIT" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://package-mirror.liara.ir/repository/npm/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-cookie": { + "version": "3.0.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/js-cookie/-/js-cookie-3.0.7.tgz", + "integrity": "sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.48", + "resolved": "https://package-mirror.liara.ir/repository/npm/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/multer/-/multer-2.1.1.tgz", + "integrity": "sha512-mo+QTzKlx8R7E5ylSXxWzGoXoZbOsRMpyitcht8By2KHvMbf3tjwosZ/Mu/XYU6UuJ3VZnODIrak5ZrPiPyB6A==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">= 10.16.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/multer/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://package-mirror.liara.ir/repository/npm/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/multer/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://package-mirror.liara.ir/repository/npm/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nodemon": { + "version": "3.1.14", + "resolved": "https://package-mirror.liara.ir/repository/npm/nodemon/-/nodemon-3.1.14.tgz", + "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^10.2.1", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pg": { + "version": "8.20.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.12.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", + "license": "MIT" + }, + "node_modules/pg-hstore": { + "version": "2.3.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg-hstore/-/pg-hstore-2.3.4.tgz", + "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==", + "license": "MIT", + "dependencies": { + "underscore": "^1.13.1" + }, + "engines": { + "node": ">= 0.8.x" + } + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.13.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.13.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://package-mirror.liara.ir/repository/npm/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://package-mirror.liara.ir/repository/npm/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://package-mirror.liara.ir/repository/npm/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://package-mirror.liara.ir/repository/npm/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/retry-as-promised": { + "version": "7.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/retry-as-promised/-/retry-as-promised-7.1.1.tgz", + "integrity": "sha512-hMD7odLOt3LkTjcif8aRZqi/hybjpLNgSk5oF5FCowfCjok6LukpN2bDX7R5wDmbgBQFn7YoBxSagmtXHaJYJw==", + "license": "MIT" + }, + "node_modules/rndm": { + "version": "1.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/rndm/-/rndm-1.2.0.tgz", + "integrity": "sha512-fJhQQI5tLrQvYIYFpOnFinzv9dwmR7hRnUz1XqP3OJ1jIweTNOd6aTO4jwQSgcBSFUB+/KHJxuGneime+FdzOw==", + "license": "MIT" + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "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/safe-buffer": { + "version": "5.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/sequelize": { + "version": "6.37.8", + "resolved": "https://package-mirror.liara.ir/repository/npm/sequelize/-/sequelize-6.37.8.tgz", + "integrity": "sha512-HJ0IQFqcTsTiqbEgiuioYFMSD00TP6Cz7zoTti+zVVBwVe9fEhev9cH6WnM3XU31+ABS356durAb99ZuOthnKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/sequelize" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.8", + "@types/validator": "^13.7.17", + "debug": "^4.3.4", + "dottie": "^2.0.6", + "inflection": "^1.13.4", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "pg-connection-string": "^2.6.1", + "retry-as-promised": "^7.0.4", + "semver": "^7.5.4", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.9.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "snowflake-sdk": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-cli": { + "version": "6.6.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/sequelize-cli/-/sequelize-cli-6.6.5.tgz", + "integrity": "sha512-DqyISCULOaEbTM+rRQH4YvcUWeOC1XDiSKcjsC6TfAnT7W837mNkChJhtB/Z4FdCFHRCojmiP7zsrA4pARmacA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fs-extra": "^9.1.0", + "js-beautify": "1.15.4", + "lodash": "^4.17.21", + "picocolors": "^1.1.1", + "resolve": "^1.22.1", + "umzug": "^2.3.0", + "yargs": "^16.2.0" + }, + "bin": { + "sequelize": "lib/sequelize", + "sequelize-cli": "lib/sequelize" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sequelize-pool": { + "version": "7.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/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/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==", + "license": "MIT" + }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "dev": true, + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "license": "MIT", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "license": "MIT", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/umzug": { + "version": "2.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://package-mirror.liara.ir/repository/npm/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "https://package-mirror.liara.ir/repository/npm/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://package-mirror.liara.ir/repository/npm/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/validator": { + "version": "13.15.35", + "resolved": "https://package-mirror.liara.ir/repository/npm/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://package-mirror.liara.ir/repository/npm/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://package-mirror.liara.ir/repository/npm/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://package-mirror.liara.ir/repository/npm/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://package-mirror.liara.ir/repository/npm/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://package-mirror.liara.ir/repository/npm/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://package-mirror.liara.ir/repository/npm/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..682c6ae --- /dev/null +++ b/package.json @@ -0,0 +1,48 @@ +{ + "name": "backend", + "version": "1.0.0", + "description": "", + "main": "index.ts", + "scripts": { + "dev": "nodemon index.ts", + "build": "tsc", + "start": "node index.ts", + "type-check": "tsc --noEmit", + "clean": "rm -rf dist" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "auto-bind": "^4.0.0", + "bcryptjs": "^3.0.3", + "cookie-parser": "^1.4.7", + "cors": "^2.8.6", + "csurf": "^1.11.0", + "express": "^5.2.1", + "express-rate-limit": "^8.5.2", + "helmet": "^8.1.0", + "hpp": "^0.2.3", + "http-errors": "^2.0.1", + "jsonwebtoken": "^9.0.3", + "multer": "^2.1.1", + "pg": "^8.20.0", + "pg-hstore": "^2.3.4", + "sequelize": "^6.37.8" + }, + "devDependencies": { + "@types/cookie-parser": "^1.4.10", + "@types/cors": "^2.8.19", + "@types/csurf": "^1.11.5", + "@types/express": "^5.0.6", + "@types/hpp": "^0.2.7", + "@types/jsonwebtoken": "^9.0.10", + "@types/node": "^25.9.0", + "dotenv": "^17.4.2", + "nodemon": "^3.1.14", + "sequelize-cli": "^6.6.5", + "ts-node": "^10.9.2", + "typescript": "^6.0.3" + } +} diff --git a/seeders/rbac.seed.ts b/seeders/rbac.seed.ts new file mode 100644 index 0000000..1864385 --- /dev/null +++ b/seeders/rbac.seed.ts @@ -0,0 +1,135 @@ +import { sequelize } from "../src/models"; +import { Permission } from "../src/models/Permission"; +import { Role } from "../src/models/Role"; + + +export async function seedRBAC() { + const transaction = await sequelize.transaction(); + + try { + + /** + * PERMISSIONS + */ + + const permissionsList = [ + "VIEW_APPLICANTS", + "CREATE_APPLICANT", + "EDIT_APPLICANT", + "DELETE_APPLICANT", + + "EXPORT_APPLICANTS", + + "VIEW_USERS", + "CREATE_USER", + "EDIT_USER", + "DELETE_USER", + + "VIEW_ROLES", + "MANAGE_ROLES", + + "SYSTEM_SETTINGS" + ]; + + const permissions: any = {}; + + for (const perm of permissionsList) { + const [permission] = await Permission.findOrCreate({ + where: { name: perm }, + defaults: { name: perm }, + transaction + }); + + permissions[perm] = permission; + } + + /** + * ROLES + */ + + const rolesData = [ + { + name: "SUPER_ADMIN", + description: "دسترسی کامل به کل سیستم" + }, + { + name: "ADMIN", + description: "مدیریت کاربران و رزومه‌ها" + }, + { + name: "HR", + description: "کارشناس منابع انسانی" + }, + { + name: "VIEWER", + description: "فقط مشاهده رزومه‌ها" + } + ]; + + const roles: any = {}; + + for (const roleData of rolesData) { + const [role] = await Role.findOrCreate({ + where: { name: roleData.name }, + defaults: roleData, + transaction + }); + + roles[roleData.name] = role; + } + + /** + * ROLE PERMISSIONS + */ + + await roles.SUPER_ADMIN.setPermissions(Object.values(permissions), { + transaction + }); + + await roles.ADMIN.setPermissions( + [ + permissions.VIEW_APPLICANTS, + permissions.CREATE_APPLICANT, + permissions.EDIT_APPLICANT, + permissions.DELETE_APPLICANT, + permissions.EXPORT_APPLICANTS, + + permissions.VIEW_USERS, + permissions.CREATE_USER, + permissions.EDIT_USER, + + permissions.VIEW_ROLES + ], + { transaction } + ); + + await roles.HR.setPermissions( + [ + permissions.VIEW_APPLICANTS, + permissions.CREATE_APPLICANT, + permissions.EDIT_APPLICANT, + permissions.EXPORT_APPLICANTS + ], + { transaction } + ); + + await roles.VIEWER.setPermissions( + [ + permissions.VIEW_APPLICANTS + ], + { transaction } + ); + + await transaction.commit(); + + console.log("✅ RBAC seed completed"); + + } catch (error) { + + await transaction.rollback(); + + console.error("❌ RBAC seed failed:", error); + + throw error; + } +} diff --git a/sequelize.config.js b/sequelize.config.js new file mode 100644 index 0000000..917c42a --- /dev/null +++ b/sequelize.config.js @@ -0,0 +1,18 @@ +require("ts-node/register"); + +module.exports = { + development: { + username: "postgres", + password: "root", + database: "employee_form", + host: "127.0.0.1", + dialect: "postgres", + }, + production: { + username: "postgres", + password: "root", + database: "employee_form_prod", + host: "127.0.0.1", + dialect: "postgres", + }, +}; diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..906bbf4 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,96 @@ +import { NextFunction, Request, Response } from "express"; +import path from "node:path"; +import cookieParser from "cookie-parser"; +import createHttpError from "http-errors"; +// import { ServerErrorsObject, ServerResponse } from "./core/types"; +// import { secureApp } from "./config/secure-app"; +// import mainRouter from "./core/router/main.router"; +import dotenv from "dotenv"; +import { secureApp } from "./core/config/secure-app"; +import initDB from "./core/config/db-connection"; +import { ServerErrorsObject, ServerResponse } from "./core/types"; +import { seedRBAC } from "../seeders/rbac.seed"; +import mainRouter from "./core/router/main.router"; + +// import { seedDepartments } from "./seeders/department.seed"; +// import { seedUsers } from "./seeders/user.seed"; +// import { seedRoles } from "./seeders/role.seed"; +const express = require("express") as typeof import("express"); +dotenv.config(); + +export default class ServerApplication { + #PORT = 4000; + #APP = express(); + constructor() { + this.serverConfiguration(); + this.StartApplication(); + this.InitClientSession(); + this.RoutesConfiguration(); + this.ErrorHandlingConfiguration(); + } + + async serverConfiguration() { + // this.#APP.use(secureApp); + this.#APP.use(express.json()); + this.#APP.use(express.urlencoded({ extended: true })); + this.#APP.set("json spaces", 2); + this.#APP.use( + "/media/images", + express.static(path.join(__dirname, "..", "media", "images")), + ); + this.#APP.use( + "/media/videos", + express.static(path.join(__dirname, "..", "media", "videos")), + ); + } + async StartApplication() { + await initDB(); + // await seedRBAC(); + + + + this.#APP.listen(this.#PORT, () => { + console.log( + `Server Running on PORT ${this.#PORT} url : ${"http://localhost:"}${ + this.#PORT + }`, + ); + }); + } + InitClientSession() { + this.#APP.use(cookieParser(process.env.COOKIE_PARSER_SECRET_KEY)); + } + RoutesConfiguration() { + // this.#APP.get("/", (req, res) => res.send("")); + + this.#APP.use("/api/v1", mainRouter); + + } + ErrorHandlingConfiguration() { + this.#APP.use((req: any, res: Response, next: NextFunction) => { + next(createHttpError.NotFound("این آدرس یافت نشد")); + }); + this.#APP.use( + async (error: any, req: any, res: ServerResponse, next: NextFunction) => { + // await ErrorLog.create({ + // message: error.message, + // stack: error.stack, + // severity: "HIGH", + // }); + // console.log(error); + const serverError = createHttpError.InternalServerError(); + const statusCode = error.status || serverError.status; + const message: string = error.message || serverError.message; + + const errorObject: ServerErrorsObject = { + status: statusCode, + error: { + message, + }, + }; + + return res.status(statusCode).json(errorObject); + }, + ); + } +} diff --git a/src/config/database.ts b/src/config/database.ts new file mode 100644 index 0000000..d94bac2 --- /dev/null +++ b/src/config/database.ts @@ -0,0 +1,16 @@ +// import { Sequelize } from "sequelize"; + +// const sequelize = new Sequelize( +// "employee_form", +// "postgres", +// "root", +// { +// host: "127.0.0.1", +// dialect: "postgres", +// logging: false +// } +// ); + + + +// export default sequelize; diff --git a/src/core/config/db-connection.ts b/src/core/config/db-connection.ts new file mode 100644 index 0000000..65c7642 --- /dev/null +++ b/src/core/config/db-connection.ts @@ -0,0 +1,15 @@ +import { sequelize } from "../../models"; + +async function initDB(): Promise { + try { + await sequelize.authenticate(); + + await sequelize.sync({ alter: true }); + console.log("✅ Database synced successfully"); + } catch (error) { + console.error("❌ Database sync failed:", error); + process.exit(1); + } +} + +export default initDB; diff --git a/src/core/config/secure-app.ts b/src/core/config/secure-app.ts new file mode 100644 index 0000000..468d28c --- /dev/null +++ b/src/core/config/secure-app.ts @@ -0,0 +1,29 @@ +import helmet from "helmet"; +import rateLimit from "express-rate-limit"; +import cors from "cors"; +import cookieParser from "cookie-parser"; +import csurf from "csurf"; +import hpp from "hpp"; +import { cors_option, helmet_option, limiter_option } from "./server-configuration"; + +export const rateLimiter = rateLimit(limiter_option); + +export const corsOptions = cors(cors_option); + +export const securityHeaders = helmet(helmet_option); + +export const csrfProtection = [ + cookieParser(), + csurf({cookie: {httpOnly: true, secure: true, sameSite: "strict"}}), +]; + +export const sanitizeData = [ + hpp(), +]; + +export const secureApp = [ + corsOptions, + rateLimiter, + securityHeaders, + ...sanitizeData, +]; diff --git a/src/core/config/server-configuration.ts b/src/core/config/server-configuration.ts new file mode 100644 index 0000000..d8668e1 --- /dev/null +++ b/src/core/config/server-configuration.ts @@ -0,0 +1,90 @@ +import { CorsOptions } from "cors"; +import dotenv from "dotenv"; +import { NextFunction } from "express"; +import { Options } from "express-rate-limit"; +import { HelmetOptions } from "helmet"; +import createHttpError from "http-errors"; + +import { Request } from "express"; + +dotenv.config(); + +const multer = require("multer"); +const path = require("path"); +const fs = require("fs"); +export const config = { + port: process.env.PORT || 3500, + db: { + host: process.env.DB_HOST, + port: Number(process.env.DB_PORT), + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + }, + jwtSecret: process.env.JWT_SECRET || "secret", +}; + +export const limiter_option: Partial = { + windowMs: 15 * 60 * 1000, + max: 4000, + standardHeaders: true, + legacyHeaders: false, + + handler: (req: any, res: any, next: NextFunction) => { + next( + new createHttpError.TooManyRequests( + "تعداد درخواست شما بیشتر از حد مجاز است ، در زمان دیگری مجدد درخواست دهید", + ), + ); + }, + // message: {error: "Too many requests, please try again later."}, +}; + +export const helmet_option: HelmetOptions = { + contentSecurityPolicy: { + useDefaults: true, + directives: { + defaultSrc: ["'self'"], + // scriptSrc: ["'self'", "'unsafe-inline'", "https://trusted.cdn.com"], + // styleSrc: ["'self'", "'unsafe-inline'"], + // imgSrc: ["'self'", "data:", "https:"], + connectSrc: ["'self'"], + // fontSrc: ["'self'", "https://fonts.gstatic.com"], + objectSrc: ["'none'"], + upgradeInsecureRequests: [], // تبدیل اتومات http به https + }, + }, + crossOriginEmbedderPolicy: true, + crossOriginResourcePolicy: { policy: "same-origin" }, + frameguard: { action: "deny" }, // جلوگیری از Clickjacking + referrerPolicy: { policy: "no-referrer" }, // جلوگیری از لو رفتن referrer + xssFilter: true, // فعال کردن فیلتر XSS + hsts: { maxAge: 63072000, includeSubDomains: true, preload: true }, // HSTS +}; + +export const cors_option: CorsOptions = { + origin: true, + credentials: true, + allowedHeaders: [ + "Content-Type", + "Authorization", + "x-upload-token", // 👈 اینو اضافه کن + ], + methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"], + maxAge: 600, + // origin:["http://localhost:3000"] +}; + +async function createDirectoryRoute(req: Request) { + const date = new Date(); + + const directory = path.join(__dirname, "..", "..", "..", "public", "images"); + req.body.fileUploadPath = path.join(directory, "original"); + fs.mkdirSync(directory, { recursive: true }); + return directory; +} + +const storage = multer.memoryStorage(); // Keep files in memory (instead of disk) +const uploadFile = multer({ storage: storage }); + +export { uploadFile }; diff --git a/src/core/constant/index.ts b/src/core/constant/index.ts new file mode 100644 index 0000000..f3b7903 --- /dev/null +++ b/src/core/constant/index.ts @@ -0,0 +1 @@ +export const TOKEN_NAME = 'tid' \ No newline at end of file diff --git a/src/core/constant/permission.ts b/src/core/constant/permission.ts new file mode 100644 index 0000000..90d8fad --- /dev/null +++ b/src/core/constant/permission.ts @@ -0,0 +1,7 @@ +export const Permissions = [ + "VIEW_APPLICANTS", + "EDIT_APPLICANT", + "DELETE_APPLICANT", + "EXPORT_APPLICANTS", + "MANAGE_USERS", +]; diff --git a/src/core/controller/main.controller.ts b/src/core/controller/main.controller.ts new file mode 100644 index 0000000..772ee8e --- /dev/null +++ b/src/core/controller/main.controller.ts @@ -0,0 +1,8 @@ +import autoBind from "auto-bind"; + +export class Controller { + constructor() { + autoBind(this); + } +} + diff --git a/src/core/messages/alerts.ts b/src/core/messages/alerts.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/core/messages/errors.ts b/src/core/messages/errors.ts new file mode 100644 index 0000000..2b72449 --- /dev/null +++ b/src/core/messages/errors.ts @@ -0,0 +1,6 @@ +export const GlobalErrorMessages = Object.freeze({ + server: { + internal: "متاسفانه خطايي رخ داده است", + }, + notFound: "يافت نشد", +}); diff --git a/src/core/messages/success.ts b/src/core/messages/success.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/core/middleware/auth.middleware.ts b/src/core/middleware/auth.middleware.ts new file mode 100644 index 0000000..a4ac704 --- /dev/null +++ b/src/core/middleware/auth.middleware.ts @@ -0,0 +1,47 @@ +import { Request, Response, NextFunction } from "express"; +import jwt from "jsonwebtoken"; +import { User } from "../../models/User"; +import { Role } from "../../models/Role"; +import { Permission } from "../../models/Permission"; + +/** + * Middleware: استخراج اطلاعات کاربر از توکن JWT + * توکن باید در Header ارسال شود: Authorization: Bearer + */ +export async function requireAuth( + req: Request, + res: Response, + next: NextFunction +) { + const authHeader = req.headers.authorization; + if (!authHeader || !authHeader.startsWith("Bearer ")) { + return res.status(401).json({ message: "توکن احراز هویت ارسال نشده است." }); + } + + const token = authHeader.split(" ")[1]; + + try { + // بررسی صحت و امضای JWT + const decoded: any = jwt.verify(token, process.env.JWT_SECRET!); + + // پیدا کردن یوزر و نقش‌ها از دیتابیس + const user = await User.findByPk(decoded.userId, { + include: [ + { + model: Role, + include: [Permission], + }, + ], + }); + + if (!user) { + return res.status(404).json({ message: "کاربر یافت نشد." }); + } + + // تزریق یوزر در request برای استفاده‌های بعدی + (req as any).user = user; + next(); + } catch (err) { + return res.status(401).json({ message: "توکن نامعتبر یا منقضی است." }); + } +} diff --git a/src/core/middleware/require-permission.middleware.ts b/src/core/middleware/require-permission.middleware.ts new file mode 100644 index 0000000..d1ed9b7 --- /dev/null +++ b/src/core/middleware/require-permission.middleware.ts @@ -0,0 +1,24 @@ +import { NextFunction } from "express"; +import { ServerResponse } from "../types"; + +export function requirePermission(...permissions: string[]) { + return (req: Request, res: ServerResponse, next: NextFunction) => { + const user = (req as any).user; + if (!user) + return res + .status(401) + .json({ status: 401, data: {}, message: "احراز هویت انجام نشده است." }); + + const userPermissions = + user.Role?.Permissions?.map((p: any) => p.name) || []; + + const hasPerm = permissions.every((p) => userPermissions.includes(p)); + if (!hasPerm) { + return res + .status(403) + .json({ status: 403, data: {}, message: "دسترسی شما کافی نیست." }); + } + + next(); + }; +} diff --git a/src/core/middleware/require-role.middleware.ts b/src/core/middleware/require-role.middleware.ts new file mode 100644 index 0000000..5a576b3 --- /dev/null +++ b/src/core/middleware/require-role.middleware.ts @@ -0,0 +1,25 @@ +import { NextFunction } from "express"; +import { ServerResponse } from "../types"; + +export function requireRole(...roles: string[]) { + return (req: Request, res: ServerResponse, next: NextFunction) => { + const user = (req as any).user; + if (!user) + return res + .status(401) + .json({ status: 401, data: {}, message: "احراز هویت انجام نشده است." }); + + const userRole = user.Role?.name; + if (!userRole || !roles.includes(userRole)) { + return res + .status(403) + .json({ + status: 403, + data: {}, + message: "شما دسترسی لازم برای این عملیات را ندارید.", + }); + } + + next(); + }; +} diff --git a/src/core/router/main.router.ts b/src/core/router/main.router.ts new file mode 100644 index 0000000..ce12285 --- /dev/null +++ b/src/core/router/main.router.ts @@ -0,0 +1,12 @@ +import { Router } from 'express'; +import AuthRouter from '../../modules/auth/router/auth.routes'; + +const mainRouter = Router(); + + +// mainRouter.use('/user',userRouter) +// mainRouter.use('/applicant',applicantRouter) +mainRouter.use('/auth',AuthRouter) +// mainRouter.use('/user',userRouter) + +export default mainRouter; \ No newline at end of file diff --git a/src/core/types/index.ts b/src/core/types/index.ts new file mode 100644 index 0000000..58b3d0a --- /dev/null +++ b/src/core/types/index.ts @@ -0,0 +1,20 @@ +import { Response } from "express"; + +export interface ServerResponseObject { + status: number; + data: any; + message?: string; +} + +export interface ServerErrorsObject { + status: number; + data?: any; + error: { + message: string; + description?: string; + }; +} + +export type ServerResponse = Response< + ServerResponseObject | ServerErrorsObject +>; diff --git a/src/models/Applicant.ts b/src/models/Applicant.ts new file mode 100644 index 0000000..303f937 --- /dev/null +++ b/src/models/Applicant.ts @@ -0,0 +1,39 @@ +import { Model, DataTypes, Sequelize, Optional } from "sequelize"; + +export interface ApplicantAttributes { + id: string; + createdAt?: Date; + updatedAt?: Date; +} + +export interface ApplicantCreationAttributes + extends Optional {} + +export class Applicant + extends Model + implements ApplicantAttributes +{ + public id!: string; + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof Applicant { + Applicant.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + allowNull: false + } + }, + { + sequelize, + tableName: "applicants", + timestamps: true + } + ); + + return Applicant; + } +} diff --git a/src/models/Center.ts b/src/models/Center.ts new file mode 100644 index 0000000..8c5b4c1 --- /dev/null +++ b/src/models/Center.ts @@ -0,0 +1,40 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class Center extends Model { + public id!: string; + public name!: string; + public address!: string; + public isUrgent!: boolean; + + static initModel(sequelize: Sequelize) { + Center.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + + name: { + type: DataTypes.STRING, + allowNull: false, + }, + address: { + type: DataTypes.TEXT, + allowNull: true, + }, + isUrgent: { + type: DataTypes.BOOLEAN, + defaultValue: false, + allowNull: false, + }, + }, + { + sequelize, + tableName: "centers", + timestamps: true, + }, + ); + return Center; + } +} diff --git a/src/models/ComputerSkill.ts b/src/models/ComputerSkill.ts new file mode 100644 index 0000000..f18f51a --- /dev/null +++ b/src/models/ComputerSkill.ts @@ -0,0 +1,46 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +const skillLevels = [ + "NONE", + "VERY_WEAK", + "WEAK", + "AVERAGE", + "GOOD", + "VERY_GOOD", + "EXCELLENT", +]; + +export class ComputerSkill extends Model { + static initModel(sequelize: Sequelize) { + ComputerSkill.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + applicantId: { type: DataTypes.UUID, allowNull: false }, + + pcUsage: { type: DataTypes.ENUM(...skillLevels), defaultValue: "NONE" }, + word: { type: DataTypes.ENUM(...skillLevels), defaultValue: "NONE" }, + excel: { type: DataTypes.ENUM(...skillLevels), defaultValue: "NONE" }, + powerPoint: { + type: DataTypes.ENUM(...skillLevels), + defaultValue: "NONE", + }, + + rahkaran: { + type: DataTypes.ENUM(...skillLevels), + defaultValue: "NONE", + }, + kasra: { type: DataTypes.ENUM(...skillLevels), defaultValue: "NONE" }, + didgah: { type: DataTypes.ENUM(...skillLevels), defaultValue: "NONE" }, + his: { type: DataTypes.ENUM(...skillLevels), defaultValue: "NONE" }, + + otherSoftware: { type: DataTypes.TEXT }, // توضیحات سایر نرم‌افزارها + }, + { sequelize, tableName: "computer_skills", timestamps: true }, + ); + return ComputerSkill; + } +} diff --git a/src/models/Course.ts b/src/models/Course.ts new file mode 100644 index 0000000..f670f41 --- /dev/null +++ b/src/models/Course.ts @@ -0,0 +1,26 @@ +import { Model, DataTypes, Sequelize, Optional } from "sequelize"; + +export interface CourseAttributes { + id: string; + applicantId: string; + title: string; + institution: string; + year: number; + duration: string; + description?: string; +} + +export class Course extends Model> { + static initModel(sequelize: Sequelize) { + Course.init({ + id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true }, + applicantId: { type: DataTypes.UUID, allowNull: false }, + title: { type: DataTypes.STRING, allowNull: false }, + institution: { type: DataTypes.STRING }, + year: { type: DataTypes.INTEGER }, + duration: { type: DataTypes.STRING }, + description: { type: DataTypes.TEXT } + }, { sequelize, tableName: "courses", timestamps: true }); + return Course; + } +} diff --git a/src/models/Education.ts b/src/models/Education.ts new file mode 100644 index 0000000..c3cb93f --- /dev/null +++ b/src/models/Education.ts @@ -0,0 +1,114 @@ +import { Model, DataTypes, Sequelize, Optional } from "sequelize"; + +export interface EducationAttributes { + id: string; + applicantId: string; + + degree: string; // مقطع تحصیلی + field: string; // رشته تحصیلی + university: string; // دانشگاه یا موسسه + + startYear?: number; + endYear?: number; + + gpa?: number; // معدل + + description?: string; + certificateImageId?: string; // آیدی تصویر مدرک تحصیلی (FK به جدول فایل‌ها) + + createdAt?: Date; + updatedAt?: Date; +} + +export type EducationCreationAttributes = Optional< + EducationAttributes, + "id" | "createdAt" | "updatedAt" | "certificateImageId" +>; + +export class Education + extends Model + implements EducationAttributes +{ + public id!: string; + public applicantId!: string; + + public degree!: string; + public field!: string; + public university!: string; + + public startYear?: number; + public endYear?: number; + + public gpa?: number; + + public description?: string; + public certificateImageId?: string; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof Education { + Education.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + allowNull: false + }, + + applicantId: { + type: DataTypes.UUID, + allowNull: false + }, + + degree: { + type: DataTypes.STRING, + allowNull: false + }, + + field: { + type: DataTypes.STRING, + allowNull: false + }, + + university: { + type: DataTypes.STRING, + allowNull: false + }, + + startYear: { + type: DataTypes.INTEGER, + allowNull: true + }, + + endYear: { + type: DataTypes.INTEGER, + allowNull: true + }, + + gpa: { + type: DataTypes.FLOAT, + allowNull: true + }, + + description: { + type: DataTypes.TEXT, + allowNull: true + }, + + certificateImageId: { + type: DataTypes.UUID, + allowNull: true + } + }, + { + sequelize, + tableName: "educations", + timestamps: true + } + ); + + return Education; + } +} diff --git a/src/models/File.ts b/src/models/File.ts new file mode 100644 index 0000000..13b7807 --- /dev/null +++ b/src/models/File.ts @@ -0,0 +1,76 @@ +import { Model, DataTypes, Sequelize, Optional } from "sequelize"; + +export interface FileAttributes { + id: string; + + fileName: string; + originalName: string; + mimeType: string; + + path: string; + size: number; + + createdAt?: Date; + updatedAt?: Date; +} + +export interface FileCreationAttributes + extends Optional {} + +export class File + extends Model + implements FileAttributes +{ + public id!: string; + + public fileName!: string; + public originalName!: string; + public mimeType!: string; + + public path!: string; + public size!: number; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof File { + File.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + + fileName: { + type: DataTypes.STRING, + allowNull: false + }, + + originalName: { + type: DataTypes.STRING + }, + + mimeType: { + type: DataTypes.STRING + }, + + path: { + type: DataTypes.STRING, + allowNull: false + }, + + size: { + type: DataTypes.INTEGER + } + }, + { + sequelize, + tableName: "files", + timestamps: true + } + ); + + return File; + } +} diff --git a/src/models/Identity.ts b/src/models/Identity.ts new file mode 100644 index 0000000..61d59b5 --- /dev/null +++ b/src/models/Identity.ts @@ -0,0 +1,119 @@ +import { Model, DataTypes, Sequelize, Optional } from "sequelize"; + +export interface IdentityAttributes { + id: string; + applicantId: string; + + firstName: string; + lastName: string; + fatherName: string; + nationalCode: string; + + birthDate: Date; + birthPlace: string; + + gender: string; + religion: string; + nationality: string; + + profilePhotoId?: string; + + createdAt?: Date; + updatedAt?: Date; +} + +export interface IdentityCreationAttributes + extends Optional {} + +export class Identity + extends Model + implements IdentityAttributes +{ + public id!: string; + public applicantId!: string; + + public firstName!: string; + public lastName!: string; + public fatherName!: string; + public nationalCode!: string; + + public birthDate!: Date; + public birthPlace!: string; + + public gender!: string; + public religion!: string; + public nationality!: string; + + public profilePhotoId?: string; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof Identity { + Identity.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true + }, + + applicantId: { + type: DataTypes.UUID, + allowNull: false + }, + + firstName: { + type: DataTypes.STRING, + allowNull: false + }, + + lastName: { + type: DataTypes.STRING, + allowNull: false + }, + + fatherName: { + type: DataTypes.STRING + }, + + nationalCode: { + type: DataTypes.STRING(10), + allowNull: false + }, + + birthDate: { + type: DataTypes.DATEONLY + }, + + birthPlace: { + type: DataTypes.STRING + }, + + gender: { + type: DataTypes.STRING + }, + + religion: { + type: DataTypes.STRING + }, + + nationality: { + type: DataTypes.STRING + }, + + profilePhotoId: { + type: DataTypes.UUID, + allowNull: true + } + }, + { + sequelize, + tableName: "identities", + timestamps: true + } + ); + + return Identity; + } +} diff --git a/src/models/JobCategory.ts b/src/models/JobCategory.ts new file mode 100644 index 0000000..9f4d6a3 --- /dev/null +++ b/src/models/JobCategory.ts @@ -0,0 +1,43 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class JobCategory extends Model { + public id!: string; + public centerId!: string; + public name!: string; + public isUrgent!: boolean; + + static initModel(sequelize: Sequelize) { + JobCategory.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + centerId: { + type: DataTypes.UUID, + allowNull: false, + references: { + model: 'centers', + key: 'id' + } + }, + name: { + type: DataTypes.STRING, + allowNull: false, + }, + isUrgent: { + type: DataTypes.BOOLEAN, + defaultValue: false, + allowNull: false, + }, + }, + { + sequelize, + tableName: "job_categories", + timestamps: true + } + ); + return JobCategory; + } +} diff --git a/src/models/JobInfo.ts b/src/models/JobInfo.ts new file mode 100644 index 0000000..f32451b --- /dev/null +++ b/src/models/JobInfo.ts @@ -0,0 +1,79 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class JobInfo extends Model { + public id!: string; + public applicantId!: string; + public readyToWorkDate!: Date; // تاریخ آمادگی برای شروع + public isCurrentEmployee!: boolean; // از پرسنل حال حاضر هستم یا خیر + public hasPastCooperation!: boolean; // سابقه همکاری در گذشته + public isCurrentlyEmployed!: boolean; // در حال حاضر مشغول به کار هستم یا خیر + public dualJobInterest!: boolean; // تمایل به دو جا کار بودن + public retirementStatus!: "None" | "Retired" | "Redeemed"; // بازنشسته / بازخرید / هیچکدام + public isMilitary!: boolean; // نظامی بودن + public hasInsurance!: boolean; // سابقه بیمه دارد یا خیر + public insuranceType?: string; // نوع بیمه (تامین اجتماعی، خدمات درمانی و...) + public totalInsuranceYears!: number; // جمع سال‌های سابقه بیمه + + static initModel(sequelize: Sequelize) { + JobInfo.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + applicantId: { + type: DataTypes.UUID, + allowNull: false, + unique: true, // معمولاً برای هر متقاضی یک رکورد وضعیت کاری وجود دارد + }, + readyToWorkDate: { + type: DataTypes.DATEONLY, + allowNull: false, + }, + isCurrentEmployee: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + hasPastCooperation: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + isCurrentlyEmployed: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + dualJobInterest: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + retirementStatus: { + type: DataTypes.ENUM("None", "Retired", "Redeemed"), + defaultValue: "None", + }, + isMilitary: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + hasInsurance: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + insuranceType: { + type: DataTypes.STRING, + allowNull: true, + }, + totalInsuranceYears: { + type: DataTypes.DECIMAL(4, 1), // مثلاً 10.5 سال سابقه + defaultValue: 0, + }, + }, + { + sequelize, + tableName: "work_experiences", + timestamps: true, + }, + ); + return JobInfo; + } +} diff --git a/src/models/JobRequest.ts b/src/models/JobRequest.ts new file mode 100644 index 0000000..c62980d --- /dev/null +++ b/src/models/JobRequest.ts @@ -0,0 +1,83 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class JobRequest extends Model { + // تعریف فیلدها برای شناسایی توسط TypeScript + public id!: string; + public applicantId!: string; + public centerId!: string; + public categoryId!: string; + public jobTitle!: string; + public description?: string; + public employmentType!: "Full-Time" | "Part-Time" | "Contract"; + public requestedSalary!: number; + public extraDescription?: string; + + // فیلدهای زمان‌بندی (اگر timestamps: true باشد) + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize) { + JobRequest.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + applicantId: { + type: DataTypes.UUID, + allowNull: false, + }, + centerId: { + type: DataTypes.UUID, + allowNull: false, + references: { + model: "centers", // نام جدول مراکز + key: "id", + }, + }, + categoryId: { + type: DataTypes.UUID, + allowNull: false, + references: { + model: "job_categories", // نام جدول رسته‌ها + key: "id", + }, + }, + jobTitle: { + type: DataTypes.STRING, + allowNull: false, + }, + description: { + type: DataTypes.TEXT, + allowNull: true, + }, + employmentType: { + // تعریف نوع همکاری به صورت ENUM + type: DataTypes.ENUM("Full-Time", "Part-Time", "Contract"), + allowNull: false, + }, + requestedSalary: { + // استفاده از BIGINT چون مبالغ ریالی معمولاً طولانی هستند + type: DataTypes.BIGINT, + allowNull: false, + get() { + // تبدیل رشته خروجی از دیتابیس به عدد در جاوااسکریپت + const value = this.getDataValue("requestedSalary"); + return value ? parseInt(value, 10) : 0; + }, + }, + extraDescription: { + type: DataTypes.TEXT, + allowNull: true, + }, + }, + { + sequelize, + tableName: "job_infos", // همان نامی که خودتان انتخاب کردید + timestamps: true, + }, + ); + return JobRequest; + } +} diff --git a/src/models/LanguageSkill.ts b/src/models/LanguageSkill.ts new file mode 100644 index 0000000..59f7b8d --- /dev/null +++ b/src/models/LanguageSkill.ts @@ -0,0 +1,16 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class LanguageSkill extends Model { + static initModel(sequelize: Sequelize) { + LanguageSkill.init({ + id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true }, + applicantId: { type: DataTypes.UUID, allowNull: false }, + languageName: { type: DataTypes.STRING }, // انگلیسی، عربی، گویش خاص و ... + proficiency: { type: DataTypes.STRING }, // میزان تسلط + hasCertificate: { type: DataTypes.BOOLEAN, defaultValue: false }, + certificateType: { type: DataTypes.STRING }, + description: { type: DataTypes.TEXT } + }, { sequelize, tableName: "language_skills", timestamps: true }); + return LanguageSkill; + } +} diff --git a/src/models/Permission.ts b/src/models/Permission.ts new file mode 100644 index 0000000..9580762 --- /dev/null +++ b/src/models/Permission.ts @@ -0,0 +1,51 @@ +// src/models/permission.model.ts + +import { + Model, + DataTypes, + Optional, + Sequelize +} from "sequelize"; + +interface PermissionAttributes { + id: string; + name: string; + createdAt?: Date; + updatedAt?: Date; +} + +type PermissionCreationAttributes = Optional; + +export class Permission extends Model< + PermissionAttributes, + PermissionCreationAttributes +> implements PermissionAttributes { + public id!: string; + public name!: string; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof Permission { + Permission.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + }, + { + sequelize, + tableName: "permissions", + } + ); + + return Permission; + } +} diff --git a/src/models/PersonalInfo.ts b/src/models/PersonalInfo.ts new file mode 100644 index 0000000..f4b2a57 --- /dev/null +++ b/src/models/PersonalInfo.ts @@ -0,0 +1,188 @@ +import { Model, DataTypes, Sequelize, Optional } from "sequelize"; + +export interface PersonalInfoAttributes { + id: string; + applicantId: string; + + maritalStatus?: string; + militaryStatus?: string; + + fatherEducation?: string; + fatherJob?: string; + + motherEducation?: string; + motherJob?: string; + + housingStatus?: string; + city?: string; + address?: string; + + homePhone?: string; + mobilePhone?: string; + emergencyPhone?: string; + email?: string; + + residenceDuration?: number; + + isVeteran?: boolean; + + hasCriminalRecord?: boolean; + criminalDescription?: string; + + createdAt?: Date; + updatedAt?: Date; +} + +export type PersonalInfoCreationAttributes = Optional< + PersonalInfoAttributes, + "id" | "createdAt" | "updatedAt" +>; + +export class PersonalInfo + extends Model + implements PersonalInfoAttributes +{ + public id!: string; + public applicantId!: string; + + public maritalStatus?: string; + public militaryStatus?: string; + + public fatherEducation?: string; + public fatherJob?: string; + + public motherEducation?: string; + public motherJob?: string; + + public housingStatus?: string; + public city?: string; + public address?: string; + + public homePhone?: string; + public mobilePhone?: string; + public emergencyPhone?: string; + public email?: string; + + public residenceDuration?: number; + + public isVeteran?: boolean; + + public hasCriminalRecord?: boolean; + public criminalDescription?: string; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof PersonalInfo { + PersonalInfo.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + allowNull: false + }, + + applicantId: { + type: DataTypes.UUID, + allowNull: false + }, + + maritalStatus: { + type: DataTypes.STRING, + allowNull: true + }, + + militaryStatus: { + type: DataTypes.STRING, + allowNull: true + }, + + fatherEducation: { + type: DataTypes.STRING, + allowNull: true + }, + + fatherJob: { + type: DataTypes.STRING, + allowNull: true + }, + + motherEducation: { + type: DataTypes.STRING, + allowNull: true + }, + + motherJob: { + type: DataTypes.STRING, + allowNull: true + }, + + housingStatus: { + type: DataTypes.STRING, + allowNull: true + }, + + city: { + type: DataTypes.STRING, + allowNull: true + }, + + address: { + type: DataTypes.TEXT, + allowNull: true + }, + + homePhone: { + type: DataTypes.STRING, + allowNull: true + }, + + mobilePhone: { + type: DataTypes.STRING, + allowNull: true + }, + + emergencyPhone: { + type: DataTypes.STRING, + allowNull: true + }, + + email: { + type: DataTypes.STRING, + allowNull: true, + validate: { + isEmail: true + } + }, + + residenceDuration: { + type: DataTypes.INTEGER, + allowNull: true + }, + + isVeteran: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + + hasCriminalRecord: { + type: DataTypes.BOOLEAN, + defaultValue: false + }, + + criminalDescription: { + type: DataTypes.TEXT, + allowNull: true + } + }, + { + sequelize, + tableName: "personal_infos", + timestamps: true + } + ); + + return PersonalInfo; + } +} diff --git a/src/models/PhysicalInfo.ts b/src/models/PhysicalInfo.ts new file mode 100644 index 0000000..e5ebd48 --- /dev/null +++ b/src/models/PhysicalInfo.ts @@ -0,0 +1,139 @@ +import { Model, DataTypes, Sequelize, Optional } from "sequelize"; + +export interface PhysicalInfoAttributes { + id: string; + applicantId: string; + + bloodType?: string; + height?: number; // به سانتی‌متر + weight?: number; // به کیلوگرم + bmi?: number; + + hasDisability: boolean; + disabilityDescription?: string; + + hasChronicDisease: boolean; + chronicDiseaseDescription?: string; + + surgeryHistory?: string; + medications?: string; + + specialMark?: string; // علامت مشخصه + + createdAt?: Date; + updatedAt?: Date; +} + +export type PhysicalInfoCreationAttributes = Optional< + PhysicalInfoAttributes, + "id" | "createdAt" | "updatedAt" | "hasDisability" | "hasChronicDisease" +>; + +export class PhysicalInfo + extends Model + implements PhysicalInfoAttributes +{ + public id!: string; + public applicantId!: string; + + public bloodType?: string; + public height?: number; + public weight?: number; + public bmi?: number; + + public hasDisability!: boolean; + public disabilityDescription?: string; + + public hasChronicDisease!: boolean; + public chronicDiseaseDescription?: string; + + public surgeryHistory?: string; + public medications?: string; + + public specialMark?: string; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof PhysicalInfo { + PhysicalInfo.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + allowNull: false + }, + + applicantId: { + type: DataTypes.UUID, + allowNull: false + }, + + bloodType: { + type: DataTypes.STRING(10), + allowNull: true + }, + + height: { + type: DataTypes.FLOAT, + allowNull: true + }, + + weight: { + type: DataTypes.FLOAT, + allowNull: true + }, + + bmi: { + type: DataTypes.FLOAT, + allowNull: true + }, + + hasDisability: { + type: DataTypes.BOOLEAN, + defaultValue: false, + allowNull: false + }, + + disabilityDescription: { + type: DataTypes.TEXT, + allowNull: true + }, + + hasChronicDisease: { + type: DataTypes.BOOLEAN, + defaultValue: false, + allowNull: false + }, + + chronicDiseaseDescription: { + type: DataTypes.TEXT, + allowNull: true + }, + + surgeryHistory: { + type: DataTypes.TEXT, + allowNull: true + }, + + medications: { + type: DataTypes.TEXT, + allowNull: true + }, + + specialMark: { + type: DataTypes.STRING, + allowNull: true + } + }, + { + sequelize, + tableName: "physical_infos", + timestamps: true + } + ); + + return PhysicalInfo; + } +} diff --git a/src/models/Referral.ts b/src/models/Referral.ts new file mode 100644 index 0000000..d278ce9 --- /dev/null +++ b/src/models/Referral.ts @@ -0,0 +1,73 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class Referral extends Model { + public id!: string; + public applicantId!: string; + public firstName!: string; + public lastName!: string; + public relationship!: string; // نسبت + public acquaintanceDuration!: string; // مدت زمان آشنایی (مثلاً: ۵ سال) + public acquaintanceType!: "Direct" | "Indirect"; // نوع آشنایی: مستقیم / غیرمستقیم + public jobTitle!: string; // شغل معرف + public workplaceName!: string; // نام محل کار معرف + public phoneNumber!: string; // تلفن تماس + + static initModel(sequelize: Sequelize) { + Referral.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + applicantId: { + type: DataTypes.UUID, + allowNull: false, + references: { + model: "applicants", // یا هر نامی که برای جدول متقاضی دارید + key: "id", + }, + }, + firstName: { + type: DataTypes.STRING, + allowNull: false, + }, + lastName: { + type: DataTypes.STRING, + allowNull: false, + }, + relationship: { + type: DataTypes.STRING, + allowNull: false, + }, + acquaintanceDuration: { + type: DataTypes.STRING, + allowNull: true, + }, + acquaintanceType: { + type: DataTypes.ENUM("Direct", "Indirect"), + allowNull: false, + defaultValue: "Direct", + }, + jobTitle: { + type: DataTypes.STRING, + allowNull: true, + }, + workplaceName: { + type: DataTypes.STRING, + allowNull: true, + }, + phoneNumber: { + type: DataTypes.STRING(15), + allowNull: false, + }, + }, + { + sequelize, + tableName: "referrals", + timestamps: true, + }, + ); + return Referral; + } +} diff --git a/src/models/Relation.ts b/src/models/Relation.ts new file mode 100644 index 0000000..8be3d35 --- /dev/null +++ b/src/models/Relation.ts @@ -0,0 +1,53 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class Relation extends Model { + static initModel(sequelize: Sequelize) { + Relation.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + applicantId: { + type: DataTypes.UUID, + allowNull: false, + references: { + model: "applicants", + key: "id", + }, + }, + firstName: { + type: DataTypes.STRING, + allowNull: false, + }, + lastName: { + type: DataTypes.STRING, + allowNull: false, + }, + relationship: { + type: DataTypes.STRING, + allowNull: false, + }, + jobTitle: { + type: DataTypes.STRING, + allowNull: true, + }, + workplaceName: { + type: DataTypes.STRING, + allowNull: true, + }, + phoneNumber: { + type: DataTypes.STRING(15), + allowNull: false, + }, + order: { + type: DataTypes.INTEGER, + allowNull: false, // عدد 1 برای آشنای اول و 2 برای آشنای دوم + }, + }, + { sequelize, tableName: "relations", timestamps: true }, + ); + return Relation; + } +} diff --git a/src/models/Role.ts b/src/models/Role.ts new file mode 100644 index 0000000..6c096a5 --- /dev/null +++ b/src/models/Role.ts @@ -0,0 +1,56 @@ +// src/models/role.model.ts + +import { + Model, + DataTypes, + Optional, + Sequelize +} from "sequelize"; + +interface RoleAttributes { + id: string; + name: string; + description?: string; + createdAt?: Date; + updatedAt?: Date; +} + +type RoleCreationAttributes = Optional; + +export class Role extends Model + implements RoleAttributes { + public id!: string; + public name!: string; + public description?: string; + + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof Role { + Role.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + name: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + description: { + type: DataTypes.STRING, + allowNull: true, + }, + }, + { + sequelize, + tableName: "roles", + timestamps:true, + } + ); + + return Role; + } +} diff --git a/src/models/User.ts b/src/models/User.ts new file mode 100644 index 0000000..0f5d6b6 --- /dev/null +++ b/src/models/User.ts @@ -0,0 +1,72 @@ +// src/models/user.model.ts + +import { Model, DataTypes, Optional, Sequelize } from "sequelize"; +import { Role } from "./Role"; + +interface UserAttributes { + id: string; + fullname: string; + email: string; + password: string; + roleId: string; + isActive: boolean; + createdAt?: Date; + updatedAt?: Date; +} + +type UserCreationAttributes = Optional; + +export class User + extends Model + implements UserAttributes +{ + public id!: string; + public fullname!: string; + public email!: string; + public password!: string; + public roleId!: string; + public isActive!: boolean; + public role?: Role; + public readonly createdAt!: Date; + public readonly updatedAt!: Date; + + static initModel(sequelize: Sequelize): typeof User { + User.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + fullname: { + type: DataTypes.STRING, + allowNull: false, + }, + email: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + password: { + type: DataTypes.STRING, + allowNull: false, + }, + roleId: { + type: DataTypes.UUID, + allowNull: false, + }, + isActive: { + type: DataTypes.BOOLEAN, + defaultValue: true, + }, + }, + { + sequelize, + tableName: "users", + timestamps: true, + }, + ); + + return User; + } +} diff --git a/src/models/WorkExperience.ts b/src/models/WorkExperience.ts new file mode 100644 index 0000000..c862ed3 --- /dev/null +++ b/src/models/WorkExperience.ts @@ -0,0 +1,25 @@ +import { DataTypes, Model, Sequelize } from "sequelize"; + +export class WorkExperience extends Model { + static initModel(sequelize: Sequelize) { + WorkExperience.init( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + applicantId: { type: DataTypes.UUID, allowNull: false }, + hasNoExperience: { type: DataTypes.BOOLEAN, defaultValue: false }, + companyName: { type: DataTypes.STRING }, + lastPosition: { type: DataTypes.STRING }, + startYear: { type: DataTypes.INTEGER }, + endYear: { type: DataTypes.INTEGER }, + leavingReason: { type: DataTypes.STRING }, + description: { type: DataTypes.TEXT }, + }, + { sequelize, tableName: "work_experiences", timestamps: true }, + ); + return WorkExperience; + } +} diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..e35920a --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,228 @@ +import { Sequelize } from "sequelize"; +import { Applicant } from "./Applicant"; +import { Identity } from "./Identity"; +import { PersonalInfo } from "./PersonalInfo"; +import { PhysicalInfo } from "./PhysicalInfo"; +import { Education } from "./Education"; +import { Course } from "./Course"; +import { ComputerSkill } from "./ComputerSkill"; +import { LanguageSkill } from "./LanguageSkill"; +import { WorkExperience } from "./WorkExperience"; +import { Relation } from "./Relation"; +import { File } from "./File"; +import { Role } from "./Role"; +import { User } from "./User"; +import { Permission } from "./Permission"; +import { Referral } from "./Referral"; +import { JobInfo } from "./JobInfo"; +import { JobRequest } from "./JobRequest"; +import { Center } from "./Center"; +import { JobCategory } from "./JobCategory"; + +// تنظیمات اتصال به دیتابیس +const sequelize = new Sequelize("employee_form", "postgres", "root", { + host: "127.0.0.1", + dialect: "postgres", + logging: false, +}); + +// ۱. مقداردهی اولیه مدل‌ها (Initialization) +const models = { + // استخدامی + Applicant: Applicant.initModel(sequelize), + Center: Center.initModel(sequelize), + Identity: Identity.initModel(sequelize), + PersonalInfo: PersonalInfo.initModel(sequelize), + PhysicalInfo: PhysicalInfo.initModel(sequelize), + Education: Education.initModel(sequelize), + Course: Course.initModel(sequelize), + ComputerSkill: ComputerSkill.initModel(sequelize), + LanguageSkill: LanguageSkill.initModel(sequelize), + WorkExperience: WorkExperience.initModel(sequelize), + JobInfo: JobInfo.initModel(sequelize), + Relation: Relation.initModel(sequelize), + File: File.initModel(sequelize), + User: User.initModel(sequelize), + Role: Role.initModel(sequelize), + Permission: Permission.initModel(sequelize), + Referral: Referral.initModel(sequelize), + JobCategory: JobCategory.initModel(sequelize), + JobRequest: JobRequest.initModel(sequelize), +}; +// Role.hasMany(User, { foreignKey: "roleId" }); +// User.belongsTo(Role, { foreignKey: "roleId" }); + +// Role.belongsToMany(Permission, { +// through: "role_permissions", +// foreignKey: "roleId", +// }); + +// Permission.belongsToMany(Role, { +// through: "role_permissions", +// foreignKey: "permissionId", +// }); + +User.belongsTo(Role, { + foreignKey: "roleId", + as: "role", +}); + +Role.hasMany(User, { + foreignKey: "roleId", + as: "users", +}); + +Role.belongsToMany(Permission, { + through: "role_permissions", + foreignKey: "roleId", + otherKey: "permissionId", + as: "permissions", +}); + +Permission.belongsToMany(Role, { + through: "role_permissions", + foreignKey: "permissionId", + otherKey: "roleId", + as: "roles", +}); +Applicant.hasOne(Identity, { + foreignKey: "applicantId", + as: "identity", + onDelete: "CASCADE", +}); + +Identity.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasOne(PersonalInfo, { + foreignKey: "applicantId", + as: "personalInfo", + onDelete: "CASCADE", +}); + +PersonalInfo.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasOne(PhysicalInfo, { + foreignKey: "applicantId", + as: "physicalInfo", + onDelete: "CASCADE", +}); + +PhysicalInfo.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasMany(Education, { + foreignKey: "applicantId", + as: "educations", + onDelete: "CASCADE", +}); + +Education.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasMany(Course, { + foreignKey: "applicantId", + as: "courses", + onDelete: "CASCADE", +}); + +Course.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasMany(ComputerSkill, { + foreignKey: "applicantId", + as: "computerSkills", + onDelete: "CASCADE", +}); + +ComputerSkill.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasMany(LanguageSkill, { + foreignKey: "applicantId", + as: "languageSkills", + onDelete: "CASCADE", +}); + +LanguageSkill.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasMany(WorkExperience, { + foreignKey: "applicantId", + as: "workExperiences", + onDelete: "CASCADE", +}); + +WorkExperience.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasOne(JobInfo, { + foreignKey: "applicantId", + as: "jobInfo", + onDelete: "CASCADE", +}); + +JobInfo.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasMany(Relation, { + foreignKey: "applicantId", + as: "relations", + onDelete: "CASCADE", +}); + +Relation.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); +Applicant.hasMany(File, { + foreignKey: "applicantId", + as: "files", + onDelete: "CASCADE", +}); + +File.belongsTo(Applicant, { + foreignKey: "applicantId", + as: "applicant", +}); + +Applicant.hasMany(Referral, { foreignKey: "applicantId", as: "referrals" }); +Referral.belongsTo(Applicant, { foreignKey: "applicantId" }); + +Applicant.hasOne(JobInfo, { + foreignKey: "applicantId", + as: "workStatus", +}); +JobInfo.belongsTo(Applicant, { foreignKey: "applicantId" }); + +// مثال رابطه در فایل اصلی مدل‌ها +JobRequest.belongsTo(JobCategory, { foreignKey: "categoryId", as: "category" }); +// در فایل تعریف روابط: +Center.hasMany(JobCategory, { foreignKey: "centerId", as: "categories" }); +JobCategory.belongsTo(Center, { foreignKey: "centerId" }); + +JobCategory.hasMany(JobRequest, { foreignKey: "categoryId" }); +Applicant.hasMany(JobRequest, { foreignKey: "applicantId", as: "jobRequests" }); +JobRequest.belongsTo(Applicant, { foreignKey: "applicantId", as: "applicant" }); +Center.hasMany(JobRequest, { foreignKey: "centerId", as: "applications" }); +JobRequest.belongsTo(Center, { foreignKey: "centerId", as: "center" }); +// ۲. برقراری روابط (Associations) +// این حلقه متد associate را در هر کلاسی که تعریف شده باشد فراخوانی می‌کند +Object.values(models).forEach((model: any) => { + if (typeof model.associate === "function") { + model.associate(models); + } +}); + +export { sequelize }; +export default models; diff --git a/src/modules/auth/controller/auth.controller.ts b/src/modules/auth/controller/auth.controller.ts new file mode 100644 index 0000000..2ded26d --- /dev/null +++ b/src/modules/auth/controller/auth.controller.ts @@ -0,0 +1,74 @@ +import { NextFunction } from "express"; +import { Controller } from "../../../core/controller/main.controller"; +import { ServerResponse } from "../../../core/types"; +import AuthService from "../service/auth.service"; +import { TOKEN_NAME } from "../../../core/constant"; +import { GlobalErrorMessages } from "../../../core/messages/errors"; + +class AuthControllerClass extends Controller { + #service; + constructor() { + super(); + this.#service = AuthService; + } + + // login function for users that controlling this form + async userLogin(req: any, res: ServerResponse, next: NextFunction) { + try { + const data = await this.#service.usersLogin( + req?.body?.email, + req?.body?.password, + ); + res.cookie(TOKEN_NAME, data.token, { + httpOnly: true, + secure: false, + sameSite: "lax", + maxAge: 24 * 60 * 60 * 1000, + }); + return res.status(200).json({ + status: 200, + data, + message: "با موفقيت وارد شديد", + }); + } catch (error) { + next(error); + } + } + async applicantLogin(req: any, res: ServerResponse, next: NextFunction) { + try { + const data = await this.#service.applicantLogin( + req?.body?.nationalCode, + ); + res.cookie(TOKEN_NAME, data.token, { + httpOnly: true, + secure: false, + sameSite: "lax", + maxAge: 24 * 60 * 60 * 1000, + }); + return res.status(200).json({ + status: 200, + data, + message: "با موفقيت وارد شديد", + }); + } catch (error) { + next(error); + } + } + async userLogout(req: any, res: ServerResponse, next: NextFunction) { + try { + res.clearCookie(TOKEN_NAME); + + return res.status(200).json({ + status: 200, + data: {}, + message: "Ok", + }); + } catch (error) { + next(GlobalErrorMessages.server.internal); + } + } +} + +const AuthController = new AuthControllerClass(); + +export default AuthController; diff --git a/src/modules/auth/messages/auth.messages.ts b/src/modules/auth/messages/auth.messages.ts new file mode 100644 index 0000000..23332ec --- /dev/null +++ b/src/modules/auth/messages/auth.messages.ts @@ -0,0 +1,14 @@ +export const authErrorMessages = Object.freeze({ + notFound:{ + user:"كاربر يافت نشد", + applicant:"متقاضي يافت نشد" + }, + dosentMatch :{ + email:"ايميل اشتباه است", + password:"پسورد اشتباه است", + }, + login:{ + invalidData:'ايميل و يا رمز عبور اشتباه است' + }, + logout:'خروج از حساب با خطا مواجه شده است' +}) \ No newline at end of file diff --git a/src/modules/auth/router/auth.routes.ts b/src/modules/auth/router/auth.routes.ts new file mode 100644 index 0000000..1efce22 --- /dev/null +++ b/src/modules/auth/router/auth.routes.ts @@ -0,0 +1,13 @@ +import { Router } from "express"; +import AuthController from "../controller/auth.controller"; + +const AuthRouter = Router(); + +// authentication applicants +AuthRouter.post("/applicant/login", AuthController.applicantLogin); +// AuthRouter.post('/applicant/logout',AuthController.applicantLogout) + +// authentication users +AuthRouter.post("/user/login", AuthController.userLogin); +AuthRouter.post("/user/logout", AuthController.userLogout); +export default AuthRouter; diff --git a/src/modules/auth/service/auth.service.ts b/src/modules/auth/service/auth.service.ts new file mode 100644 index 0000000..7093fd7 --- /dev/null +++ b/src/modules/auth/service/auth.service.ts @@ -0,0 +1,84 @@ +import createHttpError from "http-errors"; +import { Controller } from "../../../core/controller/main.controller"; +import { User } from "../../../models/User"; +import bcrypt from "bcryptjs"; +import jwt from "jsonwebtoken"; +import { Role } from "../../../models/Role"; +import { Applicant } from "../../../models/Applicant"; +import { Identity } from "../../../models/Identity"; +import { authErrorMessages } from "../messages/auth.messages"; +class AuthServiceClass extends Controller { + async usersLogin(email: string, password: string) { + try { + // ۱. پیدا کردن کاربر به همراه نقش + const user = await User.findOne({ + where: { email }, + include: [ + { + model: Role, + as: "role", + }, + ], + }); + + if (!user) + throw new createHttpError.Unauthorized("ایمیل یا رمز عبور اشتباه است."); + + // ۲. چک کردن پسورد + const isMatch = await bcrypt.compare(password, user.password); + if (!isMatch) + throw new createHttpError.Unauthorized("ایمیل یا رمز عبور اشتباه است."); + + // ۳. صدور توکن + const token = jwt.sign( + { userId: user.id }, + process.env.JWT_SECRET || "secret", + { expiresIn: "24h" }, // طول عمر توکن + ); + + return { + token, + user: { id: user.id, fullname: user.fullname, role: user }, + }; + } catch (err) { + throw new createHttpError.InternalServerError("خطای سرور"); + } + } + + async applicantLogin(nationalCode: string) { + try { + const identity = await Identity.findOne({ + where: { nationalCode }, + include: [ + { + model: Applicant, + as: "applicant", + }, + ], + }); + + if (!identity?.applicantId) { + throw new createHttpError.NotFound( + authErrorMessages.notFound.applicant, + ); + } + + const token = jwt.sign( + { userId: identity.applicantId }, + process.env.JWT_SECRET || "secret", + { expiresIn: "24h" }, // طول عمر توکن + ); + + return { + token, + applicant: { id: identity.applicantId, fullname: `${identity.firstName} ${identity.lastName}`, role: identity }, + }; + } catch (error) { + throw new createHttpError.InternalServerError("خطای سرور"); + } + } +} + +const AuthService = new AuthServiceClass(); + +export default AuthService; diff --git a/src/modules/file/controller/file.controller.ts b/src/modules/file/controller/file.controller.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/file/service/file.service.ts b/src/modules/file/service/file.service.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/center/controller/center.controller.ts b/src/modules/forms/center/controller/center.controller.ts new file mode 100644 index 0000000..58db448 --- /dev/null +++ b/src/modules/forms/center/controller/center.controller.ts @@ -0,0 +1,81 @@ +import { NextFunction } from "express"; +import { Controller } from "../../../../core/controller/main.controller"; +import { ServerResponse } from "../../../../core/types"; +import CenterService from "../service/center.service"; + +class CenterControllerClass extends Controller { + #service; + constructor() { + super(); + this.#service = CenterService; + } + async getAll(req: any, res: ServerResponse, next: NextFunction) { + try { + const centers = await this.#service.getAll(); + return res.status(200).json({ + status: 200, + data: centers, + message: "Ok", + }); + } catch (error) { + next(error); + } + } + async getById(req: any, res: ServerResponse, next: NextFunction) { + try { + const id = req?.params?.id; + + const centers = await this.#service.getById(id); + return res.status(200).json({ + status: 200, + data: centers, + message: "Ok", + }); + } catch (error) { + next(error); + } + } + async create(req: any, res: ServerResponse, next: NextFunction) { + try { + await this.#service.create(req.body); + return res.status(200).json({ + status: 200, + data: {}, + message: "ساخته شد", + }); + } catch (error) { + next(error); + } + } + async update(req: any, res: ServerResponse, next: NextFunction) { + try { + const id = req?.params?.id; + await this.#service.update(id, req.body); + return res.status(200).json({ + status: 200, + data: {}, + message: "ويرايش شد", + }); + } catch (error) { + next(error); + } + } + async delete(req: any, res: ServerResponse, next: NextFunction) { + try { + const id = req?.params?.id; + + await this.#service.delete(id); + return res.status(200).json({ + status: 200, + data: {}, + message: "حذف شد", + }); + } catch (error) { + next(error); + } + } +} + +const CenterController = new CenterControllerClass(); + +export default CenterController; diff --git a/src/modules/forms/center/routes/center.routes.ts b/src/modules/forms/center/routes/center.routes.ts new file mode 100644 index 0000000..688cfbd --- /dev/null +++ b/src/modules/forms/center/routes/center.routes.ts @@ -0,0 +1,12 @@ +import { Router } from "express"; +import CenterController from "../controller/center.controller"; + +const CenterRouter = Router(); + +CenterRouter.post("/", CenterController.create); // ایجاد +CenterRouter.get("/", CenterController.getAll); // لیست همه +CenterRouter.get("/:id", CenterController.getById); // مشاهده یکی +CenterRouter.put("/:id", CenterController.update); // ویرایش +CenterRouter.delete("/:id", CenterController.delete); // حذف + +export default CenterRouter; diff --git a/src/modules/forms/center/service/center.service.ts b/src/modules/forms/center/service/center.service.ts new file mode 100644 index 0000000..b0548ea --- /dev/null +++ b/src/modules/forms/center/service/center.service.ts @@ -0,0 +1,51 @@ +import createHttpError from "http-errors"; +import { Controller } from "../../../../core/controller/main.controller"; +import { GlobalErrorMessages } from "../../../../core/messages/errors"; +import { Center } from "../../../../models/Center"; +import { JobCategory } from "../../../../models/JobCategory"; + +class CenterServiceClass extends Controller { + // ایجاد مرکز جدید + async create(data: any) { + return await Center.create(data); + } + + // دریافت لیست تمام مراکز (همراه با رسته‌های شغلی مرتبط) + async getAll() { + return await Center.findAll({ + include: [{ model: JobCategory, as: "categories" }], + order: [["createdAt", "DESC"]], + }); + } + + // دریافت یک مرکز خاص با ID + async getById(id: string) { + const center = await Center.findByPk(id, { + include: [{ model: JobCategory, as: "categories" }], + }); + if (!center) throw new Error("مرکز مورد نظر یافت نشد."); + return center; + } + + // بروزرسانی اطلاعات مرکز + async update(id: string, data: any) { + const center = await this.getById(id); + return await center.update(data); + } + + // حذف مرکز + async delete(id: string) { + const center = await this.getById(id); + await center.destroy(); + return { message: "مرکز با موفقیت حذف شد." }; + } + + // متد کمکی برای گرفتن مراکز فوری (Urgent) + async getUrgentCenters() { + return await Center.findAll({ where: { isUrgent: true } }); + } +} + +const CenterService = new CenterServiceClass(); + +export default CenterService; diff --git a/src/modules/forms/course/controller/courseForm.controller.ts b/src/modules/forms/course/controller/courseForm.controller.ts new file mode 100644 index 0000000..2d202bd --- /dev/null +++ b/src/modules/forms/course/controller/courseForm.controller.ts @@ -0,0 +1,61 @@ +import { Controller } from "../../../../core/controller/main.controller"; +import { ServerResponse } from "../../../../core/types"; +import { NextFunction } from "express"; +import CourseInfoService from "../service/courseForm.service"; + +class CourseInfoControllerClass extends Controller { + #service; + constructor() { + super(); + this.#service = CourseInfoService; + } + async create(req: any, res: ServerResponse, next: NextFunction) { + try { + const course = await this.#service.create(req.body); + res.status(201).json({ status: 200, data: course }); + } catch (err) { + next(err); + } + } + + async getById(req: any, res: ServerResponse, next: NextFunction) { + try { + const course = await this.#service.getById(req.params.id); + res.json({ status: 200, data: course }); + } catch (err) { + next(err); + } + } + + async list(req: any, res: ServerResponse, next: NextFunction) { + try { + const { applicantId } = req.query as { applicantId?: string }; + const courses = await this.#service.list(applicantId); + res.json({ status: 200, data: courses }); + } catch (err) { + next(err); + } + } + + async update(req: any, res: ServerResponse, next: NextFunction) { + try { + const updated = await this.#service.update(req.params.id, req.body); + res.json({ status: 200, data: updated }); + } catch (err) { + next(err); + } + } + + async delete(req: any, res: ServerResponse, next: NextFunction) { + try { + const result = await this.#service.delete(req.params.id); + res.json({ status: 200, data: result }); + } catch (err) { + next(err); + } + } +} + +const CourseInfoController = new CourseInfoControllerClass(); + +export default CourseInfoController; diff --git a/src/modules/forms/course/index.routes.ts b/src/modules/forms/course/index.routes.ts new file mode 100644 index 0000000..86a0f30 --- /dev/null +++ b/src/modules/forms/course/index.routes.ts @@ -0,0 +1,11 @@ +import { Router } from "express"; +import CourseInfoController from "./controller/courseForm.controller"; + +const CourseInfoRouter = Router(); +CourseInfoRouter.post("/create", CourseInfoController.create); +// CourseInfoRouter.get("/all", CourseInfoController.getAll); +CourseInfoRouter.get("/get/:id", CourseInfoController.getById); +CourseInfoRouter.put("/update/:id", CourseInfoController.update); +CourseInfoRouter.delete("/remove/:id", CourseInfoController.delete); + +export default CourseInfoRouter; diff --git a/src/modules/forms/course/messages/courseForm.messages.ts b/src/modules/forms/course/messages/courseForm.messages.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/course/service/courseForm.service.ts b/src/modules/forms/course/service/courseForm.service.ts new file mode 100644 index 0000000..4cd87e4 --- /dev/null +++ b/src/modules/forms/course/service/courseForm.service.ts @@ -0,0 +1,49 @@ +import createHttpError from "http-errors"; +import { Controller } from "../../../../core/controller/main.controller"; +import { Course } from "../../../../models/Course"; + +export interface CoursePayload { + applicantId: string; + degree: string; + field: string; + university: string; + startYear?: number | null; + endYear?: number | null; + gpa?: number | null; + description?: string | null; + certificateImageId?: string | null; +} + +class CourseServiceClass extends Controller { + async create(data: any) { + return await Course.create(data); + } + + async getById(id: string) { + const course = await Course.findByPk(id); + if (!course) throw new createHttpError.NotFound("دوره یافت نشد"); + return course; + } + + async list(applicantId?: string) { + const where = applicantId ? { applicantId } : {}; + return await Course.findAll({ where }); + } + + async update(id: string, data: any) { + const [affectedRows] = await Course.update(data, { where: { id } }); + if (affectedRows === 0) + throw new createHttpError.NotFound("دوره برای ویرایش یافت نشد"); + return await Course.findByPk(id); + } + + async delete(id: string) { + const deleted = await Course.destroy({ where: { id } }); + if (!deleted) throw new createHttpError.NotFound("دوره برای حذف یافت نشد"); + return { message: "دوره با موفقیت حذف شد" }; + } +} + +const CourseService = new CourseServiceClass(); + +export default CourseService; diff --git a/src/modules/forms/course/validation/index.ts b/src/modules/forms/course/validation/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/education/controller/educationForm.controller.ts b/src/modules/forms/education/controller/educationForm.controller.ts new file mode 100644 index 0000000..7c6a141 --- /dev/null +++ b/src/modules/forms/education/controller/educationForm.controller.ts @@ -0,0 +1,71 @@ +import { Controller } from "../../../../core/controller/main.controller"; +import { ServerResponse } from "../../../../core/types"; +import { NextFunction } from "express"; +import EducationInfoService from "../service/educationForm.service"; + +class EducationInfoControllerClass extends Controller { + #service; + constructor() { + super(); + this.#service = EducationInfoService; + } + // POST /educations + async create(req: any, res: ServerResponse, next: NextFunction) { + try { + const result = await this.#service.create(req.body); + res.status(201).json({ status: 201, data: result }); + } catch (err) { + next(err); + } + } + + // GET /educations/:id + async getById(req: any, res: ServerResponse, next: NextFunction) { + try { + const { id } = req.params; + const result = await this.#service.getById(id); + res.json({ status: 201, data: result }); + } catch (err) { + next(err); + } + } + + // GET /educations?applicantId=... + async list(req: any, res: ServerResponse, next: NextFunction) { + try { + const { applicantId } = req.query; + const result = await this.#service.list({ + applicantId: applicantId as string | undefined, + }); + res.json({ status: 201, data: result }); + } catch (err) { + next(err); + } + } + + // PUT /educations/:id + async update(req: any, res: ServerResponse, next: NextFunction) { + try { + const { id } = req.params; + const result = await this.#service.update(id, req.body); + res.json({ status: 201, data: result }); + } catch (err) { + next(err); + } + } + + // DELETE /educations/:id + async delete(req: any, res: ServerResponse, next: NextFunction) { + try { + const { id } = req.params; + const result = await this.#service.delete(id); + res.json({ status: 201, data: result }); + } catch (err) { + next(err); + } + } +} + +const EducationInfoController = new EducationInfoControllerClass(); + +export default EducationInfoController; diff --git a/src/modules/forms/education/index.routes.ts b/src/modules/forms/education/index.routes.ts new file mode 100644 index 0000000..50e5f86 --- /dev/null +++ b/src/modules/forms/education/index.routes.ts @@ -0,0 +1,11 @@ +import { Router } from "express"; +import EducationInfoController from "./controller/educationForm.controller"; + +const EducationInfoRouter = Router(); +EducationInfoRouter.post("/create", EducationInfoController.create); +// EducationInfoRouter.get("/all", EducationInfoController.getAll); +EducationInfoRouter.get("/get/:id", EducationInfoController.getById); +EducationInfoRouter.put("/update/:id", EducationInfoController.update); +EducationInfoRouter.delete("/remove/:id", EducationInfoController.delete); + +export default EducationInfoRouter; diff --git a/src/modules/forms/education/messages/educationForm.messages.ts b/src/modules/forms/education/messages/educationForm.messages.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/education/service/educationForm.service.ts b/src/modules/forms/education/service/educationForm.service.ts new file mode 100644 index 0000000..a3bf44d --- /dev/null +++ b/src/modules/forms/education/service/educationForm.service.ts @@ -0,0 +1,120 @@ +import createHttpError from "http-errors"; +import { Controller } from "../../../../core/controller/main.controller"; +import { Education } from "../../../../models/Education"; + + +export interface EducationPayload { + applicantId: string; + degree: string; + field: string; + university: string; + startYear?: number | null; + endYear?: number | null; + gpa?: number | null; + description?: string | null; + certificateImageId?: string | null; +} + +class EducationServiceClass extends Controller { + // ایجاد رکورد جدید + async create(data: EducationPayload) { + try { + const education = await Education.create({ + applicantId: data.applicantId, + degree: data.degree, + field: data.field, + university: data.university, + startYear: data.startYear ?? undefined, + endYear: data.endYear ?? undefined, + gpa: data.gpa ?? undefined, + description: data.description ?? "", + certificateImageId: data.certificateImageId ?? undefined, + }); + + return education; + } catch (err) { + throw new createHttpError.InternalServerError( + "خطا در ایجاد سابقه تحصیلی", + ); + } + } + + // گرفتن یک رکورد با id + async getById(id: string) { + const education = await Education.findByPk(id); + + if (!education) { + throw new createHttpError.NotFound("سابقه تحصیلی پیدا نشد"); + } + + return education; + } + + // لیست سوابق، مثلا بر اساس applicantId + async list(filter?: { applicantId?: string }) { + const where: any = {}; + + if (filter?.applicantId) { + where.applicantId = filter.applicantId; + } + + const list = await Education.findAll({ where }); + return list; + } + + // بروزرسانی + async update(id: string, data: Partial) { + const education = await Education.findByPk(id); + + if (!education) { + throw new createHttpError.NotFound("سابقه تحصیلی پیدا نشد"); + } + + try { + await education.update({ + applicantId: data.applicantId ?? education.applicantId, + degree: data.degree ?? education.degree, + field: data.field ?? education.field, + university: data.university ?? education.university, + startYear: + typeof data.startYear === "number" + ? data.startYear + : education.startYear, + endYear: + typeof data.endYear === "number" ? data.endYear : education.endYear, + gpa: typeof data.gpa === "number" ? data.gpa : education.gpa, + description: data.description ?? education.description, + certificateImageId: + data.certificateImageId ?? education.certificateImageId, + }); + + return education; + } catch (err) { + throw new createHttpError.InternalServerError( + "خطا در بروزرسانی سابقه تحصیلی", + ); + } + } + + // حذف + async delete(id: string) { + const education = await Education.findByPk(id); + + if (!education) { + throw new createHttpError.NotFound("سابقه تحصیلی پیدا نشد"); + } + + try { + await education.destroy(); + return { success: true }; + } catch (err) { + throw new createHttpError.InternalServerError( + "خطا در حذف سابقه تحصیلی", + ); + } + } +} + +const EducationService = new EducationServiceClass(); + +export default EducationService; diff --git a/src/modules/forms/education/validation/index.ts b/src/modules/forms/education/validation/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/identity/controller/identityForm.controller.ts b/src/modules/forms/identity/controller/identityForm.controller.ts new file mode 100644 index 0000000..3c866e5 --- /dev/null +++ b/src/modules/forms/identity/controller/identityForm.controller.ts @@ -0,0 +1,61 @@ +import { NextFunction } from "express"; +import { Controller } from "../../../../core/controller/main.controller"; +import { ServerResponse } from "../../../../core/types"; +import IdentityFormService from "../service/identityForm.service"; + +class IdentityFormControllerClass extends Controller { + #service; + constructor() { + super(); + this.#service = IdentityFormService; + } + + async getById(req: any, res: ServerResponse, next: NextFunction) { + try { + const id = req?.params?.id; + const data = await this.#service.getById(id); + + return res.status(200).json({ + status: 200, + data, + message: "Ok", + }); + } catch (error) { + next(error); + } + } + // create and import identity form (step 1 in system) + async create(req: any, res: ServerResponse, next: NextFunction) { + try { + await this.#service.create(req.body); + + return res.status(200).json({ + status: 200, + data: {}, + message: "ثبت شد", + }); + } catch (error) { + next(error); + } + } + // update identity form + async update(req: any, res: ServerResponse, next: NextFunction) { + try { + const id = req?.params?.id; + await this.#service.update(id, req.body); + + return res.status(200).json({ + status: 200, + data: {}, + message: "ويرايش شد", + }); + } catch (error) { + next(error); + } + } + +} + +const IdentityFormController = new IdentityFormControllerClass(); + +export default IdentityFormController; diff --git a/src/modules/forms/identity/index.routes.ts b/src/modules/forms/identity/index.routes.ts new file mode 100644 index 0000000..c3f95f8 --- /dev/null +++ b/src/modules/forms/identity/index.routes.ts @@ -0,0 +1,11 @@ +import { Router } from "express"; +import IdentityFormController from "./controller/identityForm.controller"; + +const identityRouter = Router(); + +identityRouter.post("/create", IdentityFormController.create); +// identityRouter.get("/all", IdentityFormController.getAll); +identityRouter.get("/get/:id", IdentityFormController.getById); +identityRouter.put("/update/:id", IdentityFormController.update); +// identityRouter.delete("/remove/:id", IdentityFormController.remove); +export default identityRouter; diff --git a/src/modules/forms/identity/messages/identityForm.messages.ts b/src/modules/forms/identity/messages/identityForm.messages.ts new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/modules/forms/identity/messages/identityForm.messages.ts @@ -0,0 +1 @@ + diff --git a/src/modules/forms/identity/service/identityForm.service.ts b/src/modules/forms/identity/service/identityForm.service.ts new file mode 100644 index 0000000..f745147 --- /dev/null +++ b/src/modules/forms/identity/service/identityForm.service.ts @@ -0,0 +1,86 @@ +import createHttpError from "http-errors"; +import { Controller } from "../../../../core/controller/main.controller"; +import { GlobalErrorMessages } from "../../../../core/messages/errors"; +import { Identity } from "../../../../models/Identity"; +import { Applicant } from "../../../../models/Applicant"; +import { UUIDV4 } from "sequelize"; +import { Center } from "../../../../models/Center"; + +class IdentityFormServiceClass extends Controller { + async getById(id: string) { + try { + const data = await Identity.findOne({ where: { id } }); + + return data; + } catch (error) { + throw new createHttpError.InternalServerError( + GlobalErrorMessages.server.internal, + ); + } + } + async create(data: any) { + let applicantId = null; + + try { + applicantId = await Applicant.create({ + id: UUIDV4().toString({}), + }); + } catch (error) { + throw new createHttpError.InternalServerError( + GlobalErrorMessages.server.internal, + ); + } + + try { + await Identity.create({ + applicantId: applicantId.id, + birthDate: data.birthDate, + birthPlace: data.birthPlace, + fatherName: data.fatherName, + firstName: data.firstName, + nationalCode: data.nationalCode, + gender: data.gender, + lastName: data.lastName, + nationality: data.nationality, + religion: data.religion, + profilePhotoId: data.profilePhotoId, + }); + } catch (error) { + throw new createHttpError.InternalServerError( + GlobalErrorMessages.server.internal, + ); + } + } + async update(formID: string, data: any) { + const [affectedRows] = await Identity.update( + { + birthDate: data.birthDate, + birthPlace: data.birthPlace, + fatherName: data.fatherName, + firstName: data.firstName, + nationalCode: data.nationalCode, + gender: data.gender, + lastName: data.lastName, + nationality: data.nationality, + religion: data.religion, + profilePhotoId: data.profilePhotoId, + }, + { + where: { + id: formID, // اعمال شرط برای آپدیت فقط همین فرم خاص + }, + }, + ); + + // بررسی اینکه آیا ردیفی پیدا و آپدیت شده است یا خیر + if (affectedRows === 0) { + throw new createHttpError.NotFound("فرم پیدا نشد"); + } + + return true; + } +} + +const IdentityFormService = new IdentityFormServiceClass(); + +export default IdentityFormService; diff --git a/src/modules/forms/index.routes.ts b/src/modules/forms/index.routes.ts new file mode 100644 index 0000000..2ed42ef --- /dev/null +++ b/src/modules/forms/index.routes.ts @@ -0,0 +1,16 @@ +import { Router } from "express"; +import PersonalInfoRouter from "./personalInfo/index.routes"; +import identityRouter from "./identity/index.routes"; +import PhysicalInfoRouter from "./physicalInfo/index.routes"; +import EducationInfoRouter from "./education/index.routes"; +import CourseInfoRouter from "./course/index.routes"; + +const formRouter = Router(); + +formRouter.use("/identity", identityRouter); +formRouter.use("/personal-info", PersonalInfoRouter); +formRouter.use("/physical-info", PhysicalInfoRouter); +formRouter.use("/education", EducationInfoRouter); +formRouter.use("/course", CourseInfoRouter); + +export default formRouter; diff --git a/src/modules/forms/personalInfo/controller/personalInfoForm.controller.ts b/src/modules/forms/personalInfo/controller/personalInfoForm.controller.ts new file mode 100644 index 0000000..9033710 --- /dev/null +++ b/src/modules/forms/personalInfo/controller/personalInfoForm.controller.ts @@ -0,0 +1,79 @@ +import { Controller } from "../../../../core/controller/main.controller"; +import { ServerResponse } from "../../../../core/types"; +import { NextFunction } from "express"; +import PersonalInfoService from "../service/personalInfoForm.service"; + +class PersonalInfoControllerClass extends Controller { + #service; + constructor() { + super(); + this.#service = PersonalInfoService; + } + // POST /personal-infos + async create(req: any, res: ServerResponse, next: NextFunction) { + try { + const result = await this.#service.create(req.body); + res.status(201).json({ status: 201, data: result }); + } catch (error) { + next(error); + } + } + + // GET /personal-infos/:id + async getById(req: any, res: ServerResponse, next: NextFunction) { + try { + const { id } = req.params; + const result = await this.#service.findById(id); + res.status(200).json({ status: 200, data: result }); + } catch (error) { + next(error); + } + } + + // GET /personal-infos + async getAll(req: any, res: ServerResponse, next: NextFunction) { + try { + const result = await this.#service.findAll(); + res.status(200).json({ status: 200, data: result }); + } catch (error) { + next(error); + } + } + + // GET /personal-infos/applicant/:applicantId + async getByApplicantId(req: any, res: ServerResponse, next: NextFunction) { + try { + const { applicantId } = req.params; + const result = await this.#service.findByApplicantId(applicantId); + res.status(200).json({ status: 200, data: result }); + } catch (error) { + next(error); + } + } + + // PUT /personal-infos/:id + async update(req: any, res: ServerResponse, next: NextFunction) { + try { + const { id } = req.params; + const result = await this.#service.update(id, req.body); + res.status(200).json({ status: 200, data: result }); + } catch (error) { + next(error); + } + } + + // DELETE /personal-infos/:id + async remove(req: any, res: ServerResponse, next: NextFunction) { + try { + const { id } = req.params; + const result = await this.#service.delete(id); + res.status(200).json({ status: 200, data: result }); + } catch (error) { + next(error); + } + } +} + +const PersonalInfoController = new PersonalInfoControllerClass(); + +export default PersonalInfoController; diff --git a/src/modules/forms/personalInfo/index.routes.ts b/src/modules/forms/personalInfo/index.routes.ts new file mode 100644 index 0000000..bd650bd --- /dev/null +++ b/src/modules/forms/personalInfo/index.routes.ts @@ -0,0 +1,11 @@ +import { Router } from "express"; +import PersonalInfoController from "./controller/personalInfoForm.controller"; + +const PersonalInfoRouter = Router(); +PersonalInfoRouter.post("/create", PersonalInfoController.create); +PersonalInfoRouter.get("/all", PersonalInfoController.getAll); +PersonalInfoRouter.get("/get/:id", PersonalInfoController.getById); +PersonalInfoRouter.put("/update/:id", PersonalInfoController.update); +PersonalInfoRouter.delete("/remove/:id", PersonalInfoController.remove); + +export default PersonalInfoRouter; diff --git a/src/modules/forms/personalInfo/messages/personalInfoForm.messages.ts b/src/modules/forms/personalInfo/messages/personalInfoForm.messages.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/personalInfo/service/personalInfoForm.service.ts b/src/modules/forms/personalInfo/service/personalInfoForm.service.ts new file mode 100644 index 0000000..ee5abe5 --- /dev/null +++ b/src/modules/forms/personalInfo/service/personalInfoForm.service.ts @@ -0,0 +1,119 @@ +import createHttpError from "http-errors"; +import { Controller } from "../../../../core/controller/main.controller"; +import { PersonalInfo } from "../../../../models/PersonalInfo"; + +class PersonalInfoServiceClass extends Controller { + async create(data: any) { + try { + const record = await PersonalInfo.create({ + applicantId: data.applicantId, + maritalStatus: data.maritalStatus, + militaryStatus: data.militaryStatus, + fatherEducation: data.fatherEducation, + fatherJob: data.fatherJob, + motherEducation: data.motherEducation, + motherJob: data.motherJob, + housingStatus: data.housingStatus, + city: data.city, + address: data.address, + homePhone: data.homePhone, + mobilePhone: data.mobilePhone, + emergencyPhone: data.emergencyPhone, + email: data.email, + residenceDuration: data.residenceDuration, + isVeteran: data.isVeteran, + hasCriminalRecord: data.hasCriminalRecord, + criminalDescription: data.criminalDescription, + }); + + return record; + } catch (error: any) { + throw new createHttpError.InternalServerError( + error.message || "خطا در ایجاد اطلاعات شخصی", + ); + } + } + + async findById(id: string) { + const record = await PersonalInfo.findByPk(id); + + if (!record) { + throw new createHttpError.NotFound("اطلاعات شخصی پیدا نشد"); + } + + return record; + } + + // اگر لازم داری همه رکوردها رو بگیری + async findAll() { + const records = await PersonalInfo.findAll(); + return records; + } + + // مثلا گرفتن بر اساس applicantId + async findByApplicantId(applicantId: string) { + const record = await PersonalInfo.findOne({ + where: { applicantId }, + }); + + if (!record) { + throw new createHttpError.NotFound( + "اطلاعات شخصی برای این متقاضی پیدا نشد", + ); + } + + return record; + } + + async update(id: string, data: any) { + const [affectedRows] = await PersonalInfo.update( + { + applicantId: data.applicantId, + maritalStatus: data.maritalStatus, + militaryStatus: data.militaryStatus, + fatherEducation: data.fatherEducation, + fatherJob: data.fatherJob, + motherEducation: data.motherEducation, + motherJob: data.motherJob, + housingStatus: data.housingStatus, + city: data.city, + address: data.address, + homePhone: data.homePhone, + mobilePhone: data.mobilePhone, + emergencyPhone: data.emergencyPhone, + email: data.email, + residenceDuration: data.residenceDuration, + isVeteran: data.isVeteran, + hasCriminalRecord: data.hasCriminalRecord, + criminalDescription: data.criminalDescription, + }, + { + where: { id }, + }, + ); + + if (affectedRows === 0) { + throw new createHttpError.NotFound("اطلاعات شخصی برای ویرایش پیدا نشد"); + } + + // برگردوندن رکورد آپدیت‌شده + const updated = await PersonalInfo.findByPk(id); + return updated; + } + + async delete(id: string) { + const deletedCount = await PersonalInfo.destroy({ + where: { id }, + }); + + if (deletedCount === 0) { + throw new createHttpError.NotFound("اطلاعات شخصی برای حذف پیدا نشد"); + } + + return { success: true }; + } +} + +const PersonalInfoService = new PersonalInfoServiceClass(); + +export default PersonalInfoService; diff --git a/src/modules/forms/personalInfo/validation/index.ts b/src/modules/forms/personalInfo/validation/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/physicalInfo/controller/physicalInfoForm.controller.ts b/src/modules/forms/physicalInfo/controller/physicalInfoForm.controller.ts new file mode 100644 index 0000000..8d36b17 --- /dev/null +++ b/src/modules/forms/physicalInfo/controller/physicalInfoForm.controller.ts @@ -0,0 +1,51 @@ +import { Controller } from "../../../../core/controller/main.controller"; +import { ServerResponse } from "../../../../core/types"; +import { NextFunction } from "express"; +import PhysicalInfoService from "../service/physicalInfoForm.service"; + +class PhysicalInfoControllerClass extends Controller { + #service; + constructor() { + super(); + this.#service = PhysicalInfoService; + } + async create(req: any, res: ServerResponse, next: NextFunction) { + try { + const info = await this.#service.create(req.body); + res.status(201).json({ status: 201, data: info }); + } catch (error) { + next(error); + } + } + + async getById(req: any, res: ServerResponse, next: NextFunction) { + try { + const info = await this.#service.getById(req.params.id); + res.json({ status: 200, data: info }); + } catch (error) { + next(error); + } + } + + async update(req: any, res: ServerResponse, next: NextFunction) { + try { + const updatedInfo = await this.#service.update(req.params.id, req.body); + res.json({ status: 200, data: updatedInfo }); + } catch (error) { + next(error); + } + } + + async delete(req: any, res: ServerResponse, next: NextFunction) { + try { + const result = await this.#service.delete(req.params.id); + res.json({ status: 200, data: result }); + } catch (error) { + next(error); + } + } +} + +const PhysicalInfoController = new PhysicalInfoControllerClass(); + +export default PhysicalInfoController; diff --git a/src/modules/forms/physicalInfo/index.routes.ts b/src/modules/forms/physicalInfo/index.routes.ts new file mode 100644 index 0000000..3a2eaf2 --- /dev/null +++ b/src/modules/forms/physicalInfo/index.routes.ts @@ -0,0 +1,11 @@ +import { Router } from "express"; +import PhysicalInfoController from "./controller/physicalInfoForm.controller"; + +const PhysicalInfoRouter = Router(); +PhysicalInfoRouter.post("/create", PhysicalInfoController.create); +// PhysicalInfoRouter.get("/all", PhysicalInfoController.getAll); +PhysicalInfoRouter.get("/get/:id", PhysicalInfoController.getById); +PhysicalInfoRouter.put("/update/:id", PhysicalInfoController.update); +PhysicalInfoRouter.delete("/remove/:id", PhysicalInfoController.delete); + +export default PhysicalInfoRouter; diff --git a/src/modules/forms/physicalInfo/messages/physicalInfoForm.messages.ts b/src/modules/forms/physicalInfo/messages/physicalInfoForm.messages.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/forms/physicalInfo/service/physicalInfoForm.service.ts b/src/modules/forms/physicalInfo/service/physicalInfoForm.service.ts new file mode 100644 index 0000000..d132748 --- /dev/null +++ b/src/modules/forms/physicalInfo/service/physicalInfoForm.service.ts @@ -0,0 +1,43 @@ +import createHttpError from "http-errors"; +import { Controller } from "../../../../core/controller/main.controller"; +import { PhysicalInfo } from "../../../../models/PhysicalInfo"; + +class PhysicalInfoServiceClass extends Controller { + async create(data: any) { + return await PhysicalInfo.create(data); + } + + async getById(id: string) { + const info = await PhysicalInfo.findByPk(id); + if (!info) throw new createHttpError.NotFound("اطلاعات جسمانی یافت نشد"); + return info; + } + + async update(id: string, data: any) { + const [affectedRows] = await PhysicalInfo.update(data, { + where: { id }, + }); + + if (affectedRows === 0) { + throw new createHttpError.NotFound("اطلاعات جسمانی برای ویرایش یافت نشد"); + } + + return await PhysicalInfo.findByPk(id); + } + + async delete(id: string) { + const deleted = await PhysicalInfo.destroy({ + where: { id }, + }); + + if (!deleted) { + throw new createHttpError.NotFound("اطلاعات جسمانی برای حذف یافت نشد"); + } + + return { message: "با موفقیت حذف شد" }; + } +} + +const PhysicalInfoService = new PhysicalInfoServiceClass(); + +export default PhysicalInfoService; diff --git a/src/modules/forms/physicalInfo/validation/index.ts b/src/modules/forms/physicalInfo/validation/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..123bad0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + + "outDir": "dist" + } +}