├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── examples └── express │ ├── app.ts │ ├── package-lock.json │ └── package.json ├── jest.config.ts ├── jsdoc.json ├── package-lock.json ├── package.json ├── src ├── drivers │ ├── idpay │ │ ├── __tests__ │ │ │ └── idPayDriver.test.ts │ │ ├── enums │ │ │ └── urls.enum.ts │ │ ├── idpay.ts │ │ ├── index.ts │ │ └── interfaces │ │ │ ├── request.interface.ts │ │ │ └── response.interface.ts │ ├── main.ts │ ├── zarinpal │ │ ├── __tests__ │ │ │ └── zarinpal.spec.ts │ │ ├── enums │ │ │ ├── errors.enum.ts │ │ │ └── urls.enum.ts │ │ ├── index.ts │ │ ├── interfaces │ │ │ └── requests.interface.ts │ │ └── zarinpal.ts │ └── zibal │ │ ├── enums │ │ ├── message.enum.ts │ │ └── urls.enum.ts │ │ ├── index.ts │ │ ├── interfaces │ │ ├── requests.interface.ts │ │ └── response.interface.ts │ │ └── zibal.ts ├── easypay.ts └── index.ts ├── tsconfig.json └── tsup.config.ts /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | project: 'tsconfig.json', 5 | tsconfigRootDir: __dirname, 6 | sourceType: 'module' 7 | }, 8 | plugins: ['@typescript-eslint/eslint-plugin', 'prettier'], 9 | extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'], 10 | root: true, 11 | env: { 12 | node: true, 13 | jest: true 14 | }, 15 | ignorePatterns: ['.eslintrc.js'], 16 | rules: { 17 | '@typescript-eslint/interface-name-prefix': 'off', 18 | '@typescript-eslint/explicit-function-return-type': 'off', 19 | '@typescript-eslint/explicit-module-boundary-types': 'off', 20 | '@typescript-eslint/no-explicit-any': 'off', 21 | 'prettier/prettier': 'error' // Added this rule to enforce Prettier 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | 3 | dist/ 4 | *.log 5 | 6 | .DS_Store 7 | 8 | .idea 9 | .env 10 | docs 11 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSameLine": true, 4 | "bracketSpacing": true, 5 | "singleQuote": true, 6 | "trailingComma": "none", 7 | "semi": false, 8 | "printWidth": 120, 9 | "tabWidth": 2, 10 | "endOfLine": "auto" 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Sajjad Isvand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easypay.js 2 | 3 | ![GitHub package.json version](https://img.shields.io/github/package-json/v/sajjadmrx/easypay-js) 4 | ![GitHub](https://img.shields.io/github/license/sajjadmrx/easypay-js) 5 | ![GitHub last commit](https://img.shields.io/github/last-commit/sajjadmrx/easypay-js) 6 | 7 | **easypay.js** is a comprehensive payment service library designed specifically for handling various Iranian payment gateways with ease. 8 | 9 | ## Features 10 | - **Extensible**: Easily extend the library to support other Iranian payment gateways in the future. 11 | - **Simple Integration**: Designed for developers to quickly integrate payment functionalities into their applications. 12 | 13 | ## Supported Gateways 14 | - [x] ZarinPal 15 | - [x] IDPay 16 | - [x] Zibal 17 | 18 | ## Installation 19 | 20 | ```bash 21 | npm install easypay.js 22 | ``` 23 | 24 | ## Usage 25 | 26 | Here's a basic example demonstrating how to integrate ZarinPal using `easypay.js` with an Express.js application: 27 | 28 | ```typescript 29 | import express, { Request, Response } from "express"; 30 | import { getPaymentDriver, ZarinPalDriver } from "easypay.js"; 31 | 32 | const app = express(); 33 | 34 | app.listen(3000); 35 | 36 | const zarinPalDriver: ZarinPalDriver = getPaymentDriver("zarinpal"); 37 | zarinPalDriver.setToken("your-zarinpal-token"); 38 | 39 | const AMOUNT = 100000; 40 | 41 | app.post("/payment/checkout", async (req: Request, res: Response) => { 42 | const result = await zarinPalDriver.request( 43 | { 44 | amount: AMOUNT, 45 | callback_url: "http://localhost:3000/payment/checkout/cb", 46 | description: "test description", 47 | }, 48 | false, 49 | ); 50 | 51 | if (result.isError) { 52 | res.status(500).json({ 53 | success: false, 54 | message: result.error.message, 55 | errCode: result.error.code, 56 | validations: result.error.validations, 57 | }); 58 | } else { 59 | res.status(200).json({ 60 | success: true, 61 | messsage: result.data.message, 62 | url: result.data.url, 63 | }); 64 | } 65 | }); 66 | 67 | app.get("/payment/checkout/cb", async (req: Request, res: Response) => { 68 | const Status = String(req.query.Status); 69 | if (Status === "OK") { 70 | const verifyResult = await zarinPalDriver.verify({ 71 | amount: AMOUNT, 72 | authority: String(req.query.Authority), 73 | }); 74 | 75 | if (verifyResult.isError) { 76 | res.status(400).json({ 77 | success: true, 78 | message: verifyResult.error.message, // or custom message 79 | code: verifyResult.error.code, 80 | }); 81 | } else { 82 | res.status(200).json({ 83 | success: true, 84 | verifyResult, 85 | }); 86 | } 87 | } else { 88 | res.status(400).json({ success: false, message: "canceled" }); 89 | } 90 | }); 91 | 92 | console.log(`Server running on port: 3000`); 93 | ``` 94 | 95 | ## Documentation 96 | 97 | For detailed documentation and API references, visit the official documentation: [easypay.js Documentation](https://sajjadmrx.github.io/easypay-js) 98 | 99 | ## Contributing 100 | 101 | We welcome contributions! Please read our [Contributing Guidelines](link-to-contributing-guidelines) for details on how to contribute to this project. 102 | 103 | ## License 104 | 105 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 106 | -------------------------------------------------------------------------------- /examples/express/app.ts: -------------------------------------------------------------------------------- 1 | import express, { Request, Response } from "express" 2 | import { getPaymentDriver, TransactionCreateInputIdPay, TransactionCreateInputZp, TransactionCreateResponseIdPay, TransactionCreateResponseZp, ZarinPalDriver } from "../../src" 3 | import { TransactionCreateResponseZibal } from "../../src/drivers/zibal/interfaces/response.interface" 4 | import { IdPayDriver } from '../../src/drivers/idpay/idpay'; 5 | 6 | const app = express() 7 | 8 | 9 | app.listen(3000) 10 | 11 | app.post("/payment/checkout", async (req: Request, res: Response) => { 12 | const zarinPalDriver = getPaymentDriver('zarinpal') 13 | 14 | zarinPalDriver.setToken("token") 15 | const AMOUNT = 100000 16 | const result = await zarinPalDriver.request({ 17 | amount: AMOUNT, 18 | callback_url: "http://localhost:3000/payment/checkout/cb", 19 | description: "test description", 20 | }, false) 21 | 22 | if (result.isError) { 23 | res.status(500).json({ 24 | success: false, 25 | message: result.error.message, 26 | errCode: result.error.code, 27 | validations: result.error.validations 28 | }) 29 | } else { 30 | res.status(200).json({ 31 | success: true, 32 | messsage: result.data.message, 33 | url: result.data.url, 34 | }) 35 | } 36 | }) 37 | 38 | app.get("/payment/checkout/cb", async (req: Request, res: Response) => { 39 | const zarinPalDriver = getPaymentDriver('zarinpal') 40 | const AMOUNT = 100000 41 | zarinPalDriver.setToken("token") 42 | 43 | const Status = String(req.query.Status) 44 | 45 | if (Status === "OK") { 46 | const verifyResult = await zarinPalDriver.verify({ 47 | amount: AMOUNT, 48 | authority: String(req.query.Authority) 49 | }) 50 | 51 | if (verifyResult.isError) { 52 | res.status(400).json({ 53 | success: true, 54 | message: verifyResult.error.message, // or custom message 55 | code: verifyResult.error.code 56 | }) 57 | } else { 58 | res.status(200).json({ 59 | success: true, 60 | verifyResult 61 | }) 62 | } 63 | } 64 | else { 65 | res.status(400).json({ success: false, message: "canceled" }) 66 | } 67 | }) 68 | 69 | app.get('/payment/zibal/checkout', async (req: Request, res: Response) => { 70 | const zibalDriver = getPaymentDriver('zibal') 71 | const AMOUNT = 10 72 | const result: TransactionCreateResponseZibal = await zibalDriver.request({ 73 | amount: AMOUNT, 74 | callbackUrl: 'http://localhost:3000/payment/zibal/checkout/cb', 75 | description: 'test description', 76 | }, true) 77 | if (result.isError) { 78 | res.status(500).json({ 79 | success: false, 80 | message: result.error?.message, 81 | }) 82 | } else { 83 | res.status(200).json({ 84 | success: true, 85 | trackId: result.data?.trackId, 86 | url: result.data?.url, 87 | }) 88 | } 89 | }) 90 | 91 | app.get('/payment/zibal/checkout/cb', async (req: Request, res: Response) => { 92 | const zibalDriver = getPaymentDriver('zibal') 93 | const AMOUNT = 1000 94 | 95 | const response = await zibalDriver.verify({ 96 | trackId: String(req.query.trackId) 97 | },true) 98 | 99 | if (response.isError) { 100 | res.status(500).json({ 101 | success: false, 102 | message: response.error?.message, 103 | }) 104 | } else { 105 | res.status(200).json({ 106 | success: true, 107 | data: response.data, 108 | }) 109 | } 110 | 111 | }) 112 | 113 | console.log("Server is running on port 3000") -------------------------------------------------------------------------------- /examples/express/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "express", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "^4.18.2" 13 | }, 14 | "devDependencies": { 15 | "@types/express": "^4.17.21", 16 | "ts-node": "^10.9.2", 17 | "typescript": "^5.3.3" 18 | } 19 | }, 20 | "node_modules/@cspotcode/source-map-support": { 21 | "version": "0.8.1", 22 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 23 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 24 | "dev": true, 25 | "dependencies": { 26 | "@jridgewell/trace-mapping": "0.3.9" 27 | }, 28 | "engines": { 29 | "node": ">=12" 30 | } 31 | }, 32 | "node_modules/@jridgewell/resolve-uri": { 33 | "version": "3.1.1", 34 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 35 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 36 | "dev": true, 37 | "engines": { 38 | "node": ">=6.0.0" 39 | } 40 | }, 41 | "node_modules/@jridgewell/sourcemap-codec": { 42 | "version": "1.4.15", 43 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 44 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 45 | "dev": true 46 | }, 47 | "node_modules/@jridgewell/trace-mapping": { 48 | "version": "0.3.9", 49 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 50 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 51 | "dev": true, 52 | "dependencies": { 53 | "@jridgewell/resolve-uri": "^3.0.3", 54 | "@jridgewell/sourcemap-codec": "^1.4.10" 55 | } 56 | }, 57 | "node_modules/@tsconfig/node10": { 58 | "version": "1.0.9", 59 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 60 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 61 | "dev": true 62 | }, 63 | "node_modules/@tsconfig/node12": { 64 | "version": "1.0.11", 65 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 66 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 67 | "dev": true 68 | }, 69 | "node_modules/@tsconfig/node14": { 70 | "version": "1.0.3", 71 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 72 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 73 | "dev": true 74 | }, 75 | "node_modules/@tsconfig/node16": { 76 | "version": "1.0.4", 77 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 78 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", 79 | "dev": true 80 | }, 81 | "node_modules/@types/body-parser": { 82 | "version": "1.19.5", 83 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", 84 | "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", 85 | "dev": true, 86 | "dependencies": { 87 | "@types/connect": "*", 88 | "@types/node": "*" 89 | } 90 | }, 91 | "node_modules/@types/connect": { 92 | "version": "3.4.38", 93 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", 94 | "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", 95 | "dev": true, 96 | "dependencies": { 97 | "@types/node": "*" 98 | } 99 | }, 100 | "node_modules/@types/express": { 101 | "version": "4.17.21", 102 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", 103 | "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", 104 | "dev": true, 105 | "dependencies": { 106 | "@types/body-parser": "*", 107 | "@types/express-serve-static-core": "^4.17.33", 108 | "@types/qs": "*", 109 | "@types/serve-static": "*" 110 | } 111 | }, 112 | "node_modules/@types/express-serve-static-core": { 113 | "version": "4.17.41", 114 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", 115 | "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", 116 | "dev": true, 117 | "dependencies": { 118 | "@types/node": "*", 119 | "@types/qs": "*", 120 | "@types/range-parser": "*", 121 | "@types/send": "*" 122 | } 123 | }, 124 | "node_modules/@types/http-errors": { 125 | "version": "2.0.4", 126 | "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", 127 | "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", 128 | "dev": true 129 | }, 130 | "node_modules/@types/mime": { 131 | "version": "1.3.5", 132 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", 133 | "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", 134 | "dev": true 135 | }, 136 | "node_modules/@types/node": { 137 | "version": "20.10.5", 138 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", 139 | "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", 140 | "dev": true, 141 | "dependencies": { 142 | "undici-types": "~5.26.4" 143 | } 144 | }, 145 | "node_modules/@types/qs": { 146 | "version": "6.9.11", 147 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", 148 | "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", 149 | "dev": true 150 | }, 151 | "node_modules/@types/range-parser": { 152 | "version": "1.2.7", 153 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", 154 | "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", 155 | "dev": true 156 | }, 157 | "node_modules/@types/send": { 158 | "version": "0.17.4", 159 | "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", 160 | "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", 161 | "dev": true, 162 | "dependencies": { 163 | "@types/mime": "^1", 164 | "@types/node": "*" 165 | } 166 | }, 167 | "node_modules/@types/serve-static": { 168 | "version": "1.15.5", 169 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", 170 | "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", 171 | "dev": true, 172 | "dependencies": { 173 | "@types/http-errors": "*", 174 | "@types/mime": "*", 175 | "@types/node": "*" 176 | } 177 | }, 178 | "node_modules/accepts": { 179 | "version": "1.3.8", 180 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 181 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 182 | "dependencies": { 183 | "mime-types": "~2.1.34", 184 | "negotiator": "0.6.3" 185 | }, 186 | "engines": { 187 | "node": ">= 0.6" 188 | } 189 | }, 190 | "node_modules/acorn": { 191 | "version": "8.11.2", 192 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", 193 | "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", 194 | "dev": true, 195 | "bin": { 196 | "acorn": "bin/acorn" 197 | }, 198 | "engines": { 199 | "node": ">=0.4.0" 200 | } 201 | }, 202 | "node_modules/acorn-walk": { 203 | "version": "8.3.1", 204 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", 205 | "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", 206 | "dev": true, 207 | "engines": { 208 | "node": ">=0.4.0" 209 | } 210 | }, 211 | "node_modules/arg": { 212 | "version": "4.1.3", 213 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 214 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 215 | "dev": true 216 | }, 217 | "node_modules/array-flatten": { 218 | "version": "1.1.1", 219 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 220 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 221 | }, 222 | "node_modules/body-parser": { 223 | "version": "1.20.1", 224 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 225 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 226 | "dependencies": { 227 | "bytes": "3.1.2", 228 | "content-type": "~1.0.4", 229 | "debug": "2.6.9", 230 | "depd": "2.0.0", 231 | "destroy": "1.2.0", 232 | "http-errors": "2.0.0", 233 | "iconv-lite": "0.4.24", 234 | "on-finished": "2.4.1", 235 | "qs": "6.11.0", 236 | "raw-body": "2.5.1", 237 | "type-is": "~1.6.18", 238 | "unpipe": "1.0.0" 239 | }, 240 | "engines": { 241 | "node": ">= 0.8", 242 | "npm": "1.2.8000 || >= 1.4.16" 243 | } 244 | }, 245 | "node_modules/bytes": { 246 | "version": "3.1.2", 247 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 248 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 249 | "engines": { 250 | "node": ">= 0.8" 251 | } 252 | }, 253 | "node_modules/call-bind": { 254 | "version": "1.0.5", 255 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", 256 | "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", 257 | "dependencies": { 258 | "function-bind": "^1.1.2", 259 | "get-intrinsic": "^1.2.1", 260 | "set-function-length": "^1.1.1" 261 | }, 262 | "funding": { 263 | "url": "https://github.com/sponsors/ljharb" 264 | } 265 | }, 266 | "node_modules/content-disposition": { 267 | "version": "0.5.4", 268 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 269 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 270 | "dependencies": { 271 | "safe-buffer": "5.2.1" 272 | }, 273 | "engines": { 274 | "node": ">= 0.6" 275 | } 276 | }, 277 | "node_modules/content-type": { 278 | "version": "1.0.5", 279 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 280 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", 281 | "engines": { 282 | "node": ">= 0.6" 283 | } 284 | }, 285 | "node_modules/cookie": { 286 | "version": "0.5.0", 287 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 288 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 289 | "engines": { 290 | "node": ">= 0.6" 291 | } 292 | }, 293 | "node_modules/cookie-signature": { 294 | "version": "1.0.6", 295 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 296 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 297 | }, 298 | "node_modules/create-require": { 299 | "version": "1.1.1", 300 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 301 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 302 | "dev": true 303 | }, 304 | "node_modules/debug": { 305 | "version": "2.6.9", 306 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 307 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 308 | "dependencies": { 309 | "ms": "2.0.0" 310 | } 311 | }, 312 | "node_modules/define-data-property": { 313 | "version": "1.1.1", 314 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", 315 | "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", 316 | "dependencies": { 317 | "get-intrinsic": "^1.2.1", 318 | "gopd": "^1.0.1", 319 | "has-property-descriptors": "^1.0.0" 320 | }, 321 | "engines": { 322 | "node": ">= 0.4" 323 | } 324 | }, 325 | "node_modules/depd": { 326 | "version": "2.0.0", 327 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 328 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 329 | "engines": { 330 | "node": ">= 0.8" 331 | } 332 | }, 333 | "node_modules/destroy": { 334 | "version": "1.2.0", 335 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 336 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 337 | "engines": { 338 | "node": ">= 0.8", 339 | "npm": "1.2.8000 || >= 1.4.16" 340 | } 341 | }, 342 | "node_modules/diff": { 343 | "version": "4.0.2", 344 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 345 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 346 | "dev": true, 347 | "engines": { 348 | "node": ">=0.3.1" 349 | } 350 | }, 351 | "node_modules/ee-first": { 352 | "version": "1.1.1", 353 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 354 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 355 | }, 356 | "node_modules/encodeurl": { 357 | "version": "1.0.2", 358 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 359 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 360 | "engines": { 361 | "node": ">= 0.8" 362 | } 363 | }, 364 | "node_modules/escape-html": { 365 | "version": "1.0.3", 366 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 367 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 368 | }, 369 | "node_modules/etag": { 370 | "version": "1.8.1", 371 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 372 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 373 | "engines": { 374 | "node": ">= 0.6" 375 | } 376 | }, 377 | "node_modules/express": { 378 | "version": "4.18.2", 379 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 380 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 381 | "dependencies": { 382 | "accepts": "~1.3.8", 383 | "array-flatten": "1.1.1", 384 | "body-parser": "1.20.1", 385 | "content-disposition": "0.5.4", 386 | "content-type": "~1.0.4", 387 | "cookie": "0.5.0", 388 | "cookie-signature": "1.0.6", 389 | "debug": "2.6.9", 390 | "depd": "2.0.0", 391 | "encodeurl": "~1.0.2", 392 | "escape-html": "~1.0.3", 393 | "etag": "~1.8.1", 394 | "finalhandler": "1.2.0", 395 | "fresh": "0.5.2", 396 | "http-errors": "2.0.0", 397 | "merge-descriptors": "1.0.1", 398 | "methods": "~1.1.2", 399 | "on-finished": "2.4.1", 400 | "parseurl": "~1.3.3", 401 | "path-to-regexp": "0.1.7", 402 | "proxy-addr": "~2.0.7", 403 | "qs": "6.11.0", 404 | "range-parser": "~1.2.1", 405 | "safe-buffer": "5.2.1", 406 | "send": "0.18.0", 407 | "serve-static": "1.15.0", 408 | "setprototypeof": "1.2.0", 409 | "statuses": "2.0.1", 410 | "type-is": "~1.6.18", 411 | "utils-merge": "1.0.1", 412 | "vary": "~1.1.2" 413 | }, 414 | "engines": { 415 | "node": ">= 0.10.0" 416 | } 417 | }, 418 | "node_modules/finalhandler": { 419 | "version": "1.2.0", 420 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 421 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 422 | "dependencies": { 423 | "debug": "2.6.9", 424 | "encodeurl": "~1.0.2", 425 | "escape-html": "~1.0.3", 426 | "on-finished": "2.4.1", 427 | "parseurl": "~1.3.3", 428 | "statuses": "2.0.1", 429 | "unpipe": "~1.0.0" 430 | }, 431 | "engines": { 432 | "node": ">= 0.8" 433 | } 434 | }, 435 | "node_modules/forwarded": { 436 | "version": "0.2.0", 437 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 438 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 439 | "engines": { 440 | "node": ">= 0.6" 441 | } 442 | }, 443 | "node_modules/fresh": { 444 | "version": "0.5.2", 445 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 446 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 447 | "engines": { 448 | "node": ">= 0.6" 449 | } 450 | }, 451 | "node_modules/function-bind": { 452 | "version": "1.1.2", 453 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 454 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", 455 | "funding": { 456 | "url": "https://github.com/sponsors/ljharb" 457 | } 458 | }, 459 | "node_modules/get-intrinsic": { 460 | "version": "1.2.2", 461 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", 462 | "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", 463 | "dependencies": { 464 | "function-bind": "^1.1.2", 465 | "has-proto": "^1.0.1", 466 | "has-symbols": "^1.0.3", 467 | "hasown": "^2.0.0" 468 | }, 469 | "funding": { 470 | "url": "https://github.com/sponsors/ljharb" 471 | } 472 | }, 473 | "node_modules/gopd": { 474 | "version": "1.0.1", 475 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 476 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 477 | "dependencies": { 478 | "get-intrinsic": "^1.1.3" 479 | }, 480 | "funding": { 481 | "url": "https://github.com/sponsors/ljharb" 482 | } 483 | }, 484 | "node_modules/has-property-descriptors": { 485 | "version": "1.0.1", 486 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", 487 | "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", 488 | "dependencies": { 489 | "get-intrinsic": "^1.2.2" 490 | }, 491 | "funding": { 492 | "url": "https://github.com/sponsors/ljharb" 493 | } 494 | }, 495 | "node_modules/has-proto": { 496 | "version": "1.0.1", 497 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", 498 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", 499 | "engines": { 500 | "node": ">= 0.4" 501 | }, 502 | "funding": { 503 | "url": "https://github.com/sponsors/ljharb" 504 | } 505 | }, 506 | "node_modules/has-symbols": { 507 | "version": "1.0.3", 508 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 509 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 510 | "engines": { 511 | "node": ">= 0.4" 512 | }, 513 | "funding": { 514 | "url": "https://github.com/sponsors/ljharb" 515 | } 516 | }, 517 | "node_modules/hasown": { 518 | "version": "2.0.0", 519 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", 520 | "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", 521 | "dependencies": { 522 | "function-bind": "^1.1.2" 523 | }, 524 | "engines": { 525 | "node": ">= 0.4" 526 | } 527 | }, 528 | "node_modules/http-errors": { 529 | "version": "2.0.0", 530 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 531 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 532 | "dependencies": { 533 | "depd": "2.0.0", 534 | "inherits": "2.0.4", 535 | "setprototypeof": "1.2.0", 536 | "statuses": "2.0.1", 537 | "toidentifier": "1.0.1" 538 | }, 539 | "engines": { 540 | "node": ">= 0.8" 541 | } 542 | }, 543 | "node_modules/iconv-lite": { 544 | "version": "0.4.24", 545 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 546 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 547 | "dependencies": { 548 | "safer-buffer": ">= 2.1.2 < 3" 549 | }, 550 | "engines": { 551 | "node": ">=0.10.0" 552 | } 553 | }, 554 | "node_modules/inherits": { 555 | "version": "2.0.4", 556 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 557 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 558 | }, 559 | "node_modules/ipaddr.js": { 560 | "version": "1.9.1", 561 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 562 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 563 | "engines": { 564 | "node": ">= 0.10" 565 | } 566 | }, 567 | "node_modules/make-error": { 568 | "version": "1.3.6", 569 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 570 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 571 | "dev": true 572 | }, 573 | "node_modules/media-typer": { 574 | "version": "0.3.0", 575 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 576 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 577 | "engines": { 578 | "node": ">= 0.6" 579 | } 580 | }, 581 | "node_modules/merge-descriptors": { 582 | "version": "1.0.1", 583 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 584 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 585 | }, 586 | "node_modules/methods": { 587 | "version": "1.1.2", 588 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 589 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 590 | "engines": { 591 | "node": ">= 0.6" 592 | } 593 | }, 594 | "node_modules/mime": { 595 | "version": "1.6.0", 596 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 597 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 598 | "bin": { 599 | "mime": "cli.js" 600 | }, 601 | "engines": { 602 | "node": ">=4" 603 | } 604 | }, 605 | "node_modules/mime-db": { 606 | "version": "1.52.0", 607 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 608 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 609 | "engines": { 610 | "node": ">= 0.6" 611 | } 612 | }, 613 | "node_modules/mime-types": { 614 | "version": "2.1.35", 615 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 616 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 617 | "dependencies": { 618 | "mime-db": "1.52.0" 619 | }, 620 | "engines": { 621 | "node": ">= 0.6" 622 | } 623 | }, 624 | "node_modules/ms": { 625 | "version": "2.0.0", 626 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 627 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 628 | }, 629 | "node_modules/negotiator": { 630 | "version": "0.6.3", 631 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 632 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 633 | "engines": { 634 | "node": ">= 0.6" 635 | } 636 | }, 637 | "node_modules/object-inspect": { 638 | "version": "1.13.1", 639 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", 640 | "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", 641 | "funding": { 642 | "url": "https://github.com/sponsors/ljharb" 643 | } 644 | }, 645 | "node_modules/on-finished": { 646 | "version": "2.4.1", 647 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 648 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 649 | "dependencies": { 650 | "ee-first": "1.1.1" 651 | }, 652 | "engines": { 653 | "node": ">= 0.8" 654 | } 655 | }, 656 | "node_modules/parseurl": { 657 | "version": "1.3.3", 658 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 659 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 660 | "engines": { 661 | "node": ">= 0.8" 662 | } 663 | }, 664 | "node_modules/path-to-regexp": { 665 | "version": "0.1.7", 666 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 667 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 668 | }, 669 | "node_modules/proxy-addr": { 670 | "version": "2.0.7", 671 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 672 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 673 | "dependencies": { 674 | "forwarded": "0.2.0", 675 | "ipaddr.js": "1.9.1" 676 | }, 677 | "engines": { 678 | "node": ">= 0.10" 679 | } 680 | }, 681 | "node_modules/qs": { 682 | "version": "6.11.0", 683 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 684 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 685 | "dependencies": { 686 | "side-channel": "^1.0.4" 687 | }, 688 | "engines": { 689 | "node": ">=0.6" 690 | }, 691 | "funding": { 692 | "url": "https://github.com/sponsors/ljharb" 693 | } 694 | }, 695 | "node_modules/range-parser": { 696 | "version": "1.2.1", 697 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 698 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 699 | "engines": { 700 | "node": ">= 0.6" 701 | } 702 | }, 703 | "node_modules/raw-body": { 704 | "version": "2.5.1", 705 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 706 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 707 | "dependencies": { 708 | "bytes": "3.1.2", 709 | "http-errors": "2.0.0", 710 | "iconv-lite": "0.4.24", 711 | "unpipe": "1.0.0" 712 | }, 713 | "engines": { 714 | "node": ">= 0.8" 715 | } 716 | }, 717 | "node_modules/safe-buffer": { 718 | "version": "5.2.1", 719 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 720 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 721 | "funding": [ 722 | { 723 | "type": "github", 724 | "url": "https://github.com/sponsors/feross" 725 | }, 726 | { 727 | "type": "patreon", 728 | "url": "https://www.patreon.com/feross" 729 | }, 730 | { 731 | "type": "consulting", 732 | "url": "https://feross.org/support" 733 | } 734 | ] 735 | }, 736 | "node_modules/safer-buffer": { 737 | "version": "2.1.2", 738 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 739 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 740 | }, 741 | "node_modules/send": { 742 | "version": "0.18.0", 743 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 744 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 745 | "dependencies": { 746 | "debug": "2.6.9", 747 | "depd": "2.0.0", 748 | "destroy": "1.2.0", 749 | "encodeurl": "~1.0.2", 750 | "escape-html": "~1.0.3", 751 | "etag": "~1.8.1", 752 | "fresh": "0.5.2", 753 | "http-errors": "2.0.0", 754 | "mime": "1.6.0", 755 | "ms": "2.1.3", 756 | "on-finished": "2.4.1", 757 | "range-parser": "~1.2.1", 758 | "statuses": "2.0.1" 759 | }, 760 | "engines": { 761 | "node": ">= 0.8.0" 762 | } 763 | }, 764 | "node_modules/send/node_modules/ms": { 765 | "version": "2.1.3", 766 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 767 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 768 | }, 769 | "node_modules/serve-static": { 770 | "version": "1.15.0", 771 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 772 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 773 | "dependencies": { 774 | "encodeurl": "~1.0.2", 775 | "escape-html": "~1.0.3", 776 | "parseurl": "~1.3.3", 777 | "send": "0.18.0" 778 | }, 779 | "engines": { 780 | "node": ">= 0.8.0" 781 | } 782 | }, 783 | "node_modules/set-function-length": { 784 | "version": "1.1.1", 785 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", 786 | "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", 787 | "dependencies": { 788 | "define-data-property": "^1.1.1", 789 | "get-intrinsic": "^1.2.1", 790 | "gopd": "^1.0.1", 791 | "has-property-descriptors": "^1.0.0" 792 | }, 793 | "engines": { 794 | "node": ">= 0.4" 795 | } 796 | }, 797 | "node_modules/setprototypeof": { 798 | "version": "1.2.0", 799 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 800 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 801 | }, 802 | "node_modules/side-channel": { 803 | "version": "1.0.4", 804 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 805 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 806 | "dependencies": { 807 | "call-bind": "^1.0.0", 808 | "get-intrinsic": "^1.0.2", 809 | "object-inspect": "^1.9.0" 810 | }, 811 | "funding": { 812 | "url": "https://github.com/sponsors/ljharb" 813 | } 814 | }, 815 | "node_modules/statuses": { 816 | "version": "2.0.1", 817 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 818 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 819 | "engines": { 820 | "node": ">= 0.8" 821 | } 822 | }, 823 | "node_modules/toidentifier": { 824 | "version": "1.0.1", 825 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 826 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 827 | "engines": { 828 | "node": ">=0.6" 829 | } 830 | }, 831 | "node_modules/ts-node": { 832 | "version": "10.9.2", 833 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", 834 | "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", 835 | "dev": true, 836 | "dependencies": { 837 | "@cspotcode/source-map-support": "^0.8.0", 838 | "@tsconfig/node10": "^1.0.7", 839 | "@tsconfig/node12": "^1.0.7", 840 | "@tsconfig/node14": "^1.0.0", 841 | "@tsconfig/node16": "^1.0.2", 842 | "acorn": "^8.4.1", 843 | "acorn-walk": "^8.1.1", 844 | "arg": "^4.1.0", 845 | "create-require": "^1.1.0", 846 | "diff": "^4.0.1", 847 | "make-error": "^1.1.1", 848 | "v8-compile-cache-lib": "^3.0.1", 849 | "yn": "3.1.1" 850 | }, 851 | "bin": { 852 | "ts-node": "dist/bin.js", 853 | "ts-node-cwd": "dist/bin-cwd.js", 854 | "ts-node-esm": "dist/bin-esm.js", 855 | "ts-node-script": "dist/bin-script.js", 856 | "ts-node-transpile-only": "dist/bin-transpile.js", 857 | "ts-script": "dist/bin-script-deprecated.js" 858 | }, 859 | "peerDependencies": { 860 | "@swc/core": ">=1.2.50", 861 | "@swc/wasm": ">=1.2.50", 862 | "@types/node": "*", 863 | "typescript": ">=2.7" 864 | }, 865 | "peerDependenciesMeta": { 866 | "@swc/core": { 867 | "optional": true 868 | }, 869 | "@swc/wasm": { 870 | "optional": true 871 | } 872 | } 873 | }, 874 | "node_modules/type-is": { 875 | "version": "1.6.18", 876 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 877 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 878 | "dependencies": { 879 | "media-typer": "0.3.0", 880 | "mime-types": "~2.1.24" 881 | }, 882 | "engines": { 883 | "node": ">= 0.6" 884 | } 885 | }, 886 | "node_modules/typescript": { 887 | "version": "5.3.3", 888 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", 889 | "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", 890 | "dev": true, 891 | "bin": { 892 | "tsc": "bin/tsc", 893 | "tsserver": "bin/tsserver" 894 | }, 895 | "engines": { 896 | "node": ">=14.17" 897 | } 898 | }, 899 | "node_modules/undici-types": { 900 | "version": "5.26.5", 901 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 902 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 903 | "dev": true 904 | }, 905 | "node_modules/unpipe": { 906 | "version": "1.0.0", 907 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 908 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 909 | "engines": { 910 | "node": ">= 0.8" 911 | } 912 | }, 913 | "node_modules/utils-merge": { 914 | "version": "1.0.1", 915 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 916 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 917 | "engines": { 918 | "node": ">= 0.4.0" 919 | } 920 | }, 921 | "node_modules/v8-compile-cache-lib": { 922 | "version": "3.0.1", 923 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 924 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 925 | "dev": true 926 | }, 927 | "node_modules/vary": { 928 | "version": "1.1.2", 929 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 930 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 931 | "engines": { 932 | "node": ">= 0.8" 933 | } 934 | }, 935 | "node_modules/yn": { 936 | "version": "3.1.1", 937 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 938 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 939 | "dev": true, 940 | "engines": { 941 | "node": ">=6" 942 | } 943 | } 944 | }, 945 | "dependencies": { 946 | "@cspotcode/source-map-support": { 947 | "version": "0.8.1", 948 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 949 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 950 | "dev": true, 951 | "requires": { 952 | "@jridgewell/trace-mapping": "0.3.9" 953 | } 954 | }, 955 | "@jridgewell/resolve-uri": { 956 | "version": "3.1.1", 957 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 958 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 959 | "dev": true 960 | }, 961 | "@jridgewell/sourcemap-codec": { 962 | "version": "1.4.15", 963 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 964 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 965 | "dev": true 966 | }, 967 | "@jridgewell/trace-mapping": { 968 | "version": "0.3.9", 969 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 970 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 971 | "dev": true, 972 | "requires": { 973 | "@jridgewell/resolve-uri": "^3.0.3", 974 | "@jridgewell/sourcemap-codec": "^1.4.10" 975 | } 976 | }, 977 | "@tsconfig/node10": { 978 | "version": "1.0.9", 979 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 980 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", 981 | "dev": true 982 | }, 983 | "@tsconfig/node12": { 984 | "version": "1.0.11", 985 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 986 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", 987 | "dev": true 988 | }, 989 | "@tsconfig/node14": { 990 | "version": "1.0.3", 991 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 992 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", 993 | "dev": true 994 | }, 995 | "@tsconfig/node16": { 996 | "version": "1.0.4", 997 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", 998 | "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", 999 | "dev": true 1000 | }, 1001 | "@types/body-parser": { 1002 | "version": "1.19.5", 1003 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", 1004 | "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", 1005 | "dev": true, 1006 | "requires": { 1007 | "@types/connect": "*", 1008 | "@types/node": "*" 1009 | } 1010 | }, 1011 | "@types/connect": { 1012 | "version": "3.4.38", 1013 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", 1014 | "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", 1015 | "dev": true, 1016 | "requires": { 1017 | "@types/node": "*" 1018 | } 1019 | }, 1020 | "@types/express": { 1021 | "version": "4.17.21", 1022 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", 1023 | "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", 1024 | "dev": true, 1025 | "requires": { 1026 | "@types/body-parser": "*", 1027 | "@types/express-serve-static-core": "^4.17.33", 1028 | "@types/qs": "*", 1029 | "@types/serve-static": "*" 1030 | } 1031 | }, 1032 | "@types/express-serve-static-core": { 1033 | "version": "4.17.41", 1034 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz", 1035 | "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==", 1036 | "dev": true, 1037 | "requires": { 1038 | "@types/node": "*", 1039 | "@types/qs": "*", 1040 | "@types/range-parser": "*", 1041 | "@types/send": "*" 1042 | } 1043 | }, 1044 | "@types/http-errors": { 1045 | "version": "2.0.4", 1046 | "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", 1047 | "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", 1048 | "dev": true 1049 | }, 1050 | "@types/mime": { 1051 | "version": "1.3.5", 1052 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", 1053 | "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", 1054 | "dev": true 1055 | }, 1056 | "@types/node": { 1057 | "version": "20.10.5", 1058 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", 1059 | "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", 1060 | "dev": true, 1061 | "requires": { 1062 | "undici-types": "~5.26.4" 1063 | } 1064 | }, 1065 | "@types/qs": { 1066 | "version": "6.9.11", 1067 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", 1068 | "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", 1069 | "dev": true 1070 | }, 1071 | "@types/range-parser": { 1072 | "version": "1.2.7", 1073 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", 1074 | "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", 1075 | "dev": true 1076 | }, 1077 | "@types/send": { 1078 | "version": "0.17.4", 1079 | "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", 1080 | "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", 1081 | "dev": true, 1082 | "requires": { 1083 | "@types/mime": "^1", 1084 | "@types/node": "*" 1085 | } 1086 | }, 1087 | "@types/serve-static": { 1088 | "version": "1.15.5", 1089 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", 1090 | "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", 1091 | "dev": true, 1092 | "requires": { 1093 | "@types/http-errors": "*", 1094 | "@types/mime": "*", 1095 | "@types/node": "*" 1096 | } 1097 | }, 1098 | "accepts": { 1099 | "version": "1.3.8", 1100 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 1101 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 1102 | "requires": { 1103 | "mime-types": "~2.1.34", 1104 | "negotiator": "0.6.3" 1105 | } 1106 | }, 1107 | "acorn": { 1108 | "version": "8.11.2", 1109 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", 1110 | "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", 1111 | "dev": true 1112 | }, 1113 | "acorn-walk": { 1114 | "version": "8.3.1", 1115 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", 1116 | "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", 1117 | "dev": true 1118 | }, 1119 | "arg": { 1120 | "version": "4.1.3", 1121 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 1122 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", 1123 | "dev": true 1124 | }, 1125 | "array-flatten": { 1126 | "version": "1.1.1", 1127 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 1128 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 1129 | }, 1130 | "body-parser": { 1131 | "version": "1.20.1", 1132 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 1133 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 1134 | "requires": { 1135 | "bytes": "3.1.2", 1136 | "content-type": "~1.0.4", 1137 | "debug": "2.6.9", 1138 | "depd": "2.0.0", 1139 | "destroy": "1.2.0", 1140 | "http-errors": "2.0.0", 1141 | "iconv-lite": "0.4.24", 1142 | "on-finished": "2.4.1", 1143 | "qs": "6.11.0", 1144 | "raw-body": "2.5.1", 1145 | "type-is": "~1.6.18", 1146 | "unpipe": "1.0.0" 1147 | } 1148 | }, 1149 | "bytes": { 1150 | "version": "3.1.2", 1151 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 1152 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 1153 | }, 1154 | "call-bind": { 1155 | "version": "1.0.5", 1156 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", 1157 | "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", 1158 | "requires": { 1159 | "function-bind": "^1.1.2", 1160 | "get-intrinsic": "^1.2.1", 1161 | "set-function-length": "^1.1.1" 1162 | } 1163 | }, 1164 | "content-disposition": { 1165 | "version": "0.5.4", 1166 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 1167 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 1168 | "requires": { 1169 | "safe-buffer": "5.2.1" 1170 | } 1171 | }, 1172 | "content-type": { 1173 | "version": "1.0.5", 1174 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", 1175 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" 1176 | }, 1177 | "cookie": { 1178 | "version": "0.5.0", 1179 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 1180 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" 1181 | }, 1182 | "cookie-signature": { 1183 | "version": "1.0.6", 1184 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 1185 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 1186 | }, 1187 | "create-require": { 1188 | "version": "1.1.1", 1189 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 1190 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", 1191 | "dev": true 1192 | }, 1193 | "debug": { 1194 | "version": "2.6.9", 1195 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1196 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1197 | "requires": { 1198 | "ms": "2.0.0" 1199 | } 1200 | }, 1201 | "define-data-property": { 1202 | "version": "1.1.1", 1203 | "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", 1204 | "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", 1205 | "requires": { 1206 | "get-intrinsic": "^1.2.1", 1207 | "gopd": "^1.0.1", 1208 | "has-property-descriptors": "^1.0.0" 1209 | } 1210 | }, 1211 | "depd": { 1212 | "version": "2.0.0", 1213 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 1214 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 1215 | }, 1216 | "destroy": { 1217 | "version": "1.2.0", 1218 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 1219 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" 1220 | }, 1221 | "diff": { 1222 | "version": "4.0.2", 1223 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 1224 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 1225 | "dev": true 1226 | }, 1227 | "ee-first": { 1228 | "version": "1.1.1", 1229 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 1230 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 1231 | }, 1232 | "encodeurl": { 1233 | "version": "1.0.2", 1234 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 1235 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 1236 | }, 1237 | "escape-html": { 1238 | "version": "1.0.3", 1239 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 1240 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 1241 | }, 1242 | "etag": { 1243 | "version": "1.8.1", 1244 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 1245 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 1246 | }, 1247 | "express": { 1248 | "version": "4.18.2", 1249 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 1250 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 1251 | "requires": { 1252 | "accepts": "~1.3.8", 1253 | "array-flatten": "1.1.1", 1254 | "body-parser": "1.20.1", 1255 | "content-disposition": "0.5.4", 1256 | "content-type": "~1.0.4", 1257 | "cookie": "0.5.0", 1258 | "cookie-signature": "1.0.6", 1259 | "debug": "2.6.9", 1260 | "depd": "2.0.0", 1261 | "encodeurl": "~1.0.2", 1262 | "escape-html": "~1.0.3", 1263 | "etag": "~1.8.1", 1264 | "finalhandler": "1.2.0", 1265 | "fresh": "0.5.2", 1266 | "http-errors": "2.0.0", 1267 | "merge-descriptors": "1.0.1", 1268 | "methods": "~1.1.2", 1269 | "on-finished": "2.4.1", 1270 | "parseurl": "~1.3.3", 1271 | "path-to-regexp": "0.1.7", 1272 | "proxy-addr": "~2.0.7", 1273 | "qs": "6.11.0", 1274 | "range-parser": "~1.2.1", 1275 | "safe-buffer": "5.2.1", 1276 | "send": "0.18.0", 1277 | "serve-static": "1.15.0", 1278 | "setprototypeof": "1.2.0", 1279 | "statuses": "2.0.1", 1280 | "type-is": "~1.6.18", 1281 | "utils-merge": "1.0.1", 1282 | "vary": "~1.1.2" 1283 | } 1284 | }, 1285 | "finalhandler": { 1286 | "version": "1.2.0", 1287 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 1288 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 1289 | "requires": { 1290 | "debug": "2.6.9", 1291 | "encodeurl": "~1.0.2", 1292 | "escape-html": "~1.0.3", 1293 | "on-finished": "2.4.1", 1294 | "parseurl": "~1.3.3", 1295 | "statuses": "2.0.1", 1296 | "unpipe": "~1.0.0" 1297 | } 1298 | }, 1299 | "forwarded": { 1300 | "version": "0.2.0", 1301 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 1302 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 1303 | }, 1304 | "fresh": { 1305 | "version": "0.5.2", 1306 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 1307 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 1308 | }, 1309 | "function-bind": { 1310 | "version": "1.1.2", 1311 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", 1312 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" 1313 | }, 1314 | "get-intrinsic": { 1315 | "version": "1.2.2", 1316 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", 1317 | "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", 1318 | "requires": { 1319 | "function-bind": "^1.1.2", 1320 | "has-proto": "^1.0.1", 1321 | "has-symbols": "^1.0.3", 1322 | "hasown": "^2.0.0" 1323 | } 1324 | }, 1325 | "gopd": { 1326 | "version": "1.0.1", 1327 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", 1328 | "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", 1329 | "requires": { 1330 | "get-intrinsic": "^1.1.3" 1331 | } 1332 | }, 1333 | "has-property-descriptors": { 1334 | "version": "1.0.1", 1335 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", 1336 | "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", 1337 | "requires": { 1338 | "get-intrinsic": "^1.2.2" 1339 | } 1340 | }, 1341 | "has-proto": { 1342 | "version": "1.0.1", 1343 | "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", 1344 | "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" 1345 | }, 1346 | "has-symbols": { 1347 | "version": "1.0.3", 1348 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1349 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 1350 | }, 1351 | "hasown": { 1352 | "version": "2.0.0", 1353 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", 1354 | "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", 1355 | "requires": { 1356 | "function-bind": "^1.1.2" 1357 | } 1358 | }, 1359 | "http-errors": { 1360 | "version": "2.0.0", 1361 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 1362 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 1363 | "requires": { 1364 | "depd": "2.0.0", 1365 | "inherits": "2.0.4", 1366 | "setprototypeof": "1.2.0", 1367 | "statuses": "2.0.1", 1368 | "toidentifier": "1.0.1" 1369 | } 1370 | }, 1371 | "iconv-lite": { 1372 | "version": "0.4.24", 1373 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1374 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1375 | "requires": { 1376 | "safer-buffer": ">= 2.1.2 < 3" 1377 | } 1378 | }, 1379 | "inherits": { 1380 | "version": "2.0.4", 1381 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1382 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1383 | }, 1384 | "ipaddr.js": { 1385 | "version": "1.9.1", 1386 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1387 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 1388 | }, 1389 | "make-error": { 1390 | "version": "1.3.6", 1391 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 1392 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", 1393 | "dev": true 1394 | }, 1395 | "media-typer": { 1396 | "version": "0.3.0", 1397 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1398 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 1399 | }, 1400 | "merge-descriptors": { 1401 | "version": "1.0.1", 1402 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1403 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 1404 | }, 1405 | "methods": { 1406 | "version": "1.1.2", 1407 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1408 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 1409 | }, 1410 | "mime": { 1411 | "version": "1.6.0", 1412 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1413 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 1414 | }, 1415 | "mime-db": { 1416 | "version": "1.52.0", 1417 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1418 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 1419 | }, 1420 | "mime-types": { 1421 | "version": "2.1.35", 1422 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1423 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1424 | "requires": { 1425 | "mime-db": "1.52.0" 1426 | } 1427 | }, 1428 | "ms": { 1429 | "version": "2.0.0", 1430 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1431 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 1432 | }, 1433 | "negotiator": { 1434 | "version": "0.6.3", 1435 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 1436 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 1437 | }, 1438 | "object-inspect": { 1439 | "version": "1.13.1", 1440 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", 1441 | "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" 1442 | }, 1443 | "on-finished": { 1444 | "version": "2.4.1", 1445 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 1446 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 1447 | "requires": { 1448 | "ee-first": "1.1.1" 1449 | } 1450 | }, 1451 | "parseurl": { 1452 | "version": "1.3.3", 1453 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1454 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 1455 | }, 1456 | "path-to-regexp": { 1457 | "version": "0.1.7", 1458 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1459 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 1460 | }, 1461 | "proxy-addr": { 1462 | "version": "2.0.7", 1463 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 1464 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 1465 | "requires": { 1466 | "forwarded": "0.2.0", 1467 | "ipaddr.js": "1.9.1" 1468 | } 1469 | }, 1470 | "qs": { 1471 | "version": "6.11.0", 1472 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 1473 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 1474 | "requires": { 1475 | "side-channel": "^1.0.4" 1476 | } 1477 | }, 1478 | "range-parser": { 1479 | "version": "1.2.1", 1480 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1481 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 1482 | }, 1483 | "raw-body": { 1484 | "version": "2.5.1", 1485 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 1486 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 1487 | "requires": { 1488 | "bytes": "3.1.2", 1489 | "http-errors": "2.0.0", 1490 | "iconv-lite": "0.4.24", 1491 | "unpipe": "1.0.0" 1492 | } 1493 | }, 1494 | "safe-buffer": { 1495 | "version": "5.2.1", 1496 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1497 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 1498 | }, 1499 | "safer-buffer": { 1500 | "version": "2.1.2", 1501 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1502 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1503 | }, 1504 | "send": { 1505 | "version": "0.18.0", 1506 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 1507 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 1508 | "requires": { 1509 | "debug": "2.6.9", 1510 | "depd": "2.0.0", 1511 | "destroy": "1.2.0", 1512 | "encodeurl": "~1.0.2", 1513 | "escape-html": "~1.0.3", 1514 | "etag": "~1.8.1", 1515 | "fresh": "0.5.2", 1516 | "http-errors": "2.0.0", 1517 | "mime": "1.6.0", 1518 | "ms": "2.1.3", 1519 | "on-finished": "2.4.1", 1520 | "range-parser": "~1.2.1", 1521 | "statuses": "2.0.1" 1522 | }, 1523 | "dependencies": { 1524 | "ms": { 1525 | "version": "2.1.3", 1526 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1527 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1528 | } 1529 | } 1530 | }, 1531 | "serve-static": { 1532 | "version": "1.15.0", 1533 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 1534 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 1535 | "requires": { 1536 | "encodeurl": "~1.0.2", 1537 | "escape-html": "~1.0.3", 1538 | "parseurl": "~1.3.3", 1539 | "send": "0.18.0" 1540 | } 1541 | }, 1542 | "set-function-length": { 1543 | "version": "1.1.1", 1544 | "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", 1545 | "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", 1546 | "requires": { 1547 | "define-data-property": "^1.1.1", 1548 | "get-intrinsic": "^1.2.1", 1549 | "gopd": "^1.0.1", 1550 | "has-property-descriptors": "^1.0.0" 1551 | } 1552 | }, 1553 | "setprototypeof": { 1554 | "version": "1.2.0", 1555 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1556 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 1557 | }, 1558 | "side-channel": { 1559 | "version": "1.0.4", 1560 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 1561 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 1562 | "requires": { 1563 | "call-bind": "^1.0.0", 1564 | "get-intrinsic": "^1.0.2", 1565 | "object-inspect": "^1.9.0" 1566 | } 1567 | }, 1568 | "statuses": { 1569 | "version": "2.0.1", 1570 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1571 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" 1572 | }, 1573 | "toidentifier": { 1574 | "version": "1.0.1", 1575 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1576 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 1577 | }, 1578 | "ts-node": { 1579 | "version": "10.9.2", 1580 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", 1581 | "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", 1582 | "dev": true, 1583 | "requires": { 1584 | "@cspotcode/source-map-support": "^0.8.0", 1585 | "@tsconfig/node10": "^1.0.7", 1586 | "@tsconfig/node12": "^1.0.7", 1587 | "@tsconfig/node14": "^1.0.0", 1588 | "@tsconfig/node16": "^1.0.2", 1589 | "acorn": "^8.4.1", 1590 | "acorn-walk": "^8.1.1", 1591 | "arg": "^4.1.0", 1592 | "create-require": "^1.1.0", 1593 | "diff": "^4.0.1", 1594 | "make-error": "^1.1.1", 1595 | "v8-compile-cache-lib": "^3.0.1", 1596 | "yn": "3.1.1" 1597 | } 1598 | }, 1599 | "type-is": { 1600 | "version": "1.6.18", 1601 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1602 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1603 | "requires": { 1604 | "media-typer": "0.3.0", 1605 | "mime-types": "~2.1.24" 1606 | } 1607 | }, 1608 | "typescript": { 1609 | "version": "5.3.3", 1610 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", 1611 | "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", 1612 | "dev": true 1613 | }, 1614 | "undici-types": { 1615 | "version": "5.26.5", 1616 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 1617 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 1618 | "dev": true 1619 | }, 1620 | "unpipe": { 1621 | "version": "1.0.0", 1622 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1623 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 1624 | }, 1625 | "utils-merge": { 1626 | "version": "1.0.1", 1627 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1628 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 1629 | }, 1630 | "v8-compile-cache-lib": { 1631 | "version": "3.0.1", 1632 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 1633 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", 1634 | "dev": true 1635 | }, 1636 | "vary": { 1637 | "version": "1.1.2", 1638 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1639 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 1640 | }, 1641 | "yn": { 1642 | "version": "3.1.1", 1643 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 1644 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 1645 | "dev": true 1646 | } 1647 | } 1648 | } 1649 | -------------------------------------------------------------------------------- /examples/express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.18.2" 14 | }, 15 | "devDependencies": { 16 | "@types/express": "^4.17.21", 17 | "ts-node": "^10.9.2", 18 | "typescript": "^5.3.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | transform: { 3 | "^.+\\.tsx?$": "ts-jest", 4 | }, 5 | testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.(js?|ts?)$", 6 | testPathIgnorePatterns: ["/node_modules/"], 7 | moduleFileExtensions: ["ts", "js", "json"], 8 | }; 9 | -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "source": { 3 | "include": ["src"], 4 | "includePattern": "\\.(jsx|js|ts|tsx)$", 5 | "excludePattern": "(^|\\/|\\\\)_" 6 | }, 7 | "plugins": ["node_modules/better-docs/typescript"], 8 | "typescript": { 9 | "moduleRoot": "test" 10 | }, 11 | "templates": { 12 | "better-docs": { 13 | "name": "My React components" 14 | } 15 | }, 16 | "opts": { 17 | "template": "./node_modules/clean-jsdoc-theme", 18 | "destination": "docs", 19 | "recurse": true, 20 | "readme": "README.md" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easypay.js", 3 | "version": "1.0.6", 4 | "description": "a payment service library for handling different Iranian payment gateways", 5 | "main": "./dist/index.js", 6 | "types": "./dist/index.d.ts", 7 | "files": [ 8 | "/dist", 9 | "package.json", 10 | "README.md" 11 | ], 12 | "scripts": { 13 | "lint": "eslint . --ext .ts", 14 | "test:unit": "jest", 15 | "build:ts": "tsc", 16 | "build": "tsup && npm run doc", 17 | "doc": "jsdoc -c jsdoc.json", 18 | "format": "prettier --write \"./src/**/*.ts\"" 19 | }, 20 | "author": "sajjadmrx", 21 | "license": "ISC", 22 | "devDependencies": { 23 | "@types/jest": "^29.5.6", 24 | "@typescript-eslint/eslint-plugin": "^6.0.0", 25 | "@typescript-eslint/parser": "^6.0.0", 26 | "better-docs": "^2.7.3", 27 | "clean-jsdoc-theme": "^4.2.17", 28 | "eslint": "^8.42.0", 29 | "eslint-config-prettier": "^9.1.0", 30 | "eslint-plugin-prettier": "^5.1.3", 31 | "jest": "^29.7.0", 32 | "jsdoc": "^4.0.2", 33 | "jsdoc-plugin-typescript": "^2.2.1", 34 | "prettier": "^3.0.0", 35 | "ts-jest": "^29.1.1", 36 | "ts-node": "^10.9.1", 37 | "tsup": "^7.2.0", 38 | "typescript": "^5.2.2" 39 | }, 40 | "repository": { 41 | "type": "git", 42 | "url": "https://github.com/sajjadmrx/easypay.js" 43 | }, 44 | "homepage": "https://sajjadmrx.github.io/easypay-js/", 45 | "dependencies": { 46 | "axios": "^1.7.2", 47 | "prettier": "^3.0.3" 48 | }, 49 | "keywords": [ 50 | "payment", 51 | "payment gateway", 52 | "Iranian payments", 53 | "payment processing" 54 | ] 55 | } -------------------------------------------------------------------------------- /src/drivers/idpay/__tests__/idPayDriver.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | TransactionCreateInputIdPay, 3 | TransactionVerifyInputIdPay, 4 | TransactionCreateResponseIdPay, 5 | TransactionVerifyResponseIdPay 6 | } from '../' 7 | import axios from 'axios' 8 | import { IdPayDriver } from '../idpay' 9 | 10 | jest.mock('axios') 11 | 12 | describe('IdPayDriver', () => { 13 | const createTransactionMockData: TransactionCreateInputIdPay = { 14 | token: 'your_token', 15 | order_id: '12345', 16 | amount: 10000, 17 | name: 'John Doe', 18 | phone: '09381234567', 19 | mail: 'john.doe@example.com', 20 | desc: 'Payment for a product', 21 | callback: 'https://example.com/callback' 22 | } 23 | 24 | const verifyTransactionMockData: TransactionVerifyInputIdPay = { 25 | token: 'your_token', 26 | order_id: '12345', 27 | id: '987654' 28 | } 29 | 30 | const mockData = { 31 | id: '123456', 32 | link: 'https://example.com/payment-link', 33 | error_code: 'ERR001', 34 | error_message: 'Error message' 35 | } 36 | 37 | const mockAxiosPost = jest.fn() 38 | 39 | afterEach(() => { 40 | jest.clearAllMocks() 41 | }) 42 | 43 | test('request method - success', async () => { 44 | mockAxiosPost.mockResolvedValue({ data: mockData }) 45 | axios.post = mockAxiosPost 46 | 47 | const idPayDriver = new IdPayDriver() 48 | const result = await idPayDriver.request(createTransactionMockData) 49 | 50 | const expectedResponse: TransactionCreateResponseIdPay = { 51 | isError: false, 52 | data: { 53 | id: mockData.id, 54 | link: mockData.link 55 | }, 56 | error_code: null, 57 | error_message: null 58 | } 59 | 60 | expect(result).toEqual(expectedResponse) 61 | 62 | expect(mockAxiosPost).toHaveBeenCalledWith( 63 | expect.any(String), 64 | expect.objectContaining(createTransactionMockData), 65 | expect.any(Object) 66 | ) 67 | }) 68 | 69 | test('request method - error', async () => { 70 | mockAxiosPost.mockRejectedValue({ 71 | isAxiosError: true, 72 | response: { 73 | data: { 74 | error_code: mockData.error_code, 75 | error_message: mockData.error_message 76 | } 77 | } 78 | }) 79 | axios.post = mockAxiosPost 80 | 81 | const idPayDriver = new IdPayDriver() 82 | const result = await idPayDriver.request(createTransactionMockData) 83 | 84 | const expectedResponse: TransactionCreateResponseIdPay = { 85 | isError: true, 86 | error_code: mockData.error_code, 87 | error_message: mockData.error_message, 88 | data: {} as any 89 | } 90 | 91 | expect(result).toEqual(expectedResponse) 92 | }) 93 | 94 | test('verify method - success', async () => { 95 | const mockVerifyData = { 96 | status: 'Success', 97 | track_id: '123456789', 98 | id: '987654321', 99 | order_id: 'ORDER12345', 100 | amount: '100.00', 101 | date: '2023-10-29T14:30:00Z', 102 | payment: { 103 | track_id: '987654321', 104 | amount: '100.00', 105 | card_no: '**** **** **** 1234', 106 | hashed_card_no: '4b0b192d675b8632c19f989315c78e91', 107 | date: '2023-10-29T14:30:00Z' 108 | }, 109 | verify: { 110 | date: '2023-10-29T14:35:00Z' 111 | } 112 | } 113 | 114 | mockAxiosPost.mockResolvedValue({ data: mockVerifyData }) 115 | axios.post = mockAxiosPost 116 | 117 | const idPayDriver = new IdPayDriver() 118 | const result = await idPayDriver.verify(verifyTransactionMockData) 119 | 120 | const expectedResponse: TransactionVerifyResponseIdPay = { 121 | isError: false, 122 | data: { 123 | status: mockVerifyData.status, 124 | track_id: mockVerifyData.track_id, 125 | id: mockVerifyData.id, 126 | order_id: mockVerifyData.order_id, 127 | amount: mockVerifyData.amount, 128 | date: mockVerifyData.date, 129 | payment: { 130 | track_id: mockVerifyData.payment.track_id, 131 | amount: mockVerifyData.payment.amount, 132 | card_no: mockVerifyData.payment.card_no, 133 | hashed_card_no: mockVerifyData.payment.hashed_card_no, 134 | date: mockVerifyData.payment.date 135 | }, 136 | verify: { 137 | date: mockVerifyData.verify.date 138 | } 139 | }, 140 | error_code: null, 141 | error_message: null 142 | } 143 | 144 | expect(result).toEqual(expectedResponse) 145 | 146 | expect(mockAxiosPost).toHaveBeenCalledWith( 147 | expect.any(String), 148 | expect.objectContaining(verifyTransactionMockData), 149 | expect.any(Object) 150 | ) 151 | }) 152 | 153 | test('verify method - error', async () => { 154 | mockAxiosPost.mockRejectedValue({ 155 | isAxiosError: true, 156 | response: { 157 | data: { 158 | error_code: mockData.error_code, 159 | error_message: mockData.error_message 160 | } 161 | } 162 | }) 163 | axios.post = mockAxiosPost 164 | 165 | const idPayDriver = new IdPayDriver() 166 | const result = await idPayDriver.verify(verifyTransactionMockData) 167 | 168 | const expectedResponse: TransactionVerifyResponseIdPay = { 169 | isError: true, 170 | error_code: mockData.error_code, 171 | error_message: mockData.error_message, 172 | data: {} as any 173 | } 174 | 175 | expect(result).toEqual(expectedResponse) 176 | }) 177 | }) 178 | -------------------------------------------------------------------------------- /src/drivers/idpay/enums/urls.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Enum representing URLs for interacting with the IdPay API. 3 | * 4 | * @enum {string} 5 | */ 6 | export enum IdPayUrls { 7 | /** 8 | * URL for creating a payment request. 9 | * 10 | * @type {string} 11 | * @memberof IdPayUrls 12 | */ 13 | REQUEST = 'https://api.idpay.ir/v1.1/payment', 14 | /** 15 | * URL for verifying a payment. 16 | * 17 | * @type {string} 18 | * @memberof IdPayUrls 19 | */ 20 | VERIFY = 'https://api.idpay.ir/v1.1/payment/verify' 21 | } 22 | -------------------------------------------------------------------------------- /src/drivers/idpay/idpay.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { IdPayUrls } from './enums/urls.enum' 3 | import { TransactionCreateInputIdPay, TransactionVerifyInputIdPay } from './interfaces/request.interface' 4 | import { TransactionCreateResponseIdPay, TransactionVerifyResponseIdPay } from './interfaces/response.interface' 5 | 6 | /** 7 | * Class that provides methods to interact with the IdPay API. 8 | * 9 | * @class IdPayDriver 10 | */ 11 | export class IdPayDriver { 12 | private token: string | null = null 13 | private sandBox: boolean = false 14 | 15 | /** 16 | * Set the API token for authentication. 17 | * 18 | * @param {string} token - The API token. 19 | * @returns {this} Instance of IdPayDriver. 20 | */ 21 | setToken(token: string): this { 22 | this.token = token 23 | return this 24 | } 25 | 26 | /** 27 | * Set whether to use the sandbox environment or not. 28 | * 29 | * @param {boolean} sandBox - True to use sandbox, false otherwise. 30 | * @returns {this} Instance of IdPayDriver. 31 | */ 32 | setSandBox(sandBox: boolean): this { 33 | this.sandBox = sandBox 34 | return this 35 | } 36 | 37 | /** 38 | * Request method to create a transaction. 39 | * 40 | * @param {TransactionCreateInputIdPay} dataInput - Input data for creating the transaction. 41 | * @returns {Promise} Response from the IdPay API for creating a transaction. 42 | */ 43 | async request(dataInput: TransactionCreateInputIdPay): Promise { 44 | try { 45 | const { data } = await axios.post(IdPayUrls.REQUEST, dataInput, { 46 | headers: this.getHeader(this.token || dataInput.token, this.sandBox) 47 | }) 48 | return { 49 | isError: false, 50 | data: { 51 | id: data.id, 52 | link: data.link 53 | }, 54 | error_code: null, 55 | error_message: null 56 | } 57 | } catch (error: any) { 58 | if (error.isAxiosError) { 59 | return { 60 | isError: true, 61 | error_message: error.response.data.error_message, 62 | error_code: error.response.data.error_code, 63 | data: {} as any 64 | } 65 | } else throw error 66 | } 67 | } 68 | 69 | /** 70 | * Verify method to verify a transaction. 71 | * 72 | * @param {TransactionVerifyInputIdPay} dataInput - Input data for verifying the transaction. 73 | * @returns {Promise} Response from the IdPay API for verifying a transaction. 74 | */ 75 | async verify(dataInput: TransactionVerifyInputIdPay): Promise { 76 | try { 77 | const { data } = await axios.post(IdPayUrls.VERIFY, dataInput, { 78 | headers: this.getHeader(this.token || dataInput.token, this.sandBox) 79 | }) 80 | return { 81 | isError: false, 82 | error_message: null, 83 | error_code: null, 84 | data: data 85 | } 86 | } catch (error: any) { 87 | if (error.isAxiosError) { 88 | return { 89 | isError: true, 90 | error_message: error.response.data.error_message, 91 | error_code: error.response.data.error_code, 92 | data: {} as any 93 | } 94 | } else throw error 95 | } 96 | } 97 | 98 | /** 99 | * Generate headers for the HTTP requests. 100 | * 101 | * @private 102 | * @param {string | undefined} token - API token. 103 | * @param {boolean} sandbox - Whether sandbox environment should be used. 104 | * @returns {Record} Headers for the HTTP request. 105 | * @throws {Error} Throws an error if token is not provided. 106 | */ 107 | private getHeader(token: string | undefined, sandbox: boolean) { 108 | if (!token) throw new Error('token is required') 109 | return { 110 | 'Content-Type': 'application/json', 111 | 'X-API-KEY': token, 112 | 'X-SANDBOX': sandbox 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/drivers/idpay/index.ts: -------------------------------------------------------------------------------- 1 | export { IdPayDriver } from './idpay' 2 | export * from './interfaces/response.interface' 3 | 4 | export * from './interfaces/request.interface' 5 | -------------------------------------------------------------------------------- /src/drivers/idpay/interfaces/request.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents the input structure for creating a transaction with IdPay. 3 | * 4 | * @interface TransactionCreateInputIdPay 5 | * @property {string} token The token for authentication, if available. 6 | * @property {string} order_id Merchant order ID. 7 | * @property {number} amount Desired amount in Rials. 8 | * @property {string} name Name of the payer (optional). 9 | * @property {string} phone Mobile number of the payer (optional). 10 | * @property {string} mail Email address of the payer (optional). 11 | * @property {string} desc Transaction description. 12 | * @property {string} callback Merchant's callback URL. 13 | * @link https://idpay.ir/web-service/v1.1/#8614460e98 14 | */ 15 | export interface TransactionCreateInputIdPay { 16 | token?: string 17 | 18 | order_id: string 19 | 20 | amount: number 21 | 22 | name?: string 23 | 24 | phone?: string 25 | 26 | mail?: string 27 | 28 | desc: string 29 | 30 | callback: string 31 | } 32 | 33 | /** 34 | * Represents the input structure for verifying a transaction with IdPay. 35 | * Inherits properties 'order_id' and 'token' from TransactionCreateInputIdPay. 36 | * 37 | * @interface TransactionVerifyInputIdPay 38 | * @extends {Pick} 39 | * @property {string} id Transaction ID. 40 | * @link https://idpay.ir/web-service/v1.1/#8614460e98 41 | */ 42 | export interface TransactionVerifyInputIdPay extends Pick { 43 | id: string 44 | } 45 | -------------------------------------------------------------------------------- /src/drivers/idpay/interfaces/response.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents the response structure for creating a transaction with IdPay. 3 | * 4 | * @interface TransactionCreateResponseIdPay 5 | * @property {boolean} isError Indicates if there's an error in the response. 6 | * @property {object} data Data related to the transaction if successful. 7 | * @property {string} data.id Transaction ID. 8 | * @property {string} data.link URL to redirect the user to. 9 | * @property {string | null} error_code Error code if an error occurred, otherwise null. 10 | * @property {string | null} error_message Error message if an error occurred, otherwise null. 11 | */ 12 | export interface TransactionCreateResponseIdPay { 13 | isError: boolean 14 | 15 | data: { 16 | id: string 17 | link: string 18 | } 19 | 20 | error_code: string | null 21 | 22 | error_message: string | null 23 | } 24 | 25 | /** 26 | * Represents the response structure for verifying a transaction with IdPay. 27 | * Inherits properties from TransactionCreateResponseIdPay and modifies the 'data' property. 28 | * 29 | * @interface TransactionVerifyResponseIdPay 30 | * @extends {Omit} 31 | * @property {object} data Detailed data related to the verified transaction. 32 | * @property {string} data.status Status of the transaction. 33 | * @property {string} data.track_id Track ID of the transaction. 34 | * @property {string} data.id Transaction ID. 35 | * @property {string} data.order_id Order ID of the transaction. 36 | * @property {string} data.amount Amount of the transaction. 37 | * @property {string} data.date Date of the transaction. 38 | * @property {PaymentResponseIdPay} data.payment Payment details. 39 | * @property {object} data.verify Verification details. 40 | * @property {string} data.verify.date Date of the verification. 41 | * 42 | */ 43 | export interface TransactionVerifyResponseIdPay extends Omit { 44 | data: { 45 | status: string 46 | track_id: string 47 | id: string 48 | order_id: string 49 | amount: string 50 | date: string 51 | payment: PaymentResponseIdPay 52 | verify: { 53 | date: string 54 | } 55 | } 56 | } 57 | 58 | /** 59 | * Represents the payment details in the response for IdPay. 60 | * 61 | * @interface PaymentResponseIdPay 62 | * @property {string} track_id Tracking ID for the payment. 63 | * @property {string} amount Amount associated with the payment. 64 | * @property {string} card_no Card number used for the payment. 65 | * @property {string} hashed_card_no Hashed card number for security reasons. 66 | * @property {string} date Date of the payment. 67 | */ 68 | export interface PaymentResponseIdPay { 69 | track_id: string 70 | 71 | amount: string 72 | 73 | card_no: string 74 | 75 | hashed_card_no: string 76 | 77 | date: string 78 | } 79 | -------------------------------------------------------------------------------- /src/drivers/main.ts: -------------------------------------------------------------------------------- 1 | import { ZarinPalDriver } from './zarinpal/zarinpal' 2 | import { IdPayDriver } from './idpay/idpay' 3 | import { ZibalDriver } from './zibal/zibal' 4 | 5 | const drivers = { 6 | zarinpal: ZarinPalDriver, 7 | idPay: IdPayDriver, 8 | zibal: ZibalDriver 9 | } 10 | 11 | export type Drivers = keyof typeof drivers 12 | 13 | export type DriverInstance = InstanceType<(typeof drivers)[T]> 14 | 15 | export function getPaymentDriver(name: T): DriverInstance { 16 | const driverClass = drivers[name] as DriverInstance 17 | if (!driverClass) throw new Error(`Driver ${name} not found`) 18 | 19 | // @ts-ignore 20 | return new driverClass() 21 | } 22 | -------------------------------------------------------------------------------- /src/drivers/zarinpal/__tests__/zarinpal.spec.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { ZarinPalDriver } from '../zarinpal' 3 | import { TransactionCreateInputZp } from '../interfaces/requests.interface' 4 | import { zarinPalErrors } from '../enums/errors.enum' 5 | 6 | jest.mock('axios') 7 | const mockedAxios = axios as jest.Mocked 8 | 9 | describe('ZarinPalDriver', () => { 10 | let driver: ZarinPalDriver 11 | 12 | beforeEach(() => { 13 | driver = new ZarinPalDriver() 14 | }) 15 | 16 | it('should set the merchant ID', () => { 17 | const merchantId = 'your-merchant-id' 18 | driver.setToken(merchantId) 19 | expect(driver['merchant_id']).toBe(merchantId) 20 | }) 21 | 22 | it('should throw an error when setting an invalid merchant ID', () => { 23 | expect(() => driver.setToken('')).toThrowError('invalid parameters') 24 | }) 25 | 26 | it('should successfully create a transaction', async () => { 27 | const mockData: TransactionCreateInputZp = { 28 | amount: 1000, 29 | description: 'Test transaction', 30 | callback_url: 'https://example.com/callback' 31 | } 32 | 33 | const expectedResponse: any = { 34 | data: { 35 | code: 1000, 36 | message: '', 37 | fee: 100, 38 | url: '', 39 | authority: 'xx', 40 | fee_type: '' 41 | }, 42 | errors: { 43 | code: 0, 44 | message: 'Transaction created successfully', 45 | validations: [] 46 | }, 47 | isError: false 48 | } 49 | 50 | mockedAxios.post.mockResolvedValue({ data: expectedResponse }) 51 | 52 | const response = await driver.request(mockData) 53 | 54 | expect(response).toEqual(expectedResponse) 55 | }) 56 | 57 | it('should throw an error when creating a transaction with invalid parameters', async () => { 58 | const mockData: any = { 59 | amount: 1000, 60 | description: 'Test transaction' 61 | } 62 | 63 | await expect(driver.request(mockData)).rejects.toThrowError('invalid parameters') 64 | }) 65 | 66 | it('should handle transaction creation error', async () => { 67 | const mockData: any = { 68 | amount: 1000, 69 | description: 'Test transaction', 70 | callback_url: 'https://example.com/callback' 71 | } 72 | 73 | const errorResponseAxios = { 74 | data: { 75 | /* error response data */ 76 | }, 77 | errors: { 78 | code: -9, 79 | message: zarinPalErrors['-9'], 80 | validations: [] 81 | }, 82 | isError: true 83 | } 84 | 85 | const errorResponse = { 86 | data: {}, 87 | error: { 88 | code: -9, 89 | message: zarinPalErrors['-9'], 90 | validations: [] 91 | }, 92 | isError: true 93 | } 94 | 95 | mockedAxios.post.mockResolvedValue({ data: errorResponseAxios }) 96 | 97 | const response = await driver.request(mockData) 98 | 99 | expect(response).toEqual(errorResponse) 100 | }) 101 | }) 102 | -------------------------------------------------------------------------------- /src/drivers/zarinpal/enums/errors.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Object containing error codes and their corresponding descriptions for ZarinPal payment gateway. 3 | * 4 | * This list is based on the official documentation provided by ZarinPal. 5 | * 6 | * @constant 7 | * @link https://docs.zarinpal.com/paymentGateway/error.html 8 | */ 9 | export const zarinPalErrors: Record = { 10 | '-9': 'خطای اعتبار سنجی', 11 | '-10': 'ای پی و يا مرچنت كد پذيرنده صحيح نيست.', 12 | '-11': 'مرچنت کد فعال نیست لطفا با تیم پشتیبانی ما تماس بگیرید.', 13 | '-12': 'تلاش بیش از حد در یک بازه زمانی کوتاه.', 14 | '-15': 'ترمینال شما به حالت تعلیق در آمده با تیم پشتیبانی تماس بگیرید.', 15 | '-16': 'سطح تاييد پذيرنده پايين تر از سطح نقره اي است.', 16 | '-50': 'مبلغ پرداخت شده با مقدار مبلغ در تایید شده متفاوت است.', 17 | '-51': 'پرداخت ناموفق', 18 | '-30': 'پذیرنده اجازه دسترسی به سرویس تسویه اشتراکی شناور را ندارد.', 19 | '-31': 20 | 'حساب بانکی تسویه را به پنل اضافه کنید. مقادیر وارد شده برای تسهیم درست نیست. پذیرنده جهت استفاده از خدمات سرویس تسویه اشتراکی شناور، باید حساب بانکی معتبری به پنل کاربری خود اضافه نماید.', 21 | '-32': 'مبلغ وارد شده از مبلغ کل تراکنش بیشتر است.', 22 | '-33': 'درصدهای وارد شده صحیح نیست.', 23 | '-34': 'مبلغ وارد شده از مبلغ کل تراکنش بیشتر است.', 24 | '-35': 'تعداد افراد دریافت کننده تسهیم بیش از حد مجاز است.', 25 | '-36': 'حداقل مبلغ جهت تسهیم باید ۱۰۰۰۰ ریال باشد', 26 | '-37': 'یک یا چند شماره شبای وارد شده برای تسهیم از سمت بانک غیر فعال است.', 27 | '-38': 'خطا٬عدم تعریف صحیح شبا٬لطفا دقایقی دیگر تلاش کنید.', 28 | '-39': 'خطایی رخ داده است به امور مشتریان زرین پال اطلاع دهید', 29 | '-52': 'خطای غیر منتظره با پشتیبانی تماس بگیرید.', 30 | '-53': 'اتوریتی برای این مرچنت کد نیست.', 31 | '-54': 'اتوریتی نامعتبر است.', 32 | '101': 'تراکنش قبلا یک بار تایید شده است.' 33 | } 34 | -------------------------------------------------------------------------------- /src/drivers/zarinpal/enums/urls.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Enum representing URLs for interacting with the ZarinPal API endpoints. 3 | * 4 | * @enum {string} 5 | */ 6 | export enum ZarinpalUrls { 7 | /** 8 | * URL for creating a payment request in the production environment. 9 | * 10 | * @type {string} 11 | * @memberof ZarinpalUrls 12 | */ 13 | REQUEST = 'https://api.zarinpal.com/pg/v4/payment/request.json', 14 | 15 | /** 16 | * URL for creating a payment request in the sandbox environment. 17 | * 18 | * @type {string} 19 | * @memberof ZarinpalUrls 20 | */ 21 | SANDBOX_REQUEST = 'https://sandbox.zarinpal.com/pg/v4/payment/request.json', 22 | 23 | /** 24 | * URL for verifying a payment in the production environment. 25 | * 26 | * @type {string} 27 | * @memberof ZarinpalUrls 28 | */ 29 | VERIFY = 'https://api.zarinpal.com/pg/v4/payment/verify.json', 30 | 31 | /** 32 | * URL for verifying a payment in the sandbox environment. 33 | * 34 | * @type {string} 35 | * @memberof ZarinpalUrls 36 | */ 37 | SANDBOX_VERIFY = 'https://sandbox.zarinpal.com/pg/v4/payment/verify.json', 38 | 39 | /** 40 | * URL for the payment page in the production environment. 41 | * 42 | * @type {string} 43 | * @memberof ZarinpalUrls 44 | */ 45 | REQUEST_PAGE = 'https://www.zarinpal.com/pg/StartPay', 46 | 47 | /** 48 | * URL for the payment page in the sandbox environment. 49 | * 50 | * @type {string} 51 | * @memberof ZarinpalUrls 52 | */ 53 | SANDBOX_REQUEST_PAGE = 'https://sandbox.zarinpal.com/pg/StartPay/' 54 | } 55 | -------------------------------------------------------------------------------- /src/drivers/zarinpal/index.ts: -------------------------------------------------------------------------------- 1 | export { ZarinPalDriver } from './zarinpal' 2 | export * from './interfaces/requests.interface' 3 | 4 | export { zarinPalErrors } from './enums/errors.enum' 5 | -------------------------------------------------------------------------------- /src/drivers/zarinpal/interfaces/requests.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents the input structure for creating a transaction with ZarinPal. 3 | * 4 | * @interface TransactionCreateInputZp 5 | * @property {string} merchant_id Merchant ID, if available (optional). 6 | * @property {number} amount Amount for the transaction. 7 | * @property {string} callback_url Callback URL to redirect after the transaction. 8 | * @property {string} description Description for the transaction. 9 | * @property {"IRR" | "IRT"} currency Currency type for the transaction, either "IRR" or "IRT" (optional). 10 | * @property {object} metadata Additional metadata for the transaction. 11 | * @property {string} metadata.mobile Mobile number of the payer (optional). 12 | * @property {string} metadata.email Email address of the payer (optional). 13 | * @property {string} metadata.order_id Order ID for the transaction (optional). 14 | */ 15 | export interface TransactionCreateInputZp { 16 | merchant_id?: string 17 | 18 | amount: number 19 | 20 | callback_url: string 21 | 22 | description: string 23 | 24 | currency?: 'IRR' | 'IRT' 25 | 26 | metadata?: { 27 | mobile?: string 28 | email?: string 29 | order_id?: string 30 | } 31 | } 32 | 33 | /** 34 | * Represents the input structure for verifying a transaction with ZarinPal. 35 | * Inherits properties 'merchant_id' and 'amount' from TransactionCreateInputZp. 36 | * 37 | * @interface TransactionVerifyInputZp 38 | * @extends {Pick} 39 | * @property {string} authority Transaction authority. 40 | */ 41 | export interface TransactionVerifyInputZp extends Pick { 42 | authority: string 43 | } 44 | 45 | /** 46 | * Represents the error structure for ZarinPal transactions. 47 | * 48 | * @interface TransactionErrorZp 49 | * @property {number} code Error code. 50 | * @property {string} message Error message. 51 | * @property {array} validations Validation errors. 52 | * @property {string} validations[].field Field name. 53 | * @property {string} validations[].message Error message for the field. 54 | * @property {string} validations[].code Error code for the field. 55 | */ 56 | export interface TransactionErrorZp { 57 | code: number 58 | 59 | message: string 60 | 61 | validations: Record[] 62 | } 63 | 64 | /** 65 | * Represents the response structure for creating a transaction with ZarinPal. 66 | * 67 | * @interface TransactionCreateResponseZp 68 | * @property {boolean} isError Indicates if there's an error in the response. 69 | * @property {object} data Data related to the transaction if successful. 70 | * @property {number} data.code Transaction code. 71 | * @property {string} data.message Transaction message. 72 | * @property {string} data.authority Transaction authority. 73 | * @property {string} data.fee_type Fee type for the transaction. 74 | * @property {number} data.fee Fee amount for the transaction. 75 | * @property {string} data.url URL to redirect the user to. 76 | * @property {TransactionErrorZp} error Error details if an error occurred. 77 | */ 78 | export interface TransactionCreateResponseZp { 79 | isError: boolean 80 | 81 | data: { 82 | code: number 83 | message: string 84 | authority: string 85 | fee_type: string 86 | fee: number 87 | url: string 88 | } 89 | 90 | error: TransactionErrorZp 91 | } 92 | 93 | /** 94 | * Represents the response structure for verifying a transaction with ZarinPal. 95 | * 96 | * @type TransactionVerifyResponseZp 97 | * @property {boolean} isError Indicates if there's an error in the response. 98 | * @property {object} data Data related to the verified transaction if successful. 99 | * @property {number} data.code Transaction code. 100 | * @property {string} data.message Transaction message. 101 | * @property {string} data.card_hash Card hash for the transaction. 102 | * @property {string} data.card_pan Card PAN for the transaction. 103 | * @property {number} data.ref_id Reference ID for the transaction. 104 | * @property {string} data.fee_type Fee type for the transaction. 105 | * @property {number} data.fee Fee amount for the transaction. 106 | * @property {TransactionErrorZp} error Error details if an error occurred. 107 | */ 108 | export type TransactionVerifyResponseZp = 109 | | { 110 | isError: true 111 | error: TransactionErrorZp 112 | } 113 | | { 114 | isError: false 115 | data: { 116 | code: number 117 | message: string 118 | card_hash: string 119 | card_pan: string 120 | ref_id: number 121 | fee_type: string 122 | fee: number 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/drivers/zarinpal/zarinpal.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { ZarinpalUrls } from './enums/urls.enum' 3 | import { 4 | TransactionCreateInputZp, 5 | TransactionCreateResponseZp, 6 | TransactionVerifyInputZp, 7 | TransactionVerifyResponseZp 8 | } from './interfaces/requests.interface' 9 | import { zarinPalErrors } from './enums/errors.enum' 10 | 11 | interface Verify { 12 | data: { 13 | code: number 14 | message: string 15 | card_hash: string 16 | card_pan: string 17 | ref_id: number 18 | fee_type: string 19 | fee: number 20 | } 21 | errors: { 22 | code: number 23 | 24 | message: string 25 | 26 | validations: Record[] 27 | } 28 | } 29 | 30 | /** 31 | * Class to interact with the ZarinPal payment gateway. 32 | * 33 | * @class ZarinPalDriver 34 | */ 35 | export class ZarinPalDriver { 36 | private merchant_id: string | null = null 37 | 38 | /** 39 | * Set the merchant ID for the ZarinPal driver. 40 | * 41 | * @param {string} merchant_id - The merchant ID to set. 42 | * @returns {this} Instance of ZarinPalDriver. 43 | */ 44 | setToken(merchant_id: string): this { 45 | if (!merchant_id) throw new Error('invalid parameters') 46 | this.merchant_id = merchant_id 47 | return this 48 | } 49 | 50 | /** 51 | * Create a payment request to ZarinPal. 52 | * 53 | * @param {TransactionCreateInputZp} data - Input data for creating the transaction. 54 | * @param {boolean} [sandbox=false] - Flag to determine whether to use the sandbox environment. 55 | * @returns {Promise} Response from the ZarinPal API for creating a transaction. 56 | */ 57 | async request(data: TransactionCreateInputZp, sandbox: boolean = false): Promise { 58 | try { 59 | if (!data.amount || !data.description || !data.callback_url) throw new Error('invalid parameters') 60 | 61 | const requestUrl = sandbox ? ZarinpalUrls.SANDBOX_REQUEST : ZarinpalUrls.REQUEST 62 | 63 | const { data: dataAxios } = await axios.post(requestUrl, { 64 | ...data, 65 | merchant_id: data.merchant_id || this.merchant_id 66 | }) 67 | 68 | dataAxios.isError = dataAxios.errors.code < 0 69 | if (dataAxios.isError) { 70 | return { 71 | data: dataAxios.data, 72 | error: { 73 | message: zarinPalErrors[dataAxios.errors.code], 74 | code: dataAxios.errors.code, 75 | validations: dataAxios.errors.validations 76 | }, 77 | isError: true 78 | } 79 | } 80 | 81 | const url = sandbox ? ZarinpalUrls.SANDBOX_REQUEST_PAGE : ZarinpalUrls.REQUEST_PAGE 82 | 83 | dataAxios.data.url = `${url}/${dataAxios.data.authority}` 84 | 85 | return dataAxios 86 | } catch (error: any) { 87 | if (error.isAxiosError) { 88 | return { 89 | data: error.response.data.data, 90 | isError: true, 91 | error: { 92 | code: error.response.data?.errors?.code || error.response.status, 93 | message: zarinPalErrors[error.response.data?.errors?.code] || error.message, 94 | validations: [] 95 | } 96 | } 97 | } 98 | error.isError = true 99 | throw error 100 | } 101 | } 102 | 103 | /** 104 | * Verify a payment transaction with ZarinPal. 105 | * 106 | * @param {TransactionVerifyInputZp} data - Input data for verifying the transaction. 107 | * @param {boolean} [sandbox=false] - Flag to determine whether to use the sandbox environment. 108 | * @returns {Promise} Response from the ZarinPal API for verifying a transaction. 109 | */ 110 | async verify(data: TransactionVerifyInputZp, sandbox: boolean = false): Promise { 111 | try { 112 | const requestUrl = sandbox ? ZarinpalUrls.SANDBOX_VERIFY : ZarinpalUrls.VERIFY 113 | const { data: verifyData } = await axios.post(requestUrl, { 114 | ...data, 115 | merchant_id: data.merchant_id || this.merchant_id 116 | }) 117 | 118 | const code: number | undefined = verifyData.data.code 119 | 120 | let isError = false 121 | if (!code || code !== 100) { 122 | isError = true 123 | } 124 | 125 | if (isError) { 126 | return { 127 | isError: true, 128 | error: { 129 | code: verifyData.errors.code || verifyData.data.code, 130 | validations: verifyData.errors.validations, 131 | message: zarinPalErrors[verifyData.errors.code || verifyData.data.code] 132 | } 133 | } 134 | } 135 | 136 | return { 137 | data: verifyData.data, 138 | isError: false 139 | } 140 | } catch (error: any) { 141 | if (error.isAxiosError) { 142 | return { 143 | isError: true, 144 | error: { 145 | code: error.response.data?.errors?.code || error.response.status, 146 | message: zarinPalErrors[error.response.data?.errors?.code] || error.message, 147 | validations: [] 148 | } 149 | } 150 | } 151 | error.isError = true 152 | throw error 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/drivers/zibal/enums/message.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Object containing error codes and their corresponding descriptions for Zibal payment gateway. 3 | * 4 | * This list is based on the official documentation provided by Zibal. 5 | * 6 | * @constant 7 | * @link https://help.zibal.ir/IPG/API/#requestResultCode 8 | */ 9 | export const zibalMessages: Record = { 10 | '102': 'آی پی یا مرچنت کد پذیرنده صحیح نیست', 11 | '103': 'مرچنت کد فعال نیست', 12 | '104': 'مرچنت کد نامعتبر است', 13 | '105': 'amount بایستی بزرگتر از 1,000 ریال باشد.', 14 | '106': 'callbackUrl نامعتبر می‌باشد. (شروع با http و یا https)', 15 | '113': 'amount مبلغ تراکنش از سقف میزان تراکنش بیشتر است.', 16 | '201': 'قبلا تایید شده ', 17 | '202': 'سفارش پرداخت نشده یا ناموفق بوده است. جهت اطلاعات بیشتر جدول وضعیت‌ها را مطالعه کنید.', 18 | '203': 'trackId نامعتبر می‌باشد.' 19 | } 20 | -------------------------------------------------------------------------------- /src/drivers/zibal/enums/urls.enum.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Enum representing URLs for interacting with the Zibal API endpoints. 3 | * 4 | * @enum {string} 5 | */ 6 | export enum ZibalUrls { 7 | /** 8 | * URL for creating a payment request. 9 | * @type {string} 10 | * @memberof ZibalUrls 11 | * @link https://help.zibal.ir/IPG/API/#request 12 | */ 13 | REQUEST = 'https://gateway.zibal.ir/v1/request', 14 | 15 | /** 16 | * URL for verifying a payment. 17 | * @type {string} 18 | * @memberof ZibalUrls 19 | * @link https://help.zibal.ir/IPG/API/#verify 20 | */ 21 | VERIFY = 'https://gateway.zibal.ir/v1/verify' 22 | } 23 | -------------------------------------------------------------------------------- /src/drivers/zibal/index.ts: -------------------------------------------------------------------------------- 1 | export { ZibalDriver } from './zibal' 2 | 3 | export * from './interfaces/requests.interface' 4 | export * from './interfaces/response.interface' 5 | 6 | export { zibalMessages } from './enums/message.enum' 7 | -------------------------------------------------------------------------------- /src/drivers/zibal/interfaces/requests.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents the input structure for creating a transaction with Zibal. 3 | * 4 | * @interface TransactionCreateInputZibal 5 | * @property {string} merchant Merchant ID (Optional). 6 | * @property {number} amount Desired amount in Rials. 7 | * @property {string} callbackUrl URL to redirect the user to after payment. 8 | * @property {string} description Description of the transaction (Optional). 9 | * @property {string} orderId Order ID of the transaction (Optional). 10 | * @property {string} mobile Mobile number of the payer (Optional). 11 | * @property {string[]} allowedCards Allowed cards for the transaction (Optional). 12 | * @property {string} ledgerId Ledger ID for the transaction (Optional). 13 | * @property {boolean} linkToPay Indicates if the user should be redirected to the payment page (Optional). 14 | * @property {boolean} sms Indicates if an SMS should be sent to the payer (Optional). 15 | */ 16 | export interface TransactionCreateInputZibal { 17 | merchant?: string 18 | amount: number 19 | callbackUrl: string 20 | description?: string 21 | orderId?: string 22 | mobile?: string 23 | allowedCards?: string[] 24 | ledgerId?: string 25 | linkToPay?: boolean 26 | sms?: boolean 27 | } 28 | 29 | /** 30 | * 31 | * Represents the input structure for verifying a transaction with Zibal. 32 | * @property {string} merchant Merchant ID (Optional). 33 | * @property {string} trackId Track ID of the transaction. 34 | * @interface TransactionVerifyInputZibal 35 | */ 36 | export interface TransactionVerifyInputZibal { 37 | merchant?: string 38 | trackId: string 39 | } 40 | -------------------------------------------------------------------------------- /src/drivers/zibal/interfaces/response.interface.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Represents the response object for creating a transaction in Zibal. 3 | * 4 | * @interface TransactionCreateResponseZibal 5 | * @property {boolean} isError Indicates if there's an error in the response. 6 | * @property {object} data Data related to the transaction if successful. 7 | * @property {number} data.trackId Track ID of the transaction. 8 | * @property {string} data.url URL to redirect the user to. 9 | * @property {object} error Error details if an error occurred. 10 | * @property {string} error.message Error message. 11 | * @property {number} error.code Error code. 12 | */ 13 | export interface TransactionCreateResponseZibal { 14 | isError: boolean 15 | data: { 16 | trackId: number 17 | url: string 18 | } | null 19 | error: { 20 | message: string 21 | code: number 22 | } | null 23 | } 24 | 25 | /** 26 | * Represents the response object for verifying a transaction in Zibal. 27 | * 28 | * @interface TransactionVerifyResponseZibal 29 | * @property {boolean} isError Indicates if there's an error in the response. 30 | * @property {object} error Error details if an error occurred. 31 | * @property {string} error.message Error message. 32 | * @property {number} error.code Error code. 33 | * @property {object} data Data related to the transaction if successful. 34 | * @property {string} data.paidAt Date and time of the payment. 35 | * @property {number} data.status Status of the transaction. 36 | * @property {number} data.amount Amount of the transaction. 37 | * @property {string} data.orderId Order ID of the transaction. 38 | * @property {string} data.description Description of the transaction. 39 | * @property {string} data.cartNumber Cart number of the transaction. 40 | * @property {string[]} data.multiplexingInfos Multiplexing information of the transaction. 41 | * @property {number} data.refNumber Reference number of the transaction. 42 | * @property {string} data.message Message of the transaction. 43 | */ 44 | export interface TransactionVerifyResponseZibal { 45 | isError: boolean 46 | error: { 47 | message: string 48 | code: number 49 | } | null 50 | data: { 51 | paidAt: string 52 | status: number 53 | amount: number 54 | orderId: string 55 | description: string 56 | cartNumber: string | null 57 | multiplexingInfos: string[] 58 | refNumber: number | null 59 | message: string 60 | } | null 61 | } 62 | -------------------------------------------------------------------------------- /src/drivers/zibal/zibal.ts: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { ZibalUrls } from './enums/urls.enum' 3 | import { TransactionCreateInputZibal, TransactionVerifyInputZibal } from './interfaces/requests.interface' 4 | import { TransactionCreateResponseZibal, TransactionVerifyResponseZibal } from './interfaces/response.interface' 5 | import { zibalMessages } from './enums/message.enum' 6 | 7 | /** 8 | * Class to interact with the Zibal payment gateway. 9 | * 10 | * @class ZibalDriver 11 | */ 12 | export class ZibalDriver { 13 | private merchant: string | null = null 14 | 15 | setToken(merchant: string): this { 16 | if (!merchant) { 17 | throw new Error('invalid parameters') 18 | } 19 | 20 | this.merchant = merchant 21 | return this 22 | } 23 | 24 | /** 25 | * Create a payment request to Zibal. 26 | * 27 | * @param {TransactionCreateInputZibal} data - Input data for creating the transaction. 28 | * @param {boolean} [sandbox=false] - Flag to determine whether to use the sandbox environment. 29 | * @returns {Promise} Response from the Zibal API for creating a transaction. 30 | */ 31 | async request(data: TransactionCreateInputZibal, sandbox: boolean = false): Promise { 32 | try { 33 | if (!sandbox) { 34 | if (!this.merchant && !data.merchant) { 35 | throw new Error(`merchant is required for this request`) 36 | } 37 | } 38 | 39 | if (!data.amount || !data.callbackUrl) { 40 | throw new Error('invalid parameters') 41 | } 42 | 43 | const requestUrl = ZibalUrls.REQUEST 44 | 45 | const { data: dataAxios } = await axios.post(requestUrl, { 46 | ...data, 47 | merchant: sandbox ? 'zibal' : this.merchant || data.merchant 48 | }) 49 | 50 | dataAxios.isError = dataAxios.result !== 100 51 | if (dataAxios.isError) { 52 | return { 53 | data: null, 54 | error: { 55 | message: zibalMessages[dataAxios.result] || dataAxios.message, 56 | code: 0 57 | }, 58 | isError: true 59 | } 60 | } 61 | 62 | return { 63 | isError: false, 64 | error: null, 65 | data: { 66 | trackId: dataAxios.trackId, 67 | url: `https://gateway.zibal.ir/start/${dataAxios.trackId}` 68 | } 69 | } 70 | } catch (error: any) { 71 | const message = error.message || 'An error occurred while processing the request' 72 | return { 73 | error: { 74 | message, 75 | code: error.code || 500 76 | }, 77 | isError: true, 78 | data: null 79 | } 80 | } 81 | } 82 | 83 | /** 84 | * Verify a payment transaction with Zibal. 85 | * 86 | * @param {TransactionVerifyInputZibal} data - Input data for verifying the transaction. 87 | * @param {boolean} [sandbox=false] - Flag to determine whether to use the sandbox environment. 88 | * @returns {Promise} Response from the Zibal API for verifying a transaction. 89 | */ 90 | async verify(data: TransactionVerifyInputZibal, sandbox: boolean): Promise { 91 | try { 92 | if (!sandbox) { 93 | if (!this.merchant && !data.merchant) { 94 | throw new Error(`merchant is required for this request`) 95 | } 96 | } 97 | 98 | if (!data.trackId) { 99 | throw new Error(`trackId is required for this request`) 100 | } 101 | 102 | const requestUrl = ZibalUrls.VERIFY 103 | 104 | const { data: dataAxios } = await axios.post(requestUrl, { 105 | ...data, 106 | merchant: sandbox ? 'zibal' : this.merchant || data.merchant 107 | }) 108 | 109 | dataAxios.isError = dataAxios.result !== 100 110 | 111 | if (dataAxios.isError) { 112 | return { 113 | data: null, 114 | error: { 115 | message: zibalMessages[dataAxios.result] || dataAxios.message, 116 | code: 0 117 | }, 118 | isError: true 119 | } 120 | } 121 | 122 | return { 123 | data: { 124 | amount: dataAxios.amount, 125 | cartNumber: dataAxios.cardNumber, 126 | description: dataAxios.description, 127 | message: dataAxios.message, 128 | multiplexingInfos: dataAxios.multiplexingInfos, 129 | orderId: dataAxios.orderId, 130 | paidAt: dataAxios.paidAt, 131 | refNumber: dataAxios.refNumber, 132 | status: dataAxios.status 133 | }, 134 | isError: false, 135 | error: null 136 | } 137 | } catch (error: any) { 138 | const message = error.message || 'An error occurred while processing the request' 139 | return { 140 | error: { 141 | message, 142 | code: error.code || 500 143 | }, 144 | isError: true, 145 | data: null 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/easypay.ts: -------------------------------------------------------------------------------- 1 | export { getPaymentDriver } from './drivers/main' 2 | export * from './drivers/zarinpal' 3 | export * from './drivers/idpay' 4 | export * from './drivers/zibal' 5 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './easypay' 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "CommonJS", 5 | "outDir": "./dist", 6 | "rootDir": "./src", 7 | "declaration": true, 8 | "strict": true, 9 | "esModuleInterop": true 10 | }, 11 | "include": ["src/**/*.ts"], 12 | "exclude": ["node_modules", "dist", "**/*spec.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "tsup"; 2 | 3 | export default defineConfig({ 4 | entry: ["src/index.ts"], 5 | target: "esnext", 6 | format: ["cjs", "esm"], 7 | splitting: false, 8 | sourcemap: true, 9 | clean: true, 10 | dts: true, 11 | }); 12 | --------------------------------------------------------------------------------