├── .env ├── .gitignore ├── Caddyfile ├── Dockerfile ├── NOTES.md ├── README.md ├── config ├── custom-environment-variables.ts ├── default.ts ├── production.ts └── test.ts ├── deploy.sh ├── diagrams ├── data-flow.png └── refresh-token-flow.png ├── docker-compose.yml ├── package.json ├── postman_collection.json ├── service-inputs.patch ├── src ├── app.ts ├── controller │ ├── product.controller.ts │ ├── session.controller.ts │ └── user.controller.ts ├── middleware │ ├── deserializeUser.ts │ ├── requireUser.ts │ └── validateResource.ts ├── models │ ├── product.model.ts │ ├── session.model.ts │ └── user.model.ts ├── routes.ts ├── schema │ ├── product.schema.ts │ ├── session.schema.ts │ └── user.schema.ts ├── service │ ├── product.service.ts │ ├── session.service.ts │ └── user.service.ts └── utils │ ├── connect.ts │ ├── jwt.utils.ts │ ├── logger.ts │ ├── metrics.ts │ └── swagger.ts ├── tsconfig.json └── yarn.lock /.env: -------------------------------------------------------------------------------- 1 | ## Warning: Make sure you generate new keys before you deploy your application and add .env to your .gitignore 2 | 3 | # Generate new keys: https://travistidwell.com/jsencrypt/demo/ 4 | 5 | # Base64 encode the keys: https://www.base64encode.org/ 6 | 7 | ACCESS_TOKEN_PUBLIC_KEY="LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZU1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTUFEQ0JpQUtCZ0hOZEYvNFFVNU1NRmF2eW9veWVpT0VqdldXbgpvREJyemJpVzY5dnAzS1NueEF4T2NVMDlmODlUd0JWTWRsN2JUMzEzN0tMWEl6UE95OEl4TTExKzcwVmlubjgzCjUvMWVlaDhZTHBRM25KaWJZeVBqdzRjLy9GYzJoZGhENlJvM29hU25adWNteStqZUdTUFMxY0JnbThVOUR3OVAKakY0eE82UjU4RkorYXJBSkFnTUJBQUU9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ" 8 | 9 | ACCESS_TOKEN_PRIVATE_KEY="LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlDV3dJQkFBS0JnSE5kRi80UVU1TU1GYXZ5b295ZWlPRWp2V1dub0RCcnpiaVc2OXZwM0tTbnhBeE9jVTA5CmY4OVR3QlZNZGw3YlQzMTM3S0xYSXpQT3k4SXhNMTErNzBWaW5uODM1LzFlZWg4WUxwUTNuSmliWXlQanc0Yy8KL0ZjMmhkaEQ2Um8zb2FTblp1Y215K2plR1NQUzFjQmdtOFU5RHc5UGpGNHhPNlI1OEZKK2FyQUpBZ01CQUFFQwpnWUJWZ3RHLzd0WWtEemNaSjFhNXFPR0pFSGJaSFBFdU14cGdFdTV0S2VIMDRxMzgrVUFlb3RGVUdwNHNxMnFxClVTR1F2UTNZZm1PSGlXZWJYK0RWRXJ2RHlwcDA4alQ3VlMvQlpQbkRNYzVrSldRZTROWmRvZVAxOXlSblpnb3UKbFhiNXhZTklqVW5UeXNhVG5SYW9Sd0JOYjVub0NmbGZham5nMFdHZng4czRBUUpCQU5vTG1iYjVKdnZabWhJVgpPajEySGtGOU96RDhwN0ZBWUdicnovNEVybGVnR0J1enc4dkowakYyR1R0WTgvT3duaVQ1b1pndWpTOFFNTW1XCldNendtSWtDUVFDSGNkdFVUQ2lvWE9JTE54cXk0ZmhGVFZBa0ZVbGFyamlWYmt6UGlIZ2xLT0I0bmdRZmluZWQKcGJ6TXM0WTJJVUErRDlnckcwZy9MWEx2Rk94ZnhIdUJBa0VBaXlyZVNFZUwxekVTd2pua096ZzVwV2p0cjUyQwoxb0lWUlh0Ni9GRTJpVno0Smk0OWFNTitzZTBEdTdwUnNoYm5TUWcvV0dkVjIxVUZIcFVrUm1IRnFRSkFORjYxCnEzWjNFZ0kzOUpZdDRKUzI1alRxazhrWFA5UzFWREg5eVJDL1E3NzJiQ3pNODFVYXd2M2VibGZMd1FwQ1NMemYKbkd0RUdBbCtzeXFuNnErU0FRSkFERDZOVDV1TFM0WTRWWHVQT0lDWU9rTlg2RkxVbmYrTWRVb3ByZnNDdTU0Qgo1OFNBZUh0c0pmZ3hBS3BBaVA0UmNTT0l2UlE4UHZxak10RVA3d2xQVHc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ" 10 | 11 | REFRESH_PRIVATE_KEY="LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlDWEFJQkFBS0JnUUN1TEhDcGZYWkNONWpteUtjdFlmNXlja2lBbjF5bkJod0RGZG9rRGp1SDFsZlVKR0g5ClZIVDdKOTJuNzJFemNhMzJ5TVNVcGU0RXlzL2pDRkZILytUYWJJbTIzRzRLQnBHWDRzNVJyNHozZFVpSVB6OUkKdmNRSWNvQ2I0SHM0TVByaTVJdC9NR3FqOVJhTThJSzFmemZTaGFxVlNPVHI0d2JCbmV2YTdwdlhMd0lEQVFBQgpBb0dBQWx0NW51R2kweHliaGl3YkR5TXZaVzhraWhFZUdPaWRRbkZ1UldTbjY1dThEcFA3ZTRsRUdBNGZFdUhMCmgvMjI1QXN0bGZGMCtqMmdlS3NwSm5kUktwblJwZWhMaGk4YVRNLzRGT093VXJFOGlGYWFtT0lYcmhsVERVclgKMTUzY3B3bUNtYktKU2trSklIOW14bUhyWVJRdlRmYVFtY0xaL1VLNGQ1UVNhZUVDUVFEL1pUbmpmOUVkbE4vQwpOelBNWDQvMExsc0JtUjFFNHIvTUc4akxOZlNTOEJxMlZpbklLWS9abzVKK3ZqcjQ2YVlEUzZTazE2UTlMT2NjClA3RURwZXh4QWtFQXJwWDkvN3VUcEhJMW1LOGN6SnF0dzdUL0JmY2hLL0pCdU5KUjBJcXY3c2F5eHJObDBab0YKM3dLTnhmYkNla0NjQ2pKemE1d01vK2NZN2tVSzRYQk5ud0pCQU9LenVpVUZTbHlWeitHWUdyU3BoeURiSFJGWQpGckVWRGVkaUttU25xa2ZjTmZud2xmb0ZXcGw0Snd1MlZLYXEwQ0JRdnY5TUk0L2lFZXZ6WlcrMWt5RUNRRzVJCkJSaGpydEd6NnpNMWVtV3NWNU5HWThtcTMrTll0amMvYzdyZHdHQitWek80NHRwU0J0OW1SNVFEV2JuTDBrV0cKdE80R3R0MVovNStUTVZwU2pGVUNRRE5HeDBhcnFSUEhJWjZ3UFlpVXBuQkN5dU90dTExT2hYeE8xWFdIR21aaAo4d254YVk3UklZNWJ6NllzenZ2bHR4MU93YWw4a2svN3N5NjNpZGhmYmhFPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQ" 12 | 13 | REFRESH_PUBLIC_KEY="LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTRHTkFEQ0JpUUtCZ1FDdUxIQ3BmWFpDTjVqbXlLY3RZZjV5Y2tpQQpuMXluQmh3REZkb2tEanVIMWxmVUpHSDlWSFQ3SjkybjcyRXpjYTMyeU1TVXBlNEV5cy9qQ0ZGSC8rVGFiSW0yCjNHNEtCcEdYNHM1UnI0ejNkVWlJUHo5SXZjUUljb0NiNEhzNE1Qcmk1SXQvTUdxajlSYU04SUsxZnpmU2hhcVYKU09UcjR3YkJuZXZhN3B2WEx3SURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQ" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | build -------------------------------------------------------------------------------- /Caddyfile: -------------------------------------------------------------------------------- 1 | rest-api.snipd.io { 2 | reverse_proxy rest-api:1337 { 3 | header_down Strict-Transport-Security max-age=31536000; 4 | } 5 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 2 | 3 | ADD package.json /tmp/package.json 4 | 5 | ADD yarn.lock /tmp/yarn.lock 6 | 7 | RUN rm -rf build 8 | 9 | RUN cd /tmp && yarn install 10 | 11 | ADD ./ /src 12 | 13 | RUN rm -rf src/node_modules && cp -a /tmp/node_modules /src/ 14 | 15 | WORKDIR /src 16 | 17 | RUN yarn build 18 | 19 | CMD ["node", "build/src/app.js"] -------------------------------------------------------------------------------- /NOTES.md: -------------------------------------------------------------------------------- 1 | yarn add express zod config cors express mongoose pino pino-pretty dayjs bcrypt jsonwebtoken lodash nanoid 2 | 3 | yarn add @types/body-parser @types/config @types/cors @types/express @types/node @types/pino @types/bcrypt @types/jsonwebtoken @types/lodash @types/nanoid ts-node-dev typescript -D -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Build a REST API with Node.js, Mongoose & TypeScript 2 | 3 | Note: This repository includes the [postman collection for the finished API](postman_collection.json) 4 | 5 | Note 2: Make sure you add .env to your .gitignore before pushing any changes to your repository. You will also want to generate new public & private keys 6 | 7 | #### Generate new keys: https://travistidwell.com/jsencrypt/demo/ 8 | 9 | #### Base64 encode the keys: https://www.base64encode.org/ 10 | 11 | 12 | 13 | ## Common issues 14 | * I'm getting a JWT malformed error: https://youtu.be/FzKrfwplips 15 | * Managing environment variables: https://youtu.be/gfyQzeBlLTI 16 | 17 | ## Who is this tutorial for? 18 | * Junior to mid-level developers 19 | * Anyone interested in building REST APIs with TypeScript 20 | 21 | ## What you will need 22 | * A running instance of MongoDB 23 | * Postman 24 | * An IDE or text editor (VS Code) 25 | * A web browser 26 | * A package manager such as NPM or Yarn 27 | * Node.js installed 28 | 29 | ## What next? 30 | * Testing the API with Jest 31 | * Build a React.js user interface 32 | * Add Prometheus metrics to the API 33 | * Deploy the API with Caddy & Docker 34 | * Add Google OAuth 35 | 36 | ## Concepts 37 | * REST API principals 38 | * CRUD 39 | * HTTP methods 40 | * JWT & refresh tokens 41 | * Request validation 42 | ## Technologies 43 | * Node.js 44 | * MongoDB with Mongoose 45 | * TypeScript 46 | * Express.js & Express.js middleware 47 | * Zod validation 48 | 49 | ## Video structure 50 | 1. What are we going to build (Postman demo) 51 | 2. Code walk-through 52 | 3. Bootstrap application 53 | 1. Setup express JS 54 | 2. Create routes function 55 | 3. Setup database connection 56 | 4. Setup logger 57 | 5. Validate request middleware 58 | 4. Registration 59 | 1. Create user model 60 | 2. Create user endpoint 61 | 3. Create user session 62 | 4. Deserialize user middleware (refresh tokens) 63 | 5. Get sessions 64 | 6. Delete session 65 | 7. Require user middleware 66 | 5. Product resource 67 | 1. Create product model 68 | 2. Create product 69 | 3. Read product 70 | 4. Update product 71 | 5. Delete product 72 | 73 | 74 | ## Data flow 75 | ![](./diagrams/data-flow.png) 76 | 77 | 78 | ## Access & refresh token flow 79 | ![](./diagrams/refresh-token-flow.png) 80 | 81 | 82 | # Deployment 83 | 84 | ## What will we use 85 | * Docker (image) 86 | * docker-compose (container) 87 | * Caddy - Web server 88 | * DigitalOcean 89 | 90 | Note: You will need Docker installed locally if you want to test your Docker configutation 91 | 92 | ## Let's keep in touch 93 | - [Subscribe on YouTube](https://www.youtube.com/TomDoesTech) 94 | - [Discord](https://discord.gg/4ae2Esm6P7) 95 | - [Twitter](https://twitter.com/tomdoes_tech) 96 | - [TikTok](https://www.tiktok.com/@tomdoestech) 97 | - [Facebook](https://www.facebook.com/tomdoestech) 98 | - [Instagram](https://www.instagram.com/tomdoestech) 99 | 100 | [Buy me a Coffee](https://www.buymeacoffee.com/tomn) 101 | 102 | [Sign up to DigitalOcean 💖](https://m.do.co/c/1b74cb8c56f4) 103 | -------------------------------------------------------------------------------- /config/custom-environment-variables.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | accessTokenPrivateKey: "ACCESS_TOKEN_PRIVATE_KEY", 3 | accessTokenPublicKey: "ACCESS_TOKEN_PUBLIC_KEY", 4 | refreshTokenPrivateKey: "REFRESH_PRIVATE_KEY", 5 | refreshTokenPublicKey: "REFRESH_PUBLIC_KEY", 6 | dbUri: "DB_CONNECTION", 7 | port: "PORT", 8 | }; 9 | -------------------------------------------------------------------------------- /config/default.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | port: 1337, 3 | dbUri: "mongodb://localhost:27017/rest-api-tutorial", 4 | saltWorkFactor: 10, 5 | accessTokenTtl: "15m", 6 | refreshTokenTtl: "1y", 7 | accessTokenPrivateKey: ``, 8 | accessTokenPublicKey: ``, 9 | refreshTokenPrivateKey: ``, 10 | refreshTokenPublicKey: ``, 11 | }; 12 | -------------------------------------------------------------------------------- /config/production.ts: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /config/test.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomDoesTech/REST-API-Tutorial-Updated/7b5f040e1acd94d267df585516b33ee7e3b75f70/config/test.ts -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Pulling" 4 | git pull 5 | 6 | echo "Building application" 7 | docker-compose up -d --build 8 | -------------------------------------------------------------------------------- /diagrams/data-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomDoesTech/REST-API-Tutorial-Updated/7b5f040e1acd94d267df585516b33ee7e3b75f70/diagrams/data-flow.png -------------------------------------------------------------------------------- /diagrams/refresh-token-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TomDoesTech/REST-API-Tutorial-Updated/7b5f040e1acd94d267df585516b33ee7e3b75f70/diagrams/refresh-token-flow.png -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | services: 3 | rest-api: 4 | container_name: rest-api 5 | restart: unless-stopped 6 | environment: 7 | - NODE_ENV=production 8 | build: 9 | context: ./ 10 | 11 | caddy: 12 | image: caddy/caddy:2.2.1-alpine 13 | container_name: caddy-service 14 | restart: unless-stopped 15 | ports: 16 | - "80:80" 17 | - "443:443" 18 | volumes: 19 | - $PWD/Caddyfile:/etc/caddy/Caddyfile 20 | - $PWD/site:/srv 21 | - caddy_data:/data 22 | - caddy_config:/config 23 | 24 | volumes: 25 | caddy_data: 26 | caddy_config: -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rest-api-tutorial-updated", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "author": "Tom Nagle", 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "ts-node-dev --respawn --transpile-only src/app.ts", 9 | "build": "tsc" 10 | }, 11 | "dependencies": { 12 | "bcrypt": "^5.0.1", 13 | "config": "^3.3.6", 14 | "cors": "^2.8.5", 15 | "dayjs": "^1.10.7", 16 | "dotenv": "^10.0.0", 17 | "express": "^4.17.1", 18 | "jsonwebtoken": "^8.5.1", 19 | "lodash": "^4.17.21", 20 | "mongoose": "^6.0.11", 21 | "nanoid": "^3.1.30", 22 | "pino": "^7.0.2", 23 | "pino-pretty": "^7.1.0", 24 | "prom-client": "^14.0.0", 25 | "response-time": "^2.3.2", 26 | "swagger-jsdoc": "^6.1.0", 27 | "swagger-ui-express": "^4.1.6", 28 | "zod": "^3.9.8" 29 | }, 30 | "devDependencies": { 31 | "@types/bcrypt": "^5.0.0", 32 | "@types/body-parser": "^1.19.1", 33 | "@types/config": "^0.0.39", 34 | "@types/cors": "^2.8.12", 35 | "@types/express": "^4.17.13", 36 | "@types/jsonwebtoken": "^8.5.5", 37 | "@types/lodash": "^4.14.175", 38 | "@types/nanoid": "^3.0.0", 39 | "@types/node": "^16.11.1", 40 | "@types/pino": "^6.3.11", 41 | "@types/response-time": "^2.3.5", 42 | "@types/swagger-jsdoc": "^6.0.1", 43 | "@types/swagger-ui-express": "^4.1.3", 44 | "ts-node-dev": "^1.1.8", 45 | "typescript": "^4.4.4" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "d3a34203-6dac-480e-8aac-0dce44241f83", 4 | "name": "REST API Tutorial", 5 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 6 | }, 7 | "item": [ 8 | { 9 | "name": "User", 10 | "item": [ 11 | { 12 | "name": "Create User", 13 | "request": { 14 | "method": "POST", 15 | "header": [], 16 | "body": { 17 | "mode": "raw", 18 | "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\",\n \"passwordConfirmation\": \"{{password}}\",\n \"name\": \"{{name}}\"\n}", 19 | "options": { 20 | "raw": { 21 | "language": "json" 22 | } 23 | } 24 | }, 25 | "url": { 26 | "raw": "{{endpoint}}/api/users", 27 | "host": [ 28 | "{{endpoint}}" 29 | ], 30 | "path": [ 31 | "api", 32 | "users" 33 | ] 34 | } 35 | }, 36 | "response": [] 37 | }, 38 | { 39 | "name": "Create Session", 40 | "event": [ 41 | { 42 | "listen": "test", 43 | "script": { 44 | "exec": [ 45 | "var jsonData = JSON.parse(responseBody);", 46 | "console.log(jsonData)", 47 | "postman.setEnvironmentVariable(\"accessToken\", jsonData.accessToken);", 48 | "postman.setEnvironmentVariable(\"refreshToken\", jsonData.refreshToken);" 49 | ], 50 | "type": "text/javascript" 51 | } 52 | } 53 | ], 54 | "request": { 55 | "method": "POST", 56 | "header": [], 57 | "body": { 58 | "mode": "raw", 59 | "raw": "{\n \"email\": \"{{email}}\",\n \"password\": \"{{password}}\"\n}", 60 | "options": { 61 | "raw": { 62 | "language": "json" 63 | } 64 | } 65 | }, 66 | "url": { 67 | "raw": "{{endpoint}}/api/sessions", 68 | "host": [ 69 | "{{endpoint}}" 70 | ], 71 | "path": [ 72 | "api", 73 | "sessions" 74 | ] 75 | } 76 | }, 77 | "response": [] 78 | }, 79 | { 80 | "name": "Get Sessions", 81 | "event": [ 82 | { 83 | "listen": "test", 84 | "script": { 85 | "exec": [ 86 | "", 87 | "const newAccessToken = responseHeaders['x-access-token']", 88 | "", 89 | "if(newAccessToken){", 90 | " console.log('Set new access token')", 91 | "postman.setEnvironmentVariable(\"accessToken\", newAccessToken);", 92 | "}", 93 | "", 94 | "" 95 | ], 96 | "type": "text/javascript" 97 | } 98 | } 99 | ], 100 | "request": { 101 | "auth": { 102 | "type": "bearer", 103 | "bearer": [ 104 | { 105 | "key": "token", 106 | "value": "{{accessToken}}", 107 | "type": "string" 108 | } 109 | ] 110 | }, 111 | "method": "GET", 112 | "header": [ 113 | { 114 | "key": "x-refresh", 115 | "value": "{{refreshToken}}", 116 | "type": "text" 117 | } 118 | ], 119 | "url": { 120 | "raw": "{{endpoint}}/api/sessions", 121 | "host": [ 122 | "{{endpoint}}" 123 | ], 124 | "path": [ 125 | "api", 126 | "sessions" 127 | ] 128 | } 129 | }, 130 | "response": [] 131 | }, 132 | { 133 | "name": "Delete Session", 134 | "event": [ 135 | { 136 | "listen": "test", 137 | "script": { 138 | "exec": [ 139 | "const newAccessToken = responseHeaders['x-access-token']", 140 | "", 141 | "if(newAccessToken){", 142 | " console.log('Set new access token')", 143 | "postman.setEnvironmentVariable(\"accessToken\", newAccessToken);", 144 | "}", 145 | "", 146 | "" 147 | ], 148 | "type": "text/javascript" 149 | } 150 | } 151 | ], 152 | "request": { 153 | "auth": { 154 | "type": "bearer", 155 | "bearer": [ 156 | { 157 | "key": "token", 158 | "value": "{{accessToken}}", 159 | "type": "string" 160 | } 161 | ] 162 | }, 163 | "method": "DELETE", 164 | "header": [ 165 | { 166 | "key": "x-refresh", 167 | "value": "{{refreshToken}}", 168 | "type": "text" 169 | } 170 | ], 171 | "url": { 172 | "raw": "{{endpoint}}/api/sessions", 173 | "host": [ 174 | "{{endpoint}}" 175 | ], 176 | "path": [ 177 | "api", 178 | "sessions" 179 | ] 180 | } 181 | }, 182 | "response": [] 183 | } 184 | ] 185 | }, 186 | { 187 | "name": "Product", 188 | "item": [ 189 | { 190 | "name": "Create Product", 191 | "event": [ 192 | { 193 | "listen": "test", 194 | "script": { 195 | "exec": [ 196 | "var jsonData = JSON.parse(responseBody);", 197 | "postman.setEnvironmentVariable(\"productId\", jsonData.productId);", 198 | "", 199 | "", 200 | "const newAccessToken = responseHeaders['x-access-token']", 201 | "", 202 | "if(newAccessToken){", 203 | " console.log('Set new access token')", 204 | "postman.setEnvironmentVariable(\"accessToken\", newAccessToken);", 205 | "}" 206 | ], 207 | "type": "text/javascript" 208 | } 209 | } 210 | ], 211 | "request": { 212 | "auth": { 213 | "type": "bearer", 214 | "bearer": [ 215 | { 216 | "key": "token", 217 | "value": "{{accessToken}}", 218 | "type": "string" 219 | } 220 | ] 221 | }, 222 | "method": "POST", 223 | "header": [ 224 | { 225 | "key": "x-refresh", 226 | "value": "{{refreshToken}}", 227 | "type": "text" 228 | } 229 | ], 230 | "body": { 231 | "mode": "raw", 232 | "raw": "{\n \"title\": \"Canon EOS 1500D DSLR Camera with 18-55mm Lens\",\n \"description\": \"Designed for first-time DSLR owners who want impressive results straight out of the box, capture those magic moments no matter your level with the EOS 1500D. With easy to use automatic shooting modes, large 24.1 MP sensor, Canon Camera Connect app integration and built-in feature guide, EOS 1500D is always ready to go.\",\n \"price\": 879.99,\n \"image\": \"https://i.imgur.com/QlRphfQ.jpg\"\n}", 233 | "options": { 234 | "raw": { 235 | "language": "json" 236 | } 237 | } 238 | }, 239 | "url": { 240 | "raw": "{{endpoint}}/api/products", 241 | "host": [ 242 | "{{endpoint}}" 243 | ], 244 | "path": [ 245 | "api", 246 | "products" 247 | ] 248 | } 249 | }, 250 | "response": [] 251 | }, 252 | { 253 | "name": "Get Product", 254 | "event": [ 255 | { 256 | "listen": "test", 257 | "script": { 258 | "exec": [ 259 | "" 260 | ], 261 | "type": "text/javascript" 262 | } 263 | } 264 | ], 265 | "protocolProfileBehavior": { 266 | "disableBodyPruning": true 267 | }, 268 | "request": { 269 | "method": "GET", 270 | "header": [], 271 | "body": { 272 | "mode": "raw", 273 | "raw": "{\n \"title\": \"A post title\",\n \"body\": \"Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text\"\n}", 274 | "options": { 275 | "raw": { 276 | "language": "json" 277 | } 278 | } 279 | }, 280 | "url": { 281 | "raw": "{{endpoint}}/api/products/{{productId}}", 282 | "host": [ 283 | "{{endpoint}}" 284 | ], 285 | "path": [ 286 | "api", 287 | "products", 288 | "{{productId}}" 289 | ] 290 | } 291 | }, 292 | "response": [] 293 | }, 294 | { 295 | "name": "Update Product", 296 | "event": [ 297 | { 298 | "listen": "test", 299 | "script": { 300 | "exec": [ 301 | "const newAccessToken = responseHeaders['x-access-token']", 302 | "", 303 | "if(newAccessToken){", 304 | " console.log('Set new access token')", 305 | "postman.setEnvironmentVariable(\"accessToken\", newAccessToken);", 306 | "}" 307 | ], 308 | "type": "text/javascript" 309 | } 310 | } 311 | ], 312 | "request": { 313 | "auth": { 314 | "type": "bearer", 315 | "bearer": [ 316 | { 317 | "key": "token", 318 | "value": "{{accessToken}}", 319 | "type": "string" 320 | } 321 | ] 322 | }, 323 | "method": "PUT", 324 | "header": [ 325 | { 326 | "key": "x-refresh", 327 | "value": "{{refreshToken}}", 328 | "type": "text" 329 | } 330 | ], 331 | "body": { 332 | "mode": "raw", 333 | "raw": "{\n \"title\": \"Canon EOS 1500D DSLR Camera with 18-55mm Lens\",\n \"description\": \"Designed for first-time DSLR owners who want impressive results straight out of the box, capture those magic moments no matter your level with the EOS 1500D. With easy to use automatic shooting modes, large 24.1 MP sensor, Canon Camera Connect app integration and built-in feature guide, EOS 1500D is always ready to go.\",\n \"price\": 699.99,\n \"image\": \"https://i.imgur.com/QlRphfQ.jpg\"\n}", 334 | "options": { 335 | "raw": { 336 | "language": "json" 337 | } 338 | } 339 | }, 340 | "url": { 341 | "raw": "{{endpoint}}/api/products/{{productId}}", 342 | "host": [ 343 | "{{endpoint}}" 344 | ], 345 | "path": [ 346 | "api", 347 | "products", 348 | "{{productId}}" 349 | ] 350 | } 351 | }, 352 | "response": [] 353 | }, 354 | { 355 | "name": "Delete Product", 356 | "event": [ 357 | { 358 | "listen": "test", 359 | "script": { 360 | "exec": [ 361 | "const newAccessToken = responseHeaders['x-access-token']", 362 | "", 363 | "if(newAccessToken){", 364 | " console.log('Set new access token')", 365 | "postman.setEnvironmentVariable(\"accessToken\", newAccessToken);", 366 | "}" 367 | ], 368 | "type": "text/javascript" 369 | } 370 | } 371 | ], 372 | "request": { 373 | "auth": { 374 | "type": "bearer", 375 | "bearer": [ 376 | { 377 | "key": "token", 378 | "value": "{{accessToken}}", 379 | "type": "string" 380 | } 381 | ] 382 | }, 383 | "method": "DELETE", 384 | "header": [ 385 | { 386 | "key": "x-refresh", 387 | "value": "{{refreshToken}}", 388 | "type": "text" 389 | } 390 | ], 391 | "body": { 392 | "mode": "raw", 393 | "raw": "{\n \"title\": \"A post title\",\n \"body\": \"Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text Some HTML text\"\n}", 394 | "options": { 395 | "raw": { 396 | "language": "json" 397 | } 398 | } 399 | }, 400 | "url": { 401 | "raw": "{{endpoint}}/api/products/{{productId}}", 402 | "host": [ 403 | "{{endpoint}}" 404 | ], 405 | "path": [ 406 | "api", 407 | "products", 408 | "{{productId}}" 409 | ] 410 | } 411 | }, 412 | "response": [] 413 | } 414 | ] 415 | }, 416 | { 417 | "name": "Metrics", 418 | "item": [ 419 | { 420 | "name": "Get metrics", 421 | "request": { 422 | "method": "GET", 423 | "header": [], 424 | "url": { 425 | "raw": "http://localhost:9100/metrics", 426 | "protocol": "http", 427 | "host": [ 428 | "localhost" 429 | ], 430 | "port": "9100", 431 | "path": [ 432 | "metrics" 433 | ] 434 | } 435 | }, 436 | "response": [] 437 | } 438 | ] 439 | } 440 | ], 441 | "auth": { 442 | "type": "bearer", 443 | "bearer": [ 444 | { 445 | "key": "token", 446 | "value": "{{accessToken}}", 447 | "type": "string" 448 | } 449 | ] 450 | }, 451 | "event": [ 452 | { 453 | "listen": "prerequest", 454 | "script": { 455 | "type": "text/javascript", 456 | "exec": [ 457 | "" 458 | ] 459 | } 460 | }, 461 | { 462 | "listen": "test", 463 | "script": { 464 | "type": "text/javascript", 465 | "exec": [ 466 | "" 467 | ] 468 | } 469 | } 470 | ], 471 | "variable": [ 472 | { 473 | "key": "email", 474 | "value": "test@example.com" 475 | }, 476 | { 477 | "key": "password", 478 | "value": "Password456!" 479 | }, 480 | { 481 | "key": "name", 482 | "value": "Jane Doe" 483 | }, 484 | { 485 | "key": "accessToken", 486 | "value": "" 487 | }, 488 | { 489 | "key": "refreshToken", 490 | "value": "" 491 | }, 492 | { 493 | "key": "endpoint", 494 | "value": "http://localhost:1337" 495 | }, 496 | { 497 | "key": "productId", 498 | "value": "" 499 | } 500 | ] 501 | } -------------------------------------------------------------------------------- /service-inputs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/models/product.model.ts b/src/models/product.model.ts 2 | index 4b83d65..03d548f 100644 3 | --- a/src/models/product.model.ts 4 | +++ b/src/models/product.model.ts 5 | @@ -4,12 +4,15 @@ import { UserDocument } from "./user.model"; 6 | 7 | const nanoid = customAlphabet("abcdefghijklmnopqrstuvwxyz0123456789", 10); 8 | 9 | -export interface ProductDocument extends mongoose.Document { 10 | +export interface ProductInput { 11 | user: UserDocument["_id"]; 12 | title: string; 13 | description: string; 14 | price: number; 15 | image: string; 16 | +} 17 | + 18 | +export interface ProductDocument extends ProductInput, mongoose.Document { 19 | createdAt: Date; 20 | updatedAt: Date; 21 | } 22 | diff --git a/src/models/user.model.ts b/src/models/user.model.ts 23 | index ce6ea8f..37dfbc0 100644 24 | --- a/src/models/user.model.ts 25 | +++ b/src/models/user.model.ts 26 | @@ -2,10 +2,13 @@ import mongoose from "mongoose"; 27 | import bcrypt from "bcrypt"; 28 | import config from "config"; 29 | 30 | -export interface UserDocument extends mongoose.Document { 31 | +export interface UserInput { 32 | email: string; 33 | name: string; 34 | password: string; 35 | +} 36 | + 37 | +export interface UserDocument extends UserInput, mongoose.Document { 38 | createdAt: Date; 39 | updatedAt: Date; 40 | comparePassword(candidatePassword: string): Promise; 41 | diff --git a/src/service/product.service.ts b/src/service/product.service.ts 42 | index 2dad4ca..b382b4b 100644 43 | --- a/src/service/product.service.ts 44 | +++ b/src/service/product.service.ts 45 | @@ -1,14 +1,10 @@ 46 | -import { 47 | - DocumentDefinition, 48 | - FilterQuery, 49 | - QueryOptions, 50 | - UpdateQuery, 51 | -} from "mongoose"; 52 | -import ProductModel, { ProductDocument } from "../models/product.model"; 53 | +import { FilterQuery, QueryOptions, UpdateQuery } from "mongoose"; 54 | +import ProductModel, { 55 | + ProductDocument, 56 | + ProductInput, 57 | +} from "../models/product.model"; 58 | 59 | -export async function createProduct( 60 | - input: DocumentDefinition> 61 | -) { 62 | +export async function createProduct(input: ProductInput) { 63 | return ProductModel.create(input); 64 | } 65 | 66 | diff --git a/src/service/user.service.ts b/src/service/user.service.ts 67 | index 7dee694..af904d0 100644 68 | --- a/src/service/user.service.ts 69 | +++ b/src/service/user.service.ts 70 | @@ -1,12 +1,8 @@ 71 | -import { DocumentDefinition, FilterQuery } from "mongoose"; 72 | +import { FilterQuery } from "mongoose"; 73 | import { omit } from "lodash"; 74 | -import UserModel, { UserDocument } from "../models/user.model"; 75 | +import UserModel, { UserDocument, UserInput } from "../models/user.model"; 76 | 77 | -export async function createUser( 78 | - input: DocumentDefinition< 79 | - Omit 80 | - > 81 | -) { 82 | +export async function createUser(input: UserInput) { 83 | try { 84 | const user = await UserModel.create(input); 85 | 86 | -------------------------------------------------------------------------------- /src/app.ts: -------------------------------------------------------------------------------- 1 | import express, { Request, Response } from "express"; 2 | import dotenv from "dotenv"; 3 | dotenv.config(); 4 | import config from "config"; 5 | import responseTime from "response-time"; 6 | import connect from "./utils/connect"; 7 | import logger from "./utils/logger"; 8 | import routes from "./routes"; 9 | import deserializeUser from "./middleware/deserializeUser"; 10 | import { restResponseTimeHistogram, startMetricsServer } from "./utils/metrics"; 11 | import swaggerDocs from "./utils/swagger"; 12 | 13 | const port = config.get("port"); 14 | 15 | const app = express(); 16 | 17 | app.use(express.json()); 18 | 19 | app.use(deserializeUser); 20 | 21 | app.use( 22 | responseTime((req: Request, res: Response, time: number) => { 23 | if (req?.route?.path) { 24 | restResponseTimeHistogram.observe( 25 | { 26 | method: req.method, 27 | route: req.route.path, 28 | status_code: res.statusCode, 29 | }, 30 | time * 1000 31 | ); 32 | } 33 | }) 34 | ); 35 | 36 | app.listen(port, async () => { 37 | logger.info(`App is running at http://localhost:${port}`); 38 | 39 | await connect(); 40 | 41 | routes(app); 42 | 43 | startMetricsServer(); 44 | 45 | swaggerDocs(app, port); 46 | }); 47 | -------------------------------------------------------------------------------- /src/controller/product.controller.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { 3 | CreateProductInput, 4 | UpdateProductInput, 5 | } from "../schema/product.schema"; 6 | import { 7 | createProduct, 8 | deleteProduct, 9 | findAndUpdateProduct, 10 | findProduct, 11 | } from "../service/product.service"; 12 | 13 | export async function createProductHandler( 14 | req: Request<{}, {}, CreateProductInput["body"]>, 15 | res: Response 16 | ) { 17 | const userId = res.locals.user._id; 18 | 19 | const body = req.body; 20 | 21 | const product = await createProduct({ ...body, user: userId }); 22 | 23 | return res.send(product); 24 | } 25 | 26 | export async function updateProductHandler( 27 | req: Request, 28 | res: Response 29 | ) { 30 | const userId = res.locals.user._id; 31 | 32 | const productId = req.params.productId; 33 | const update = req.body; 34 | 35 | const product = await findProduct({ productId }); 36 | 37 | if (!product) { 38 | return res.sendStatus(404); 39 | } 40 | 41 | if (String(product.user) !== userId) { 42 | return res.sendStatus(403); 43 | } 44 | 45 | const updatedProduct = await findAndUpdateProduct({ productId }, update, { 46 | new: true, 47 | }); 48 | 49 | return res.send(updatedProduct); 50 | } 51 | 52 | export async function getProductHandler( 53 | req: Request, 54 | res: Response 55 | ) { 56 | const productId = req.params.productId; 57 | const product = await findProduct({ productId }); 58 | 59 | if (!product) { 60 | return res.sendStatus(404); 61 | } 62 | 63 | return res.send(product); 64 | } 65 | 66 | export async function deleteProductHandler( 67 | req: Request, 68 | res: Response 69 | ) { 70 | const userId = res.locals.user._id; 71 | const productId = req.params.productId; 72 | 73 | const product = await findProduct({ productId }); 74 | 75 | if (!product) { 76 | return res.sendStatus(404); 77 | } 78 | 79 | if (String(product.user) !== userId) { 80 | return res.sendStatus(403); 81 | } 82 | 83 | await deleteProduct({ productId }); 84 | 85 | return res.sendStatus(200); 86 | } 87 | -------------------------------------------------------------------------------- /src/controller/session.controller.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import config from "config"; 3 | import { 4 | createSession, 5 | findSessions, 6 | updateSession, 7 | } from "../service/session.service"; 8 | import { validatePassword } from "../service/user.service"; 9 | import { signJwt } from "../utils/jwt.utils"; 10 | 11 | export async function createUserSessionHandler(req: Request, res: Response) { 12 | // Validate the user's password 13 | const user = await validatePassword(req.body); 14 | 15 | if (!user) { 16 | return res.status(401).send("Invalid email or password"); 17 | } 18 | 19 | // create a session 20 | const session = await createSession(user._id, req.get("user-agent") || ""); 21 | 22 | // create an access token 23 | 24 | const accessToken = signJwt( 25 | { ...user, session: session._id }, 26 | "accessTokenPrivateKey", 27 | { expiresIn: config.get("accessTokenTtl") } // 15 minutes, 28 | ); 29 | 30 | // create a refresh token 31 | const refreshToken = signJwt( 32 | { ...user, session: session._id }, 33 | "refreshTokenPrivateKey", 34 | { expiresIn: config.get("refreshTokenTtl") } // 15 minutes 35 | ); 36 | 37 | // return access & refresh tokens 38 | 39 | return res.send({ accessToken, refreshToken }); 40 | } 41 | 42 | export async function getUserSessionsHandler(req: Request, res: Response) { 43 | const userId = res.locals.user._id; 44 | 45 | const sessions = await findSessions({ user: userId, valid: true }); 46 | 47 | return res.send(sessions); 48 | } 49 | 50 | export async function deleteSessionHandler(req: Request, res: Response) { 51 | const sessionId = res.locals.user.session; 52 | 53 | await updateSession({ _id: sessionId }, { valid: false }); 54 | 55 | return res.send({ 56 | accessToken: null, 57 | refreshToken: null, 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /src/controller/user.controller.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { omit } from "lodash"; 3 | import { CreateUserInput } from "../schema/user.schema"; 4 | import { createUser } from "../service/user.service"; 5 | import logger from "../utils/logger"; 6 | 7 | export async function createUserHandler( 8 | req: Request<{}, {}, CreateUserInput["body"]>, 9 | res: Response 10 | ) { 11 | try { 12 | const user = await createUser(req.body); 13 | return res.send(user); 14 | } catch (e: any) { 15 | logger.error(e); 16 | return res.status(409).send(e.message); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/middleware/deserializeUser.ts: -------------------------------------------------------------------------------- 1 | import { get } from "lodash"; 2 | import { Request, Response, NextFunction } from "express"; 3 | import { verifyJwt } from "../utils/jwt.utils"; 4 | import { reIssueAccessToken } from "../service/session.service"; 5 | 6 | const deserializeUser = async ( 7 | req: Request, 8 | res: Response, 9 | next: NextFunction 10 | ) => { 11 | const accessToken = get(req, "headers.authorization", "").replace( 12 | /^Bearer\s/, 13 | "" 14 | ); 15 | 16 | const refreshToken = get(req, "headers.x-refresh"); 17 | 18 | if (!accessToken) { 19 | return next(); 20 | } 21 | 22 | const { decoded, expired } = verifyJwt(accessToken, "accessTokenPublicKey"); 23 | 24 | if (decoded) { 25 | res.locals.user = decoded; 26 | return next(); 27 | } 28 | 29 | if (expired && refreshToken) { 30 | const newAccessToken = await reIssueAccessToken({ refreshToken }); 31 | 32 | if (newAccessToken) { 33 | res.setHeader("x-access-token", newAccessToken); 34 | } 35 | 36 | const result = verifyJwt(newAccessToken as string, "accessTokenPublicKey"); 37 | 38 | res.locals.user = result.decoded; 39 | return next(); 40 | } 41 | 42 | return next(); 43 | }; 44 | 45 | export default deserializeUser; 46 | -------------------------------------------------------------------------------- /src/middleware/requireUser.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | 3 | const requireUser = (req: Request, res: Response, next: NextFunction) => { 4 | const user = res.locals.user; 5 | 6 | if (!user) { 7 | return res.sendStatus(403); 8 | } 9 | 10 | return next(); 11 | }; 12 | 13 | export default requireUser; 14 | -------------------------------------------------------------------------------- /src/middleware/validateResource.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response, NextFunction } from "express"; 2 | import { AnyZodObject } from "zod"; 3 | 4 | const validate = 5 | (schema: AnyZodObject) => 6 | (req: Request, res: Response, next: NextFunction) => { 7 | try { 8 | schema.parse({ 9 | body: req.body, 10 | query: req.query, 11 | params: req.params, 12 | }); 13 | next(); 14 | } catch (e: any) { 15 | return res.status(400).send(e.errors); 16 | } 17 | }; 18 | 19 | export default validate; 20 | -------------------------------------------------------------------------------- /src/models/product.model.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | import { customAlphabet } from "nanoid"; 3 | import { UserDocument } from "./user.model"; 4 | 5 | const nanoid = customAlphabet("abcdefghijklmnopqrstuvwxyz0123456789", 10); 6 | 7 | export interface ProductInput { 8 | user: UserDocument["_id"]; 9 | title: string; 10 | description: string; 11 | price: number; 12 | image: string; 13 | } 14 | 15 | export interface ProductDocument extends ProductInput, mongoose.Document { 16 | createdAt: Date; 17 | updatedAt: Date; 18 | } 19 | 20 | const productSchema = new mongoose.Schema( 21 | { 22 | productId: { 23 | type: String, 24 | required: true, 25 | unique: true, 26 | default: () => `product_${nanoid()}`, 27 | }, 28 | user: { type: mongoose.Schema.Types.ObjectId, ref: "User" }, 29 | title: { type: String, required: true }, 30 | description: { type: String, required: true }, 31 | price: { type: Number, required: true }, 32 | image: { type: String, required: true }, 33 | }, 34 | { 35 | timestamps: true, 36 | } 37 | ); 38 | 39 | const ProductModel = mongoose.model("Product", productSchema); 40 | 41 | export default ProductModel; 42 | -------------------------------------------------------------------------------- /src/models/session.model.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | import { UserDocument } from "./user.model"; 3 | 4 | export interface SessionDocument extends mongoose.Document { 5 | user: UserDocument["_id"]; 6 | valid: boolean; 7 | userAgent: string; 8 | createdAt: Date; 9 | updatedAt: Date; 10 | } 11 | 12 | const sessionSchema = new mongoose.Schema( 13 | { 14 | user: { type: mongoose.Schema.Types.ObjectId, ref: "User" }, 15 | valid: { type: Boolean, default: true }, 16 | userAgent: { type: String }, 17 | }, 18 | { 19 | timestamps: true, 20 | } 21 | ); 22 | 23 | const SessionModel = mongoose.model("Session", sessionSchema); 24 | 25 | export default SessionModel; 26 | -------------------------------------------------------------------------------- /src/models/user.model.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | import bcrypt from "bcrypt"; 3 | import config from "config"; 4 | 5 | export interface UserInput { 6 | email: string; 7 | name: string; 8 | password: string; 9 | } 10 | 11 | export interface UserDocument extends UserInput, mongoose.Document { 12 | createdAt: Date; 13 | updatedAt: Date; 14 | comparePassword(candidatePassword: string): Promise; 15 | } 16 | 17 | const userSchema = new mongoose.Schema( 18 | { 19 | email: { type: String, required: true, unique: true }, 20 | name: { type: String, required: true }, 21 | password: { type: String, required: true }, 22 | }, 23 | { 24 | timestamps: true, 25 | } 26 | ); 27 | 28 | userSchema.pre("save", async function (next) { 29 | let user = this as UserDocument; 30 | 31 | if (!user.isModified("password")) { 32 | return next(); 33 | } 34 | 35 | const salt = await bcrypt.genSalt(config.get("saltWorkFactor")); 36 | 37 | const hash = await bcrypt.hashSync(user.password, salt); 38 | 39 | user.password = hash; 40 | 41 | return next(); 42 | }); 43 | 44 | userSchema.methods.comparePassword = async function ( 45 | candidatePassword: string 46 | ): Promise { 47 | const user = this as UserDocument; 48 | 49 | return bcrypt.compare(candidatePassword, user.password).catch((e) => false); 50 | }; 51 | 52 | const UserModel = mongoose.model("User", userSchema); 53 | 54 | export default UserModel; 55 | -------------------------------------------------------------------------------- /src/routes.ts: -------------------------------------------------------------------------------- 1 | import { Express, Request, Response } from "express"; 2 | import { 3 | createProductHandler, 4 | getProductHandler, 5 | updateProductHandler, 6 | deleteProductHandler, 7 | } from "./controller/product.controller"; 8 | import { 9 | createUserSessionHandler, 10 | getUserSessionsHandler, 11 | deleteSessionHandler, 12 | } from "./controller/session.controller"; 13 | import { createUserHandler } from "./controller/user.controller"; 14 | import requireUser from "./middleware/requireUser"; 15 | import validateResource from "./middleware/validateResource"; 16 | import { 17 | createProductSchema, 18 | deleteProductSchema, 19 | getProductSchema, 20 | updateProductSchema, 21 | } from "./schema/product.schema"; 22 | import { createSessionSchema } from "./schema/session.schema"; 23 | import { createUserSchema } from "./schema/user.schema"; 24 | 25 | function routes(app: Express) { 26 | /** 27 | * @openapi 28 | * /healthcheck: 29 | * get: 30 | * tags: 31 | * - Healthcheck 32 | * description: Responds if the app is up and running 33 | * responses: 34 | * 200: 35 | * description: App is up and running 36 | */ 37 | app.get("/healthcheck", (req: Request, res: Response) => res.sendStatus(200)); 38 | 39 | /** 40 | * @openapi 41 | * '/api/users': 42 | * post: 43 | * tags: 44 | * - User 45 | * summary: Register a user 46 | * requestBody: 47 | * required: true 48 | * content: 49 | * application/json: 50 | * schema: 51 | * $ref: '#/components/schemas/CreateUserInput' 52 | * responses: 53 | * 200: 54 | * description: Success 55 | * content: 56 | * application/json: 57 | * schema: 58 | * $ref: '#/components/schemas/CreateUserResponse' 59 | * 409: 60 | * description: Conflict 61 | * 400: 62 | * description: Bad request 63 | */ 64 | app.post("/api/users", validateResource(createUserSchema), createUserHandler); 65 | 66 | /** 67 | * @openapi 68 | * '/api/sessions': 69 | * get: 70 | * tags: 71 | * - Session 72 | * summary: Get all sessions 73 | * responses: 74 | * 200: 75 | * description: Get all sessions for current user 76 | * content: 77 | * application/json: 78 | * schema: 79 | * $ref: '#/components/schemas/GetSessionResponse' 80 | * 403: 81 | * description: Forbidden 82 | * post: 83 | * tags: 84 | * - Session 85 | * summary: Create a session 86 | * requestBody: 87 | * required: true 88 | * content: 89 | * application/json: 90 | * schema: 91 | * $ref: '#/components/schemas/CreateSessionInput' 92 | * responses: 93 | * 200: 94 | * description: Session created 95 | * content: 96 | * application/json: 97 | * schema: 98 | * $ref: '#/components/schemas/CreateSessionResponse' 99 | * 401: 100 | * description: Unauthorized 101 | * delete: 102 | * tags: 103 | * - Session 104 | * summary: Delete a session 105 | * responses: 106 | * 200: 107 | * description: Session deleted 108 | * 403: 109 | * description: Forbidden 110 | */ 111 | app.post( 112 | "/api/sessions", 113 | validateResource(createSessionSchema), 114 | createUserSessionHandler 115 | ); 116 | 117 | app.get("/api/sessions", requireUser, getUserSessionsHandler); 118 | 119 | app.delete("/api/sessions", requireUser, deleteSessionHandler); 120 | 121 | /** 122 | * @openapi 123 | * '/api/products': 124 | * post: 125 | * tags: 126 | * - Products 127 | * summary: Create a new product 128 | * requestBody: 129 | * required: true 130 | * content: 131 | * application/json: 132 | * schema: 133 | * $ref: '#/components/schema/Product' 134 | * responses: 135 | * 200: 136 | * description: Product created 137 | * content: 138 | * application/json: 139 | * schema: 140 | * $ref: '#/components/schema/productResponse' 141 | * example: 142 | * "user": "642a0de05f16e6dad68efdad" 143 | * "title": "Canon EOS 1500D DSLR Camera with 18-55mm Lens" 144 | * "description": "Designed for first-time DSLR owners who want impressive results straight out of the box, capture those magic moments no matter your level with the EOS 1500D. With easy to use automatic shooting modes, large 24.1 MP sensor, Canon Camera Connect app integration and built-in feature guide, EOS 1500D is always ready to go." 145 | * "price": 879.99 146 | * "image": "https://i.imgur.com/QlRphfQ.jpg" 147 | * "_id": "642a1cfcc1bec76d8a2e7ac2" 148 | * "productId": "product_xxqm8z3eho" 149 | * "createdAt": "2023-04-03T00:25:32.189Z" 150 | * "updatedAt": "2023-04-03T00:25:32.189Z" 151 | * "__v": 0 152 | */ 153 | app.post( 154 | "/api/products", 155 | [requireUser, validateResource(createProductSchema)], 156 | createProductHandler 157 | ); 158 | 159 | /** 160 | * @openapi 161 | * '/api/products/{productId}': 162 | * get: 163 | * tags: 164 | * - Products 165 | * summary: Get a single product by the productId 166 | * parameters: 167 | * - name: productId 168 | * in: path 169 | * description: The id of the product 170 | * required: true 171 | * responses: 172 | * 200: 173 | * description: Success 174 | * content: 175 | * application/json: 176 | * schema: 177 | * $ref: '#/components/schema/productResponse' 178 | * 404: 179 | * description: Product not found 180 | * put: 181 | * tags: 182 | * - Products 183 | * summary: Update a single product 184 | * parameters: 185 | * - name: productId 186 | * in: path 187 | * description: The id of the product 188 | * required: true 189 | * requestBody: 190 | * required: true 191 | * content: 192 | * application/json: 193 | * schema: 194 | * $ref: '#/components/schema/Product' 195 | * responses: 196 | * 200: 197 | * description: Success 198 | * content: 199 | * application/json: 200 | * schema: 201 | * $ref: '#/components/schema/productResponse' 202 | * 403: 203 | * description: Forbidden 204 | * 404: 205 | * description: Product not found 206 | * delete: 207 | * tags: 208 | * - Products 209 | * summary: Delete a single product 210 | * parameters: 211 | * - name: productId 212 | * in: path 213 | * description: The id of the product 214 | * required: true 215 | * responses: 216 | * 200: 217 | * description: Product deleted 218 | * 403: 219 | * description: Forbidden 220 | * 404: 221 | * description: Product not found 222 | */ 223 | app.put( 224 | "/api/products/:productId", 225 | [requireUser, validateResource(updateProductSchema)], 226 | updateProductHandler 227 | ); 228 | 229 | app.get( 230 | "/api/products/:productId", 231 | validateResource(getProductSchema), 232 | getProductHandler 233 | ); 234 | 235 | app.delete( 236 | "/api/products/:productId", 237 | [requireUser, validateResource(deleteProductSchema)], 238 | deleteProductHandler 239 | ); 240 | } 241 | 242 | export default routes; 243 | -------------------------------------------------------------------------------- /src/schema/product.schema.ts: -------------------------------------------------------------------------------- 1 | import { object, number, string, TypeOf } from "zod"; 2 | 3 | /** 4 | * @openapi 5 | * components: 6 | * schema: 7 | * Product: 8 | * type: object 9 | * required: 10 | * - title 11 | * - description 12 | * - price 13 | * - image 14 | * properties: 15 | * title: 16 | * type: string 17 | * default: "Canon EOS 1500D DSLR Camera with 18-55mm Lens" 18 | * description: 19 | * type: string 20 | * default: "Designed for first-time DSLR owners who want impressive results straight out of the box, capture those magic moments no matter your level with the EOS 1500D. With easy to use automatic shooting modes, large 24.1 MP sensor, Canon Camera Connect app integration and built-in feature guide, EOS 1500D is always ready to go." 21 | * price: 22 | * type: number 23 | * default: 879.99 24 | * image: 25 | * type: string 26 | * default: "https://i.imgur.com/QlRphfQ.jpg" 27 | * productResponse: 28 | * type: object 29 | * properties: 30 | * user: 31 | * type: string 32 | * _id: 33 | * type: string 34 | * title: 35 | * type: string 36 | * description: 37 | * type: string 38 | * price: 39 | * type: number 40 | * image: 41 | * type: string 42 | * productId: 43 | * type: string 44 | * createdAt: 45 | * type: string 46 | * updatedAt: 47 | * type: string 48 | * __v: 49 | * type: number 50 | * 51 | */ 52 | 53 | const payload = { 54 | body: object({ 55 | title: string({ 56 | required_error: "Title is required", 57 | }), 58 | description: string({ 59 | required_error: "Description is required", 60 | }).min(120, "Description should be at least 120 characters long"), 61 | price: number({ 62 | required_error: "Price is required", 63 | }), 64 | image: string({ 65 | required_error: "Image is required", 66 | }), 67 | }), 68 | }; 69 | 70 | const params = { 71 | params: object({ 72 | productId: string({ 73 | required_error: "productId is required", 74 | }), 75 | }), 76 | }; 77 | 78 | export const createProductSchema = object({ 79 | ...payload, 80 | }); 81 | 82 | export const updateProductSchema = object({ 83 | ...payload, 84 | ...params, 85 | }); 86 | 87 | export const deleteProductSchema = object({ 88 | ...params, 89 | }); 90 | 91 | export const getProductSchema = object({ 92 | ...params, 93 | }); 94 | 95 | export type CreateProductInput = TypeOf; 96 | export type UpdateProductInput = TypeOf; 97 | export type ReadProductInput = TypeOf; 98 | export type DeleteProductInput = TypeOf; 99 | -------------------------------------------------------------------------------- /src/schema/session.schema.ts: -------------------------------------------------------------------------------- 1 | import { object, string } from "zod"; 2 | 3 | /** 4 | * @openapi 5 | * components: 6 | * schemas: 7 | * GetSessionResponse: 8 | * type: array 9 | * items: 10 | * type: object 11 | * required: 12 | * - user 13 | * - valid 14 | * - userAgent 15 | * - createdAt 16 | * - updatedAt 17 | * properties: 18 | * _id: 19 | * type: string 20 | * user: 21 | * type: string 22 | * valid: 23 | * type: boolean 24 | * userAgent: 25 | * type: string 26 | * createdAt: 27 | * type: string 28 | * updatedAt: 29 | * type: string 30 | * __v: 31 | * type: number 32 | * CreateSessionInput: 33 | * type: object 34 | * required: 35 | * - email 36 | * - password 37 | * properties: 38 | * email: 39 | * type: string 40 | * default: jane.doe@example.com 41 | * password: 42 | * type: string 43 | * default: stringPassword123 44 | * CreateSessionResponse: 45 | * type: object 46 | * required: 47 | * - accessToken 48 | * - refreshToken 49 | * properties: 50 | * accessToken: 51 | * type: string 52 | * refreshToken: 53 | * type: string 54 | */ 55 | 56 | export const createSessionSchema = object({ 57 | body: object({ 58 | email: string({ 59 | required_error: "Email is required", 60 | }), 61 | password: string({ 62 | required_error: "Password is required", 63 | }), 64 | }), 65 | }); 66 | -------------------------------------------------------------------------------- /src/schema/user.schema.ts: -------------------------------------------------------------------------------- 1 | import { object, string, TypeOf } from "zod"; 2 | 3 | /** 4 | * @openapi 5 | * components: 6 | * schemas: 7 | * CreateUserInput: 8 | * type: object 9 | * required: 10 | * - email 11 | * - name 12 | * - password 13 | * - passwordConfirmation 14 | * properties: 15 | * email: 16 | * type: string 17 | * default: jane.doe@example.com 18 | * name: 19 | * type: string 20 | * default: Jane Doe 21 | * password: 22 | * type: string 23 | * default: stringPassword123 24 | * passwordConfirmation: 25 | * type: string 26 | * default: stringPassword123 27 | * CreateUserResponse: 28 | * type: object 29 | * properties: 30 | * email: 31 | * type: string 32 | * name: 33 | * type: string 34 | * _id: 35 | * type: string 36 | * createdAt: 37 | * type: string 38 | * updatedAt: 39 | * type: string 40 | */ 41 | 42 | export const createUserSchema = object({ 43 | body: object({ 44 | name: string({ 45 | required_error: "Name is required", 46 | }), 47 | password: string({ 48 | required_error: "Password is required", 49 | }).min(6, "Password too short - should be 6 chars minimum"), 50 | passwordConfirmation: string({ 51 | required_error: "passwordConfirmation is required", 52 | }), 53 | email: string({ 54 | required_error: "Email is required", 55 | }).email("Not a valid email"), 56 | }).refine((data) => data.password === data.passwordConfirmation, { 57 | message: "Passwords do not match", 58 | path: ["passwordConfirmation"], 59 | }), 60 | }); 61 | 62 | export type CreateUserInput = Omit< 63 | TypeOf, 64 | "body.passwordConfirmation" 65 | >; 66 | -------------------------------------------------------------------------------- /src/service/product.service.ts: -------------------------------------------------------------------------------- 1 | import { FilterQuery, QueryOptions, UpdateQuery } from "mongoose"; 2 | import ProductModel, { 3 | ProductDocument, 4 | ProductInput, 5 | } from "../models/product.model"; 6 | import { databaseResponseTimeHistogram } from "../utils/metrics"; 7 | 8 | export async function createProduct(input: ProductInput) { 9 | const metricsLabels = { 10 | operation: "createProduct", 11 | }; 12 | 13 | const timer = databaseResponseTimeHistogram.startTimer(); 14 | try { 15 | const result = await ProductModel.create(input); 16 | timer({ ...metricsLabels, success: "true" }); 17 | return result; 18 | } catch (e) { 19 | timer({ ...metricsLabels, success: "false" }); 20 | throw e; 21 | } 22 | } 23 | 24 | export async function findProduct( 25 | query: FilterQuery, 26 | options: QueryOptions = { lean: true } 27 | ) { 28 | const metricsLabels = { 29 | operation: "findProduct", 30 | }; 31 | 32 | const timer = databaseResponseTimeHistogram.startTimer(); 33 | try { 34 | const result = await ProductModel.findOne(query, {}, options); 35 | timer({ ...metricsLabels, success: "true" }); 36 | return result; 37 | } catch (e) { 38 | timer({ ...metricsLabels, success: "false" }); 39 | 40 | throw e; 41 | } 42 | } 43 | 44 | export async function findAndUpdateProduct( 45 | query: FilterQuery, 46 | update: UpdateQuery, 47 | options: QueryOptions 48 | ) { 49 | return ProductModel.findOneAndUpdate(query, update, options); 50 | } 51 | 52 | export async function deleteProduct(query: FilterQuery) { 53 | return ProductModel.deleteOne(query); 54 | } 55 | -------------------------------------------------------------------------------- /src/service/session.service.ts: -------------------------------------------------------------------------------- 1 | import { get } from "lodash"; 2 | import config from "config"; 3 | import { FilterQuery, UpdateQuery } from "mongoose"; 4 | import SessionModel, { SessionDocument } from "../models/session.model"; 5 | import { verifyJwt, signJwt } from "../utils/jwt.utils"; 6 | import { findUser } from "./user.service"; 7 | 8 | export async function createSession(userId: string, userAgent: string) { 9 | const session = await SessionModel.create({ user: userId, userAgent }); 10 | 11 | return session.toJSON(); 12 | } 13 | 14 | export async function findSessions(query: FilterQuery) { 15 | return SessionModel.find(query).lean(); 16 | } 17 | 18 | export async function updateSession( 19 | query: FilterQuery, 20 | update: UpdateQuery 21 | ) { 22 | return SessionModel.updateOne(query, update); 23 | } 24 | 25 | export async function reIssueAccessToken({ 26 | refreshToken, 27 | }: { 28 | refreshToken: string; 29 | }) { 30 | const { decoded } = verifyJwt(refreshToken, "refreshTokenPublicKey"); 31 | 32 | if (!decoded || !get(decoded, "session")) return false; 33 | 34 | const session = await SessionModel.findById(get(decoded, "session")); 35 | 36 | if (!session || !session.valid) return false; 37 | 38 | const user = await findUser({ _id: session.user }); 39 | 40 | if (!user) return false; 41 | 42 | const accessToken = signJwt( 43 | { ...user, session: session._id }, 44 | "accessTokenPrivateKey", 45 | { expiresIn: config.get("accessTokenTtl") } // 15 minutes 46 | ); 47 | 48 | return accessToken; 49 | } 50 | -------------------------------------------------------------------------------- /src/service/user.service.ts: -------------------------------------------------------------------------------- 1 | import { FilterQuery } from "mongoose"; 2 | import { omit } from "lodash"; 3 | import UserModel, { UserDocument, UserInput } from "../models/user.model"; 4 | 5 | export async function createUser(input: UserInput) { 6 | try { 7 | const user = await UserModel.create(input); 8 | 9 | return omit(user.toJSON(), "password"); 10 | } catch (e: any) { 11 | throw new Error(e); 12 | } 13 | } 14 | 15 | export async function validatePassword({ 16 | email, 17 | password, 18 | }: { 19 | email: string; 20 | password: string; 21 | }) { 22 | const user = await UserModel.findOne({ email }); 23 | 24 | if (!user) { 25 | return false; 26 | } 27 | 28 | const isValid = await user.comparePassword(password); 29 | 30 | if (!isValid) return false; 31 | 32 | return omit(user.toJSON(), "password"); 33 | } 34 | 35 | export async function findUser(query: FilterQuery) { 36 | return UserModel.findOne(query).lean(); 37 | } 38 | -------------------------------------------------------------------------------- /src/utils/connect.ts: -------------------------------------------------------------------------------- 1 | import mongoose from "mongoose"; 2 | import config from "config"; 3 | import logger from "./logger"; 4 | 5 | async function connect() { 6 | const dbUri = config.get("dbUri"); 7 | 8 | try { 9 | await mongoose.connect(dbUri); 10 | logger.info("DB connected"); 11 | } catch (error) { 12 | logger.error("Could not connect to db"); 13 | process.exit(1); 14 | } 15 | } 16 | 17 | export default connect; 18 | -------------------------------------------------------------------------------- /src/utils/jwt.utils.ts: -------------------------------------------------------------------------------- 1 | import jwt from "jsonwebtoken"; 2 | import config from "config"; 3 | 4 | export function signJwt( 5 | object: Object, 6 | keyName: "accessTokenPrivateKey" | "refreshTokenPrivateKey", 7 | options?: jwt.SignOptions | undefined 8 | ) { 9 | const signingKey = Buffer.from( 10 | config.get(keyName), 11 | "base64" 12 | ).toString("ascii"); 13 | 14 | return jwt.sign(object, signingKey, { 15 | ...(options && options), 16 | algorithm: "RS256", 17 | }); 18 | } 19 | 20 | export function verifyJwt( 21 | token: string, 22 | keyName: "accessTokenPublicKey" | "refreshTokenPublicKey" 23 | ) { 24 | const publicKey = Buffer.from(config.get(keyName), "base64").toString( 25 | "ascii" 26 | ); 27 | 28 | try { 29 | const decoded = jwt.verify(token, publicKey); 30 | return { 31 | valid: true, 32 | expired: false, 33 | decoded, 34 | }; 35 | } catch (e: any) { 36 | console.error(e); 37 | return { 38 | valid: false, 39 | expired: e.message === "jwt expired", 40 | decoded: null, 41 | }; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import logger from "pino"; 2 | import dayjs from "dayjs"; 3 | 4 | const log = logger({ 5 | prettyPrint: true, 6 | base: { 7 | pid: false, 8 | }, 9 | timestamp: () => `,"time":"${dayjs().format()}"`, 10 | }); 11 | 12 | export default log; 13 | -------------------------------------------------------------------------------- /src/utils/metrics.ts: -------------------------------------------------------------------------------- 1 | import express from "express"; 2 | import client from "prom-client"; 3 | import log from "./logger"; 4 | 5 | const app = express(); 6 | 7 | export const restResponseTimeHistogram = new client.Histogram({ 8 | name: "rest_response_time_duration_seconds", 9 | help: "REST API response time in seconds", 10 | labelNames: ["method", "route", "status_code"], 11 | }); 12 | 13 | export const databaseResponseTimeHistogram = new client.Histogram({ 14 | name: "db_response_time_duration_seconds", 15 | help: "Database response time in seconds", 16 | labelNames: ["operation", "success"], 17 | }); 18 | 19 | export function startMetricsServer() { 20 | const collectDefaultMetrics = client.collectDefaultMetrics; 21 | 22 | collectDefaultMetrics(); 23 | 24 | app.get("/metrics", async (req, res) => { 25 | res.set("Content-Type", client.register.contentType); 26 | 27 | return res.send(await client.register.metrics()); 28 | }); 29 | 30 | app.listen(9100, () => { 31 | log.info("Metrics server started at http://localhost:9100"); 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/swagger.ts: -------------------------------------------------------------------------------- 1 | import { Express, Request, Response } from "express"; 2 | import swaggerJsdoc from "swagger-jsdoc"; 3 | import swaggerUi from "swagger-ui-express"; 4 | import { version } from "../../package.json"; 5 | import log from "./logger"; 6 | 7 | const options: swaggerJsdoc.Options = { 8 | definition: { 9 | openapi: "3.0.0", 10 | info: { 11 | title: "REST API Docs", 12 | version, 13 | }, 14 | components: { 15 | securitySchemes: { 16 | bearerAuth: { 17 | type: "http", 18 | scheme: "bearer", 19 | bearerFormat: "JWT", 20 | }, 21 | }, 22 | }, 23 | security: [ 24 | { 25 | bearerAuth: [], 26 | }, 27 | ], 28 | }, 29 | apis: ["./src/routes.ts", "./src/schema/*.ts"], 30 | }; 31 | 32 | const swaggerSpec = swaggerJsdoc(options); 33 | 34 | function swaggerDocs(app: Express, port: number) { 35 | // Swagger page 36 | app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec)); 37 | 38 | // Docs in JSON format 39 | app.get("/docs.json", (req: Request, res: Response) => { 40 | res.setHeader("Content-Type", "application/json"); 41 | res.send(swaggerSpec); 42 | }); 43 | 44 | log.info(`Docs available at http://localhost:${port}/docs`); 45 | } 46 | 47 | export default swaggerDocs; 48 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | "outDir": "build", 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "es5" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "commonjs" /* Specify what module code is generated. */, 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | "resolveJsonModule": true /* Enable importing .json files */, 37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | // "noEmit": true, /* Disable emitting files from a compilation. */ 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | 68 | /* Interop Constraints */ 69 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 70 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 71 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, 72 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 73 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 74 | 75 | /* Type Checking */ 76 | "strict": true /* Enable all strict type-checking options. */, 77 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 78 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 79 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 80 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 81 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 82 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 83 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 84 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 85 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 86 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 87 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 88 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 89 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 90 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 91 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 92 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 93 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 94 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 95 | 96 | /* Completeness */ 97 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 98 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@apidevtools/json-schema-ref-parser@^9.0.6": 6 | version "9.0.9" 7 | resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b" 8 | integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w== 9 | dependencies: 10 | "@jsdevtools/ono" "^7.1.3" 11 | "@types/json-schema" "^7.0.6" 12 | call-me-maybe "^1.0.1" 13 | js-yaml "^4.1.0" 14 | 15 | "@apidevtools/openapi-schemas@^2.0.4": 16 | version "2.1.0" 17 | resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" 18 | integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== 19 | 20 | "@apidevtools/swagger-methods@^3.0.2": 21 | version "3.0.2" 22 | resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" 23 | integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== 24 | 25 | "@apidevtools/swagger-parser@10.0.2": 26 | version "10.0.2" 27 | resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.2.tgz#f4145afb7c3a3bafe0376f003b5c3bdeae17a952" 28 | integrity sha512-JFxcEyp8RlNHgBCE98nwuTkZT6eNFPc1aosWV6wPcQph72TSEEu1k3baJD4/x1qznU+JiDdz8F5pTwabZh+Dhg== 29 | dependencies: 30 | "@apidevtools/json-schema-ref-parser" "^9.0.6" 31 | "@apidevtools/openapi-schemas" "^2.0.4" 32 | "@apidevtools/swagger-methods" "^3.0.2" 33 | "@jsdevtools/ono" "^7.1.3" 34 | call-me-maybe "^1.0.1" 35 | z-schema "^4.2.3" 36 | 37 | "@jsdevtools/ono@^7.1.3": 38 | version "7.1.3" 39 | resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" 40 | integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== 41 | 42 | "@mapbox/node-pre-gyp@^1.0.0": 43 | version "1.0.5" 44 | resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz#2a0b32fcb416fb3f2250fd24cb2a81421a4f5950" 45 | integrity sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA== 46 | dependencies: 47 | detect-libc "^1.0.3" 48 | https-proxy-agent "^5.0.0" 49 | make-dir "^3.1.0" 50 | node-fetch "^2.6.1" 51 | nopt "^5.0.0" 52 | npmlog "^4.1.2" 53 | rimraf "^3.0.2" 54 | semver "^7.3.4" 55 | tar "^6.1.0" 56 | 57 | "@types/bcrypt@^5.0.0": 58 | version "5.0.0" 59 | resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-5.0.0.tgz#a835afa2882d165aff5690893db314eaa98b9f20" 60 | integrity sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw== 61 | dependencies: 62 | "@types/node" "*" 63 | 64 | "@types/body-parser@*", "@types/body-parser@^1.19.1": 65 | version "1.19.1" 66 | resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c" 67 | integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg== 68 | dependencies: 69 | "@types/connect" "*" 70 | "@types/node" "*" 71 | 72 | "@types/config@^0.0.39": 73 | version "0.0.39" 74 | resolved "https://registry.yarnpkg.com/@types/config/-/config-0.0.39.tgz#aad18ceb9439329adc3d4c6b91a908a72c715612" 75 | integrity sha512-EBHj9lSIyw62vwqCwkeJXjiV6C2m2o+RJZlRWLkHduGYiNBoMXcY6AhSLqjQQ+uPdrPYrOMYvVa41zjo00LbFQ== 76 | 77 | "@types/connect@*": 78 | version "3.4.35" 79 | resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" 80 | integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== 81 | dependencies: 82 | "@types/node" "*" 83 | 84 | "@types/cors@^2.8.12": 85 | version "2.8.12" 86 | resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" 87 | integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== 88 | 89 | "@types/express-serve-static-core@^4.17.18": 90 | version "4.17.24" 91 | resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07" 92 | integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA== 93 | dependencies: 94 | "@types/node" "*" 95 | "@types/qs" "*" 96 | "@types/range-parser" "*" 97 | 98 | "@types/express@*", "@types/express@^4.17.13": 99 | version "4.17.13" 100 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034" 101 | integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== 102 | dependencies: 103 | "@types/body-parser" "*" 104 | "@types/express-serve-static-core" "^4.17.18" 105 | "@types/qs" "*" 106 | "@types/serve-static" "*" 107 | 108 | "@types/json-schema@^7.0.6": 109 | version "7.0.9" 110 | resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" 111 | integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== 112 | 113 | "@types/jsonwebtoken@^8.5.5": 114 | version "8.5.5" 115 | resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.5.tgz#da5f2f4baee88f052ef3e4db4c1a0afb46cff22c" 116 | integrity sha512-OGqtHQ7N5/Ap/TUwO6IgHDuLiAoTmHhGpNvgkCm/F4N6pKzx/RBSfr2OXZSwC6vkfnsEdb6+7DNZVtiXiwdwFw== 117 | dependencies: 118 | "@types/node" "*" 119 | 120 | "@types/lodash@^4.14.175": 121 | version "4.14.175" 122 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.175.tgz#b78dfa959192b01fae0ad90e166478769b215f45" 123 | integrity sha512-XmdEOrKQ8a1Y/yxQFOMbC47G/V2VDO1GvMRnl4O75M4GW/abC5tnfzadQYkqEveqRM1dEJGFFegfPNA2vvx2iw== 124 | 125 | "@types/mime@^1": 126 | version "1.3.2" 127 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" 128 | integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== 129 | 130 | "@types/nanoid@^3.0.0": 131 | version "3.0.0" 132 | resolved "https://registry.yarnpkg.com/@types/nanoid/-/nanoid-3.0.0.tgz#c757b20f343f3a1dd76e80a9a431b6290fc20f35" 133 | integrity sha512-UXitWSmXCwhDmAKe7D3hNQtQaHeHt5L8LO1CB8GF8jlYVzOv5cBWDNqiJ+oPEWrWei3i3dkZtHY/bUtd0R/uOQ== 134 | dependencies: 135 | nanoid "*" 136 | 137 | "@types/node@*": 138 | version "16.10.2" 139 | resolved "https://registry.yarnpkg.com/@types/node/-/node-16.10.2.tgz#5764ca9aa94470adb4e1185fe2e9f19458992b2e" 140 | integrity sha512-zCclL4/rx+W5SQTzFs9wyvvyCwoK9QtBpratqz2IYJ3O8Umrn0m3nsTv0wQBk9sRGpvUe9CwPDrQFB10f1FIjQ== 141 | 142 | "@types/node@^16.11.1": 143 | version "16.11.1" 144 | resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.1.tgz#2e50a649a50fc403433a14f829eface1a3443e97" 145 | integrity sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA== 146 | 147 | "@types/pino-pretty@*": 148 | version "4.7.1" 149 | resolved "https://registry.yarnpkg.com/@types/pino-pretty/-/pino-pretty-4.7.1.tgz#2ce3f56f3cf4f9632374419d616ae2e6c933b935" 150 | integrity sha512-l1ntNXdpVWsnPYUk5HyO5Lxfr38zLCgxVfEn/9Zhhm+nGF04/BiIou/m8XPwvoVZLV+livUo79VdHXMJPfUYxA== 151 | dependencies: 152 | "@types/pino" "*" 153 | 154 | "@types/pino-std-serializers@*": 155 | version "2.4.1" 156 | resolved "https://registry.yarnpkg.com/@types/pino-std-serializers/-/pino-std-serializers-2.4.1.tgz#f8bd52a209c8b3c97d1533b1ba27f57c816382bf" 157 | integrity sha512-17XcksO47M24IVTVKPeAByWUd3Oez7EbIjXpSbzMPhXVzgjGtrOa49gKBwxH9hb8dKv58OelsWQ+A1G1l9S3wQ== 158 | dependencies: 159 | "@types/node" "*" 160 | 161 | "@types/pino@*", "@types/pino@^6.3.11": 162 | version "6.3.11" 163 | resolved "https://registry.yarnpkg.com/@types/pino/-/pino-6.3.11.tgz#83652799e76b3ad692aaf68f6fbf994e83af5db2" 164 | integrity sha512-S7+fLONqSpHeW9d7TApUqO6VN47KYgOXhCNKwGBVLHObq8HhaAYlVqUNdfnvoXjCMiwE5xcPm/5R2ZUh8bgaXQ== 165 | dependencies: 166 | "@types/node" "*" 167 | "@types/pino-pretty" "*" 168 | "@types/pino-std-serializers" "*" 169 | sonic-boom "^2.1.0" 170 | 171 | "@types/qs@*": 172 | version "6.9.7" 173 | resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" 174 | integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== 175 | 176 | "@types/range-parser@*": 177 | version "1.2.4" 178 | resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" 179 | integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== 180 | 181 | "@types/response-time@^2.3.5": 182 | version "2.3.5" 183 | resolved "https://registry.yarnpkg.com/@types/response-time/-/response-time-2.3.5.tgz#e85ff348caefd0f8d3e8902424c681a59aafc31e" 184 | integrity sha512-4ANzp+I3K7sztFFAGPALWBvSl4ayaDSKzI2Bok+WNz+en2eB2Pvk6VCjR47PBXBWOkEg2r4uWpZOlXA5DNINOQ== 185 | dependencies: 186 | "@types/express" "*" 187 | "@types/node" "*" 188 | 189 | "@types/serve-static@*": 190 | version "1.13.10" 191 | resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9" 192 | integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ== 193 | dependencies: 194 | "@types/mime" "^1" 195 | "@types/node" "*" 196 | 197 | "@types/strip-bom@^3.0.0": 198 | version "3.0.0" 199 | resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" 200 | integrity sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I= 201 | 202 | "@types/strip-json-comments@0.0.30": 203 | version "0.0.30" 204 | resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" 205 | integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== 206 | 207 | "@types/swagger-jsdoc@^6.0.1": 208 | version "6.0.1" 209 | resolved "https://registry.yarnpkg.com/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.1.tgz#94a99aca0356cb64ad2a6eb903ed034703453801" 210 | integrity sha512-+MUpcbyxD528dECUBCEVm6abNuORdbuGjbrUdHDeAQ+rkPuo2a+L4N02WJHF3bonSSE6SJ3dUJwF2V6+cHnf0w== 211 | 212 | "@types/swagger-ui-express@^4.1.3": 213 | version "4.1.3" 214 | resolved "https://registry.yarnpkg.com/@types/swagger-ui-express/-/swagger-ui-express-4.1.3.tgz#7adbbbf5343b45869debef1e9ff39c9ba73e380f" 215 | integrity sha512-jqCjGU/tGEaqIplPy3WyQg+Nrp6y80DCFnDEAvVKWkJyv0VivSSDCChkppHRHAablvInZe6pijDFMnavtN0vqA== 216 | dependencies: 217 | "@types/express" "*" 218 | "@types/serve-static" "*" 219 | 220 | "@types/webidl-conversions@*": 221 | version "6.1.1" 222 | resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e" 223 | integrity sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q== 224 | 225 | "@types/whatwg-url@^8.2.1": 226 | version "8.2.1" 227 | resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.1.tgz#f1aac222dab7c59e011663a0cb0a3117b2ef05d4" 228 | integrity sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ== 229 | dependencies: 230 | "@types/node" "*" 231 | "@types/webidl-conversions" "*" 232 | 233 | abbrev@1: 234 | version "1.1.1" 235 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 236 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 237 | 238 | accepts@~1.3.7: 239 | version "1.3.7" 240 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 241 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 242 | dependencies: 243 | mime-types "~2.1.24" 244 | negotiator "0.6.2" 245 | 246 | agent-base@6: 247 | version "6.0.2" 248 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" 249 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 250 | dependencies: 251 | debug "4" 252 | 253 | ansi-regex@^2.0.0: 254 | version "2.1.1" 255 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 256 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 257 | 258 | ansi-regex@^5.0.1: 259 | version "5.0.1" 260 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 261 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 262 | 263 | ansi-styles@^3.2.1: 264 | version "3.2.1" 265 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 266 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 267 | dependencies: 268 | color-convert "^1.9.0" 269 | 270 | anymatch@~3.1.2: 271 | version "3.1.2" 272 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 273 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 274 | dependencies: 275 | normalize-path "^3.0.0" 276 | picomatch "^2.0.4" 277 | 278 | aproba@^1.0.3: 279 | version "1.2.0" 280 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 281 | integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== 282 | 283 | are-we-there-yet@~1.1.2: 284 | version "1.1.7" 285 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" 286 | integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== 287 | dependencies: 288 | delegates "^1.0.0" 289 | readable-stream "^2.0.6" 290 | 291 | arg@^4.1.0: 292 | version "4.1.3" 293 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" 294 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 295 | 296 | argparse@^2.0.1: 297 | version "2.0.1" 298 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 299 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 300 | 301 | args@^5.0.1: 302 | version "5.0.1" 303 | resolved "https://registry.yarnpkg.com/args/-/args-5.0.1.tgz#4bf298df90a4799a09521362c579278cc2fdd761" 304 | integrity sha512-1kqmFCFsPffavQFGt8OxJdIcETti99kySRUPMpOhaGjL6mRJn8HFU1OxKY5bMqfZKUwTQc1mZkAjmGYaVOHFtQ== 305 | dependencies: 306 | camelcase "5.0.0" 307 | chalk "2.4.2" 308 | leven "2.1.0" 309 | mri "1.1.4" 310 | 311 | array-flatten@1.1.1: 312 | version "1.1.1" 313 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 314 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 315 | 316 | atomic-sleep@^1.0.0: 317 | version "1.0.0" 318 | resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" 319 | integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== 320 | 321 | balanced-match@^1.0.0: 322 | version "1.0.2" 323 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 324 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 325 | 326 | base64-js@^1.3.1: 327 | version "1.5.1" 328 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" 329 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== 330 | 331 | bcrypt@^5.0.1: 332 | version "5.0.1" 333 | resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.1.tgz#f1a2c20f208e2ccdceea4433df0c8b2c54ecdf71" 334 | integrity sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw== 335 | dependencies: 336 | "@mapbox/node-pre-gyp" "^1.0.0" 337 | node-addon-api "^3.1.0" 338 | 339 | binary-extensions@^2.0.0: 340 | version "2.2.0" 341 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 342 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 343 | 344 | bintrees@1.0.1: 345 | version "1.0.1" 346 | resolved "https://registry.yarnpkg.com/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" 347 | integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= 348 | 349 | body-parser@1.19.0: 350 | version "1.19.0" 351 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 352 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== 353 | dependencies: 354 | bytes "3.1.0" 355 | content-type "~1.0.4" 356 | debug "2.6.9" 357 | depd "~1.1.2" 358 | http-errors "1.7.2" 359 | iconv-lite "0.4.24" 360 | on-finished "~2.3.0" 361 | qs "6.7.0" 362 | raw-body "2.4.0" 363 | type-is "~1.6.17" 364 | 365 | brace-expansion@^1.1.7: 366 | version "1.1.11" 367 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 368 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 369 | dependencies: 370 | balanced-match "^1.0.0" 371 | concat-map "0.0.1" 372 | 373 | braces@~3.0.2: 374 | version "3.0.2" 375 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 376 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 377 | dependencies: 378 | fill-range "^7.0.1" 379 | 380 | bson@^4.2.2: 381 | version "4.5.2" 382 | resolved "https://registry.yarnpkg.com/bson/-/bson-4.5.2.tgz#567b4ee94372d5284a4d6c47fb6e1cc711ae76ba" 383 | integrity sha512-8CEMJpwc7qlQtrn2rney38jQSEeMar847lz0LyitwRmVknAW8iHXrzW4fTjHfyWm0E3sukyD/zppdH+QU1QefA== 384 | dependencies: 385 | buffer "^5.6.0" 386 | 387 | bson@^4.5.2: 388 | version "4.5.3" 389 | resolved "https://registry.yarnpkg.com/bson/-/bson-4.5.3.tgz#de3783b357a407d935510beb1fbb285fef43bb06" 390 | integrity sha512-qVX7LX79Mtj7B3NPLzCfBiCP6RAsjiV8N63DjlaVVpZW+PFoDTxQ4SeDbSpcqgE6mXksM5CAwZnXxxxn/XwC0g== 391 | dependencies: 392 | buffer "^5.6.0" 393 | 394 | buffer-equal-constant-time@1.0.1: 395 | version "1.0.1" 396 | resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" 397 | integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= 398 | 399 | buffer-from@^1.0.0: 400 | version "1.1.2" 401 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 402 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 403 | 404 | buffer@^5.6.0: 405 | version "5.7.1" 406 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" 407 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== 408 | dependencies: 409 | base64-js "^1.3.1" 410 | ieee754 "^1.1.13" 411 | 412 | bytes@3.1.0: 413 | version "3.1.0" 414 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 415 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 416 | 417 | call-me-maybe@^1.0.1: 418 | version "1.0.1" 419 | resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" 420 | integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= 421 | 422 | camelcase@5.0.0: 423 | version "5.0.0" 424 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" 425 | integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== 426 | 427 | chalk@2.4.2: 428 | version "2.4.2" 429 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 430 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 431 | dependencies: 432 | ansi-styles "^3.2.1" 433 | escape-string-regexp "^1.0.5" 434 | supports-color "^5.3.0" 435 | 436 | chokidar@^3.5.1: 437 | version "3.5.2" 438 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" 439 | integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== 440 | dependencies: 441 | anymatch "~3.1.2" 442 | braces "~3.0.2" 443 | glob-parent "~5.1.2" 444 | is-binary-path "~2.1.0" 445 | is-glob "~4.0.1" 446 | normalize-path "~3.0.0" 447 | readdirp "~3.6.0" 448 | optionalDependencies: 449 | fsevents "~2.3.2" 450 | 451 | chownr@^2.0.0: 452 | version "2.0.0" 453 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" 454 | integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== 455 | 456 | code-point-at@^1.0.0: 457 | version "1.1.0" 458 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 459 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 460 | 461 | color-convert@^1.9.0: 462 | version "1.9.3" 463 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 464 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 465 | dependencies: 466 | color-name "1.1.3" 467 | 468 | color-name@1.1.3: 469 | version "1.1.3" 470 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 471 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 472 | 473 | colorette@^2.0.7: 474 | version "2.0.16" 475 | resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" 476 | integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== 477 | 478 | commander@6.2.0: 479 | version "6.2.0" 480 | resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" 481 | integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q== 482 | 483 | commander@^2.7.1: 484 | version "2.20.3" 485 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 486 | integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== 487 | 488 | concat-map@0.0.1: 489 | version "0.0.1" 490 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 491 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 492 | 493 | config@^3.3.6: 494 | version "3.3.6" 495 | resolved "https://registry.yarnpkg.com/config/-/config-3.3.6.tgz#b87799db7399cc34988f55379b5f43465b1b065c" 496 | integrity sha512-Hj5916C5HFawjYJat1epbyY2PlAgLpBtDUlr0MxGLgo3p5+7kylyvnRY18PqJHgnNWXcdd0eWDemT7eYWuFgwg== 497 | dependencies: 498 | json5 "^2.1.1" 499 | 500 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 501 | version "1.1.0" 502 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 503 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= 504 | 505 | content-disposition@0.5.3: 506 | version "0.5.3" 507 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 508 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 509 | dependencies: 510 | safe-buffer "5.1.2" 511 | 512 | content-type@~1.0.4: 513 | version "1.0.4" 514 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 515 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 516 | 517 | cookie-signature@1.0.6: 518 | version "1.0.6" 519 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 520 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 521 | 522 | cookie@0.4.0: 523 | version "0.4.0" 524 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" 525 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== 526 | 527 | core-util-is@~1.0.0: 528 | version "1.0.3" 529 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 530 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 531 | 532 | cors@^2.8.5: 533 | version "2.8.5" 534 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" 535 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== 536 | dependencies: 537 | object-assign "^4" 538 | vary "^1" 539 | 540 | create-require@^1.1.0: 541 | version "1.1.1" 542 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 543 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 544 | 545 | dateformat@^4.6.3: 546 | version "4.6.3" 547 | resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" 548 | integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== 549 | 550 | dayjs@^1.10.7: 551 | version "1.10.7" 552 | resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.7.tgz#2cf5f91add28116748440866a0a1d26f3a6ce468" 553 | integrity sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig== 554 | 555 | debug@2.6.9: 556 | version "2.6.9" 557 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 558 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 559 | dependencies: 560 | ms "2.0.0" 561 | 562 | debug@4, debug@4.x: 563 | version "4.3.2" 564 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" 565 | integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== 566 | dependencies: 567 | ms "2.1.2" 568 | 569 | delegates@^1.0.0: 570 | version "1.0.0" 571 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 572 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= 573 | 574 | denque@^2.0.1: 575 | version "2.0.1" 576 | resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a" 577 | integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== 578 | 579 | depd@~1.1.0, depd@~1.1.2: 580 | version "1.1.2" 581 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 582 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 583 | 584 | destroy@~1.0.4: 585 | version "1.0.4" 586 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 587 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 588 | 589 | detect-libc@^1.0.3: 590 | version "1.0.3" 591 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 592 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= 593 | 594 | diff@^4.0.1: 595 | version "4.0.2" 596 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 597 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 598 | 599 | doctrine@3.0.0: 600 | version "3.0.0" 601 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" 602 | integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== 603 | dependencies: 604 | esutils "^2.0.2" 605 | 606 | dotenv@^10.0.0: 607 | version "10.0.0" 608 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" 609 | integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== 610 | 611 | duplexify@^4.1.2: 612 | version "4.1.2" 613 | resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" 614 | integrity sha512-fz3OjcNCHmRP12MJoZMPglx8m4rrFP8rovnk4vT8Fs+aonZoCwGg10dSsQsfP/E62eZcPTMSMP6686fu9Qlqtw== 615 | dependencies: 616 | end-of-stream "^1.4.1" 617 | inherits "^2.0.3" 618 | readable-stream "^3.1.1" 619 | stream-shift "^1.0.0" 620 | 621 | dynamic-dedupe@^0.3.0: 622 | version "0.3.0" 623 | resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" 624 | integrity sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE= 625 | dependencies: 626 | xtend "^4.0.0" 627 | 628 | ecdsa-sig-formatter@1.0.11: 629 | version "1.0.11" 630 | resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" 631 | integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== 632 | dependencies: 633 | safe-buffer "^5.0.1" 634 | 635 | ee-first@1.1.1: 636 | version "1.1.1" 637 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 638 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 639 | 640 | emoji-regex@^8.0.0: 641 | version "8.0.0" 642 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 643 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 644 | 645 | encodeurl@~1.0.2: 646 | version "1.0.2" 647 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 648 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 649 | 650 | end-of-stream@^1.1.0, end-of-stream@^1.4.1: 651 | version "1.4.4" 652 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 653 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 654 | dependencies: 655 | once "^1.4.0" 656 | 657 | escape-html@~1.0.3: 658 | version "1.0.3" 659 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 660 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 661 | 662 | escape-string-regexp@^1.0.5: 663 | version "1.0.5" 664 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 665 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 666 | 667 | esutils@^2.0.2: 668 | version "2.0.3" 669 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 670 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 671 | 672 | etag@~1.8.1: 673 | version "1.8.1" 674 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 675 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 676 | 677 | express@^4.17.1: 678 | version "4.17.1" 679 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" 680 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== 681 | dependencies: 682 | accepts "~1.3.7" 683 | array-flatten "1.1.1" 684 | body-parser "1.19.0" 685 | content-disposition "0.5.3" 686 | content-type "~1.0.4" 687 | cookie "0.4.0" 688 | cookie-signature "1.0.6" 689 | debug "2.6.9" 690 | depd "~1.1.2" 691 | encodeurl "~1.0.2" 692 | escape-html "~1.0.3" 693 | etag "~1.8.1" 694 | finalhandler "~1.1.2" 695 | fresh "0.5.2" 696 | merge-descriptors "1.0.1" 697 | methods "~1.1.2" 698 | on-finished "~2.3.0" 699 | parseurl "~1.3.3" 700 | path-to-regexp "0.1.7" 701 | proxy-addr "~2.0.5" 702 | qs "6.7.0" 703 | range-parser "~1.2.1" 704 | safe-buffer "5.1.2" 705 | send "0.17.1" 706 | serve-static "1.14.1" 707 | setprototypeof "1.1.1" 708 | statuses "~1.5.0" 709 | type-is "~1.6.18" 710 | utils-merge "1.0.1" 711 | vary "~1.1.2" 712 | 713 | fast-redact@^3.0.0: 714 | version "3.0.2" 715 | resolved "https://registry.yarnpkg.com/fast-redact/-/fast-redact-3.0.2.tgz#c940ba7162dde3aeeefc522926ae8c5231412904" 716 | integrity sha512-YN+CYfCVRVMUZOUPeinHNKgytM1wPI/C/UCLEi56EsY2dwwvI00kIJHJoI7pMVqGoMew8SMZ2SSfHKHULHXDsg== 717 | 718 | fast-safe-stringify@^2.0.7: 719 | version "2.1.1" 720 | resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" 721 | integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== 722 | 723 | fastify-warning@^0.2.0: 724 | version "0.2.0" 725 | resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f" 726 | integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw== 727 | 728 | fill-range@^7.0.1: 729 | version "7.0.1" 730 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 731 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 732 | dependencies: 733 | to-regex-range "^5.0.1" 734 | 735 | finalhandler@~1.1.2: 736 | version "1.1.2" 737 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 738 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 739 | dependencies: 740 | debug "2.6.9" 741 | encodeurl "~1.0.2" 742 | escape-html "~1.0.3" 743 | on-finished "~2.3.0" 744 | parseurl "~1.3.3" 745 | statuses "~1.5.0" 746 | unpipe "~1.0.0" 747 | 748 | forwarded@0.2.0: 749 | version "0.2.0" 750 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" 751 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 752 | 753 | fresh@0.5.2: 754 | version "0.5.2" 755 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 756 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 757 | 758 | fs-minipass@^2.0.0: 759 | version "2.1.0" 760 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" 761 | integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== 762 | dependencies: 763 | minipass "^3.0.0" 764 | 765 | fs.realpath@^1.0.0: 766 | version "1.0.0" 767 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 768 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 769 | 770 | fsevents@~2.3.2: 771 | version "2.3.2" 772 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 773 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 774 | 775 | function-bind@^1.1.1: 776 | version "1.1.1" 777 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 778 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 779 | 780 | gauge@~2.7.3: 781 | version "2.7.4" 782 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 783 | integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= 784 | dependencies: 785 | aproba "^1.0.3" 786 | console-control-strings "^1.0.0" 787 | has-unicode "^2.0.0" 788 | object-assign "^4.1.0" 789 | signal-exit "^3.0.0" 790 | string-width "^1.0.1" 791 | strip-ansi "^3.0.1" 792 | wide-align "^1.1.0" 793 | 794 | get-caller-file@^2.0.5: 795 | version "2.0.5" 796 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 797 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 798 | 799 | glob-parent@~5.1.2: 800 | version "5.1.2" 801 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 802 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 803 | dependencies: 804 | is-glob "^4.0.1" 805 | 806 | glob@7.1.6: 807 | version "7.1.6" 808 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 809 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 810 | dependencies: 811 | fs.realpath "^1.0.0" 812 | inflight "^1.0.4" 813 | inherits "2" 814 | minimatch "^3.0.4" 815 | once "^1.3.0" 816 | path-is-absolute "^1.0.0" 817 | 818 | glob@^7.1.3: 819 | version "7.2.0" 820 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" 821 | integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== 822 | dependencies: 823 | fs.realpath "^1.0.0" 824 | inflight "^1.0.4" 825 | inherits "2" 826 | minimatch "^3.0.4" 827 | once "^1.3.0" 828 | path-is-absolute "^1.0.0" 829 | 830 | has-flag@^3.0.0: 831 | version "3.0.0" 832 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 833 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 834 | 835 | has-unicode@^2.0.0: 836 | version "2.0.1" 837 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 838 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= 839 | 840 | has@^1.0.3: 841 | version "1.0.3" 842 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 843 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 844 | dependencies: 845 | function-bind "^1.1.1" 846 | 847 | http-errors@1.7.2: 848 | version "1.7.2" 849 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 850 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 851 | dependencies: 852 | depd "~1.1.2" 853 | inherits "2.0.3" 854 | setprototypeof "1.1.1" 855 | statuses ">= 1.5.0 < 2" 856 | toidentifier "1.0.0" 857 | 858 | http-errors@~1.7.2: 859 | version "1.7.3" 860 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" 861 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== 862 | dependencies: 863 | depd "~1.1.2" 864 | inherits "2.0.4" 865 | setprototypeof "1.1.1" 866 | statuses ">= 1.5.0 < 2" 867 | toidentifier "1.0.0" 868 | 869 | https-proxy-agent@^5.0.0: 870 | version "5.0.0" 871 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" 872 | integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== 873 | dependencies: 874 | agent-base "6" 875 | debug "4" 876 | 877 | iconv-lite@0.4.24: 878 | version "0.4.24" 879 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 880 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 881 | dependencies: 882 | safer-buffer ">= 2.1.2 < 3" 883 | 884 | ieee754@^1.1.13: 885 | version "1.2.1" 886 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" 887 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== 888 | 889 | inflight@^1.0.4: 890 | version "1.0.6" 891 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 892 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 893 | dependencies: 894 | once "^1.3.0" 895 | wrappy "1" 896 | 897 | inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.3: 898 | version "2.0.4" 899 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 900 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 901 | 902 | inherits@2.0.3: 903 | version "2.0.3" 904 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 905 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 906 | 907 | ipaddr.js@1.9.1: 908 | version "1.9.1" 909 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 910 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 911 | 912 | is-binary-path@~2.1.0: 913 | version "2.1.0" 914 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 915 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 916 | dependencies: 917 | binary-extensions "^2.0.0" 918 | 919 | is-core-module@^2.2.0: 920 | version "2.8.0" 921 | resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" 922 | integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== 923 | dependencies: 924 | has "^1.0.3" 925 | 926 | is-extglob@^2.1.1: 927 | version "2.1.1" 928 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 929 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 930 | 931 | is-fullwidth-code-point@^1.0.0: 932 | version "1.0.0" 933 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 934 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 935 | dependencies: 936 | number-is-nan "^1.0.0" 937 | 938 | is-fullwidth-code-point@^3.0.0: 939 | version "3.0.0" 940 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 941 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 942 | 943 | is-glob@^4.0.1, is-glob@~4.0.1: 944 | version "4.0.3" 945 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 946 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 947 | dependencies: 948 | is-extglob "^2.1.1" 949 | 950 | is-number@^7.0.0: 951 | version "7.0.0" 952 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 953 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 954 | 955 | isarray@~1.0.0: 956 | version "1.0.0" 957 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 958 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 959 | 960 | joycon@^3.0.0: 961 | version "3.0.1" 962 | resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.0.1.tgz#9074c9b08ccf37a6726ff74a18485f85efcaddaf" 963 | integrity sha512-SJcJNBg32dGgxhPtM0wQqxqV0ax9k/9TaUskGDSJkSFSQOEWWvQ3zzWdGQRIUry2j1zA5+ReH13t0Mf3StuVZA== 964 | 965 | js-yaml@^4.1.0: 966 | version "4.1.0" 967 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 968 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 969 | dependencies: 970 | argparse "^2.0.1" 971 | 972 | json-stringify-safe@^5.0.1: 973 | version "5.0.1" 974 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 975 | integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= 976 | 977 | json5@^2.1.1: 978 | version "2.2.0" 979 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" 980 | integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== 981 | dependencies: 982 | minimist "^1.2.5" 983 | 984 | jsonwebtoken@^8.5.1: 985 | version "8.5.1" 986 | resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" 987 | integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== 988 | dependencies: 989 | jws "^3.2.2" 990 | lodash.includes "^4.3.0" 991 | lodash.isboolean "^3.0.3" 992 | lodash.isinteger "^4.0.4" 993 | lodash.isnumber "^3.0.3" 994 | lodash.isplainobject "^4.0.6" 995 | lodash.isstring "^4.0.1" 996 | lodash.once "^4.0.0" 997 | ms "^2.1.1" 998 | semver "^5.6.0" 999 | 1000 | jwa@^1.4.1: 1001 | version "1.4.1" 1002 | resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" 1003 | integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== 1004 | dependencies: 1005 | buffer-equal-constant-time "1.0.1" 1006 | ecdsa-sig-formatter "1.0.11" 1007 | safe-buffer "^5.0.1" 1008 | 1009 | jws@^3.2.2: 1010 | version "3.2.2" 1011 | resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" 1012 | integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== 1013 | dependencies: 1014 | jwa "^1.4.1" 1015 | safe-buffer "^5.0.1" 1016 | 1017 | kareem@2.3.2: 1018 | version "2.3.2" 1019 | resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.2.tgz#78c4508894985b8d38a0dc15e1a8e11078f2ca93" 1020 | integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ== 1021 | 1022 | leven@2.1.0: 1023 | version "2.1.0" 1024 | resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" 1025 | integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= 1026 | 1027 | lodash.get@^4.4.2: 1028 | version "4.4.2" 1029 | resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" 1030 | integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= 1031 | 1032 | lodash.includes@^4.3.0: 1033 | version "4.3.0" 1034 | resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" 1035 | integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= 1036 | 1037 | lodash.isboolean@^3.0.3: 1038 | version "3.0.3" 1039 | resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" 1040 | integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= 1041 | 1042 | lodash.isequal@^4.5.0: 1043 | version "4.5.0" 1044 | resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" 1045 | integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= 1046 | 1047 | lodash.isinteger@^4.0.4: 1048 | version "4.0.4" 1049 | resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" 1050 | integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= 1051 | 1052 | lodash.isnumber@^3.0.3: 1053 | version "3.0.3" 1054 | resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" 1055 | integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= 1056 | 1057 | lodash.isplainobject@^4.0.6: 1058 | version "4.0.6" 1059 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" 1060 | integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= 1061 | 1062 | lodash.isstring@^4.0.1: 1063 | version "4.0.1" 1064 | resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" 1065 | integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= 1066 | 1067 | lodash.mergewith@^4.6.2: 1068 | version "4.6.2" 1069 | resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" 1070 | integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== 1071 | 1072 | lodash.once@^4.0.0: 1073 | version "4.1.1" 1074 | resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" 1075 | integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= 1076 | 1077 | lodash@^4.17.21: 1078 | version "4.17.21" 1079 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 1080 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 1081 | 1082 | lru-cache@^6.0.0: 1083 | version "6.0.0" 1084 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 1085 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 1086 | dependencies: 1087 | yallist "^4.0.0" 1088 | 1089 | make-dir@^3.1.0: 1090 | version "3.1.0" 1091 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 1092 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== 1093 | dependencies: 1094 | semver "^6.0.0" 1095 | 1096 | make-error@^1.1.1: 1097 | version "1.3.6" 1098 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 1099 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 1100 | 1101 | media-typer@0.3.0: 1102 | version "0.3.0" 1103 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 1104 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 1105 | 1106 | memory-pager@^1.0.2: 1107 | version "1.5.0" 1108 | resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" 1109 | integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== 1110 | 1111 | merge-descriptors@1.0.1: 1112 | version "1.0.1" 1113 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 1114 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 1115 | 1116 | methods@~1.1.2: 1117 | version "1.1.2" 1118 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 1119 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 1120 | 1121 | mime-db@1.50.0: 1122 | version "1.50.0" 1123 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.50.0.tgz#abd4ac94e98d3c0e185016c67ab45d5fde40c11f" 1124 | integrity sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A== 1125 | 1126 | mime-types@~2.1.24: 1127 | version "2.1.33" 1128 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.33.tgz#1fa12a904472fafd068e48d9e8401f74d3f70edb" 1129 | integrity sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g== 1130 | dependencies: 1131 | mime-db "1.50.0" 1132 | 1133 | mime@1.6.0: 1134 | version "1.6.0" 1135 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 1136 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 1137 | 1138 | minimatch@^3.0.4: 1139 | version "3.0.4" 1140 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1141 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 1142 | dependencies: 1143 | brace-expansion "^1.1.7" 1144 | 1145 | minimist@^1.2.5: 1146 | version "1.2.5" 1147 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 1148 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 1149 | 1150 | minipass@^3.0.0: 1151 | version "3.1.5" 1152 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.5.tgz#71f6251b0a33a49c01b3cf97ff77eda030dff732" 1153 | integrity sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw== 1154 | dependencies: 1155 | yallist "^4.0.0" 1156 | 1157 | minizlib@^2.1.1: 1158 | version "2.1.2" 1159 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" 1160 | integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== 1161 | dependencies: 1162 | minipass "^3.0.0" 1163 | yallist "^4.0.0" 1164 | 1165 | mkdirp@^1.0.3, mkdirp@^1.0.4: 1166 | version "1.0.4" 1167 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" 1168 | integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== 1169 | 1170 | mongodb-connection-string-url@^2.0.0: 1171 | version "2.1.0" 1172 | resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.1.0.tgz#9c522c11c37f571fecddcb267ac4a76ef432aeb7" 1173 | integrity sha512-Qf9Zw7KGiRljWvMrrUFDdVqo46KIEiDuCzvEN97rh/PcKzk2bd6n9KuzEwBwW9xo5glwx69y1mI6s+jFUD/aIQ== 1174 | dependencies: 1175 | "@types/whatwg-url" "^8.2.1" 1176 | whatwg-url "^9.1.0" 1177 | 1178 | mongodb@4.1.2: 1179 | version "4.1.2" 1180 | resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.1.2.tgz#36ab494db3a9a827df41ccb0d9b36a94bfeae8d7" 1181 | integrity sha512-pHCKDoOy1h6mVurziJmXmTMPatYWOx8pbnyFgSgshja9Y36Q+caHUzTDY6rrIy9HCSrjnbXmx3pCtvNZHmR8xg== 1182 | dependencies: 1183 | bson "^4.5.2" 1184 | denque "^2.0.1" 1185 | mongodb-connection-string-url "^2.0.0" 1186 | optionalDependencies: 1187 | saslprep "^1.0.3" 1188 | 1189 | mongoose@^6.0.11: 1190 | version "6.0.11" 1191 | resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.0.11.tgz#579cda5157a58b155812974567d7a9a92b26a118" 1192 | integrity sha512-ESLnGIZB15xpqAbtjL/wcx+NEmzewlNuST/Dp/md4eqirVGTuEeN+IhS4qr3D5GFhnQAGdadpGlTfrWj5Ggykw== 1193 | dependencies: 1194 | bson "^4.2.2" 1195 | kareem "2.3.2" 1196 | mongodb "4.1.2" 1197 | mpath "0.8.4" 1198 | mquery "4.0.0" 1199 | ms "2.1.2" 1200 | regexp-clone "1.0.0" 1201 | sift "13.5.2" 1202 | sliced "1.0.1" 1203 | 1204 | mpath@0.8.4: 1205 | version "0.8.4" 1206 | resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.4.tgz#6b566d9581621d9e931dd3b142ed3618e7599313" 1207 | integrity sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g== 1208 | 1209 | mquery@4.0.0: 1210 | version "4.0.0" 1211 | resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.0.tgz#6c62160ad25289e99e0840907757cdfd62bde775" 1212 | integrity sha512-nGjm89lHja+T/b8cybAby6H0YgA4qYC/lx6UlwvHGqvTq8bDaNeCwl1sY8uRELrNbVWJzIihxVd+vphGGn1vBw== 1213 | dependencies: 1214 | debug "4.x" 1215 | regexp-clone "^1.0.0" 1216 | sliced "1.0.1" 1217 | 1218 | mri@1.1.4: 1219 | version "1.1.4" 1220 | resolved "https://registry.yarnpkg.com/mri/-/mri-1.1.4.tgz#7cb1dd1b9b40905f1fac053abe25b6720f44744a" 1221 | integrity sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w== 1222 | 1223 | ms@2.0.0: 1224 | version "2.0.0" 1225 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1226 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 1227 | 1228 | ms@2.1.1: 1229 | version "2.1.1" 1230 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 1231 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 1232 | 1233 | ms@2.1.2: 1234 | version "2.1.2" 1235 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 1236 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1237 | 1238 | ms@^2.1.1: 1239 | version "2.1.3" 1240 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 1241 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1242 | 1243 | nanoid@*, nanoid@^3.1.30: 1244 | version "3.1.30" 1245 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" 1246 | integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== 1247 | 1248 | negotiator@0.6.2: 1249 | version "0.6.2" 1250 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 1251 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 1252 | 1253 | node-addon-api@^3.1.0: 1254 | version "3.2.1" 1255 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" 1256 | integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== 1257 | 1258 | node-fetch@^2.6.1: 1259 | version "2.6.5" 1260 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd" 1261 | integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ== 1262 | dependencies: 1263 | whatwg-url "^5.0.0" 1264 | 1265 | nopt@^5.0.0: 1266 | version "5.0.0" 1267 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" 1268 | integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== 1269 | dependencies: 1270 | abbrev "1" 1271 | 1272 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1273 | version "3.0.0" 1274 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 1275 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 1276 | 1277 | npmlog@^4.1.2: 1278 | version "4.1.2" 1279 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 1280 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== 1281 | dependencies: 1282 | are-we-there-yet "~1.1.2" 1283 | console-control-strings "~1.1.0" 1284 | gauge "~2.7.3" 1285 | set-blocking "~2.0.0" 1286 | 1287 | number-is-nan@^1.0.0: 1288 | version "1.0.1" 1289 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1290 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 1291 | 1292 | object-assign@^4, object-assign@^4.1.0: 1293 | version "4.1.1" 1294 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1295 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 1296 | 1297 | on-exit-leak-free@^0.2.0: 1298 | version "0.2.0" 1299 | resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-0.2.0.tgz#b39c9e3bf7690d890f4861558b0d7b90a442d209" 1300 | integrity sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg== 1301 | 1302 | on-finished@~2.3.0: 1303 | version "2.3.0" 1304 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1305 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 1306 | dependencies: 1307 | ee-first "1.1.1" 1308 | 1309 | on-headers@~1.0.1: 1310 | version "1.0.2" 1311 | resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" 1312 | integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== 1313 | 1314 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 1315 | version "1.4.0" 1316 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1317 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 1318 | dependencies: 1319 | wrappy "1" 1320 | 1321 | parseurl@~1.3.3: 1322 | version "1.3.3" 1323 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 1324 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 1325 | 1326 | path-is-absolute@^1.0.0: 1327 | version "1.0.1" 1328 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1329 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1330 | 1331 | path-parse@^1.0.6: 1332 | version "1.0.7" 1333 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 1334 | integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== 1335 | 1336 | path-to-regexp@0.1.7: 1337 | version "0.1.7" 1338 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 1339 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 1340 | 1341 | picomatch@^2.0.4, picomatch@^2.2.1: 1342 | version "2.3.0" 1343 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" 1344 | integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== 1345 | 1346 | pino-abstract-transport@^0.4.0, pino-abstract-transport@v0.4.0: 1347 | version "0.4.0" 1348 | resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-0.4.0.tgz#be5913fa55542f82fccb77f6a9e04735fa583cac" 1349 | integrity sha512-Znl3f1ntZnDG+NpCyJyJDS+lkrlRSbgQBkV3eqNAvet/QHql6rhKLc4DuYRlwfc3fvV611O9NXPm5pbT9AJ50g== 1350 | dependencies: 1351 | duplexify "^4.1.2" 1352 | split2 "^3.2.2" 1353 | 1354 | pino-pretty@^7.1.0: 1355 | version "7.1.0" 1356 | resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-7.1.0.tgz#bfd16e6919985a141eb8c1c2e5c87d5fa3f7bb77" 1357 | integrity sha512-khuvWuuf2ABRp388AlPOv3sOzj+zEgnj9EeFOXw1VUqmSuPK1JqKfdvITk6prhxddVgnjQtbi5x63QeIcWencw== 1358 | dependencies: 1359 | args "^5.0.1" 1360 | colorette "^2.0.7" 1361 | dateformat "^4.6.3" 1362 | fast-safe-stringify "^2.0.7" 1363 | joycon "^3.0.0" 1364 | pino-abstract-transport "^0.4.0" 1365 | pump "^3.0.0" 1366 | readable-stream "^3.6.0" 1367 | rfdc "^1.3.0" 1368 | secure-json-parse "^2.4.0" 1369 | sonic-boom "^2.2.0" 1370 | strip-json-comments "^3.1.1" 1371 | 1372 | pino-std-serializers@^4.0.0: 1373 | version "4.0.0" 1374 | resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz#1791ccd2539c091ae49ce9993205e2cd5dbba1e2" 1375 | integrity sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q== 1376 | 1377 | pino@^7.0.2: 1378 | version "7.0.2" 1379 | resolved "https://registry.yarnpkg.com/pino/-/pino-7.0.2.tgz#9b9e8d9d882add253ba4e7d6e9299740ad40a23d" 1380 | integrity sha512-ArRw6tLKDi+AaOenkxfs4pqdaQuEXKTuNtsMaa8W0muAGINntBGethgskfPhQRDC18I+zgcDpEVRrWNCKKIP2w== 1381 | dependencies: 1382 | fast-redact "^3.0.0" 1383 | fastify-warning "^0.2.0" 1384 | get-caller-file "^2.0.5" 1385 | json-stringify-safe "^5.0.1" 1386 | on-exit-leak-free "^0.2.0" 1387 | pino-abstract-transport v0.4.0 1388 | pino-std-serializers "^4.0.0" 1389 | quick-format-unescaped "^4.0.3" 1390 | sonic-boom "^2.2.1" 1391 | thread-stream "^0.11.1" 1392 | 1393 | process-nextick-args@~2.0.0: 1394 | version "2.0.1" 1395 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1396 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1397 | 1398 | prom-client@^14.0.0: 1399 | version "14.0.0" 1400 | resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.0.0.tgz#7af5a0f8f544743f0dee4447c06ac9bb0d052719" 1401 | integrity sha512-etPa4SMO4j6qTn2uaSZy7+uahGK0kXUZwO7WhoDpTf3yZ837I3jqUDYmG6N0caxuU6cyqrg0xmOxh+yneczvyA== 1402 | dependencies: 1403 | tdigest "^0.1.1" 1404 | 1405 | proxy-addr@~2.0.5: 1406 | version "2.0.7" 1407 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" 1408 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 1409 | dependencies: 1410 | forwarded "0.2.0" 1411 | ipaddr.js "1.9.1" 1412 | 1413 | pump@^3.0.0: 1414 | version "3.0.0" 1415 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 1416 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 1417 | dependencies: 1418 | end-of-stream "^1.1.0" 1419 | once "^1.3.1" 1420 | 1421 | punycode@^2.1.1: 1422 | version "2.1.1" 1423 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 1424 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== 1425 | 1426 | qs@6.7.0: 1427 | version "6.7.0" 1428 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 1429 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 1430 | 1431 | quick-format-unescaped@^4.0.3: 1432 | version "4.0.4" 1433 | resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" 1434 | integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== 1435 | 1436 | range-parser@~1.2.1: 1437 | version "1.2.1" 1438 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 1439 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 1440 | 1441 | raw-body@2.4.0: 1442 | version "2.4.0" 1443 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 1444 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== 1445 | dependencies: 1446 | bytes "3.1.0" 1447 | http-errors "1.7.2" 1448 | iconv-lite "0.4.24" 1449 | unpipe "1.0.0" 1450 | 1451 | readable-stream@^2.0.6: 1452 | version "2.3.7" 1453 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 1454 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 1455 | dependencies: 1456 | core-util-is "~1.0.0" 1457 | inherits "~2.0.3" 1458 | isarray "~1.0.0" 1459 | process-nextick-args "~2.0.0" 1460 | safe-buffer "~5.1.1" 1461 | string_decoder "~1.1.1" 1462 | util-deprecate "~1.0.1" 1463 | 1464 | readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.6.0: 1465 | version "3.6.0" 1466 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" 1467 | integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== 1468 | dependencies: 1469 | inherits "^2.0.3" 1470 | string_decoder "^1.1.1" 1471 | util-deprecate "^1.0.1" 1472 | 1473 | readdirp@~3.6.0: 1474 | version "3.6.0" 1475 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 1476 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 1477 | dependencies: 1478 | picomatch "^2.2.1" 1479 | 1480 | regexp-clone@1.0.0, regexp-clone@^1.0.0: 1481 | version "1.0.0" 1482 | resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" 1483 | integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== 1484 | 1485 | resolve@^1.0.0: 1486 | version "1.20.0" 1487 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" 1488 | integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== 1489 | dependencies: 1490 | is-core-module "^2.2.0" 1491 | path-parse "^1.0.6" 1492 | 1493 | response-time@^2.3.2: 1494 | version "2.3.2" 1495 | resolved "https://registry.yarnpkg.com/response-time/-/response-time-2.3.2.tgz#ffa71bab952d62f7c1d49b7434355fbc68dffc5a" 1496 | integrity sha1-/6cbq5UtYvfB1Jt0NDVfvGjf/Fo= 1497 | dependencies: 1498 | depd "~1.1.0" 1499 | on-headers "~1.0.1" 1500 | 1501 | rfdc@^1.3.0: 1502 | version "1.3.0" 1503 | resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" 1504 | integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== 1505 | 1506 | rimraf@^2.6.1: 1507 | version "2.7.1" 1508 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 1509 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== 1510 | dependencies: 1511 | glob "^7.1.3" 1512 | 1513 | rimraf@^3.0.2: 1514 | version "3.0.2" 1515 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1516 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1517 | dependencies: 1518 | glob "^7.1.3" 1519 | 1520 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1521 | version "5.1.2" 1522 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1523 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1524 | 1525 | safe-buffer@^5.0.1, safe-buffer@~5.2.0: 1526 | version "5.2.1" 1527 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1528 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1529 | 1530 | "safer-buffer@>= 2.1.2 < 3": 1531 | version "2.1.2" 1532 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1533 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1534 | 1535 | saslprep@^1.0.3: 1536 | version "1.0.3" 1537 | resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" 1538 | integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== 1539 | dependencies: 1540 | sparse-bitfield "^3.0.3" 1541 | 1542 | secure-json-parse@^2.4.0: 1543 | version "2.4.0" 1544 | resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.4.0.tgz#5aaeaaef85c7a417f76271a4f5b0cc3315ddca85" 1545 | integrity sha512-Q5Z/97nbON5t/L/sH6mY2EacfjVGwrCcSi5D3btRO2GZ8pf1K1UN7Z9H5J57hjVU2Qzxr1xO+FmBhOvEkzCMmg== 1546 | 1547 | semver@^5.6.0: 1548 | version "5.7.1" 1549 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1550 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1551 | 1552 | semver@^6.0.0: 1553 | version "6.3.0" 1554 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 1555 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 1556 | 1557 | semver@^7.3.4: 1558 | version "7.3.5" 1559 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" 1560 | integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== 1561 | dependencies: 1562 | lru-cache "^6.0.0" 1563 | 1564 | send@0.17.1: 1565 | version "0.17.1" 1566 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" 1567 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== 1568 | dependencies: 1569 | debug "2.6.9" 1570 | depd "~1.1.2" 1571 | destroy "~1.0.4" 1572 | encodeurl "~1.0.2" 1573 | escape-html "~1.0.3" 1574 | etag "~1.8.1" 1575 | fresh "0.5.2" 1576 | http-errors "~1.7.2" 1577 | mime "1.6.0" 1578 | ms "2.1.1" 1579 | on-finished "~2.3.0" 1580 | range-parser "~1.2.1" 1581 | statuses "~1.5.0" 1582 | 1583 | serve-static@1.14.1: 1584 | version "1.14.1" 1585 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" 1586 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== 1587 | dependencies: 1588 | encodeurl "~1.0.2" 1589 | escape-html "~1.0.3" 1590 | parseurl "~1.3.3" 1591 | send "0.17.1" 1592 | 1593 | set-blocking@~2.0.0: 1594 | version "2.0.0" 1595 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1596 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 1597 | 1598 | setprototypeof@1.1.1: 1599 | version "1.1.1" 1600 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 1601 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 1602 | 1603 | sift@13.5.2: 1604 | version "13.5.2" 1605 | resolved "https://registry.yarnpkg.com/sift/-/sift-13.5.2.tgz#24a715e13c617b086166cd04917d204a591c9da6" 1606 | integrity sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA== 1607 | 1608 | signal-exit@^3.0.0: 1609 | version "3.0.5" 1610 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.5.tgz#9e3e8cc0c75a99472b44321033a7702e7738252f" 1611 | integrity sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ== 1612 | 1613 | sliced@1.0.1: 1614 | version "1.0.1" 1615 | resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" 1616 | integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= 1617 | 1618 | sonic-boom@^2.1.0, sonic-boom@^2.2.0, sonic-boom@^2.2.1: 1619 | version "2.3.0" 1620 | resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-2.3.0.tgz#b1622bbd29111ed12be94a644ea6b586b6daea70" 1621 | integrity sha512-lEPaw654/4/rCJHz/TNzV4GIthqCq4inO+O3aFhbdOvR1bE+2//sVkcS+xlqPdb8gdjQCEE0hE9BuvnVixbnWQ== 1622 | dependencies: 1623 | atomic-sleep "^1.0.0" 1624 | 1625 | source-map-support@^0.5.12, source-map-support@^0.5.17: 1626 | version "0.5.20" 1627 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" 1628 | integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== 1629 | dependencies: 1630 | buffer-from "^1.0.0" 1631 | source-map "^0.6.0" 1632 | 1633 | source-map@^0.6.0: 1634 | version "0.6.1" 1635 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1636 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 1637 | 1638 | sparse-bitfield@^3.0.3: 1639 | version "3.0.3" 1640 | resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" 1641 | integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= 1642 | dependencies: 1643 | memory-pager "^1.0.2" 1644 | 1645 | split2@^3.2.2: 1646 | version "3.2.2" 1647 | resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" 1648 | integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== 1649 | dependencies: 1650 | readable-stream "^3.0.0" 1651 | 1652 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 1653 | version "1.5.0" 1654 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 1655 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 1656 | 1657 | stream-shift@^1.0.0: 1658 | version "1.0.1" 1659 | resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" 1660 | integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== 1661 | 1662 | string-width@^1.0.1: 1663 | version "1.0.2" 1664 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1665 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 1666 | dependencies: 1667 | code-point-at "^1.0.0" 1668 | is-fullwidth-code-point "^1.0.0" 1669 | strip-ansi "^3.0.0" 1670 | 1671 | "string-width@^1.0.2 || 2 || 3 || 4": 1672 | version "4.2.3" 1673 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 1674 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 1675 | dependencies: 1676 | emoji-regex "^8.0.0" 1677 | is-fullwidth-code-point "^3.0.0" 1678 | strip-ansi "^6.0.1" 1679 | 1680 | string_decoder@^1.1.1: 1681 | version "1.3.0" 1682 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" 1683 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== 1684 | dependencies: 1685 | safe-buffer "~5.2.0" 1686 | 1687 | string_decoder@~1.1.1: 1688 | version "1.1.1" 1689 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1690 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1691 | dependencies: 1692 | safe-buffer "~5.1.0" 1693 | 1694 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1695 | version "3.0.1" 1696 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1697 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 1698 | dependencies: 1699 | ansi-regex "^2.0.0" 1700 | 1701 | strip-ansi@^6.0.1: 1702 | version "6.0.1" 1703 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1704 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1705 | dependencies: 1706 | ansi-regex "^5.0.1" 1707 | 1708 | strip-bom@^3.0.0: 1709 | version "3.0.0" 1710 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1711 | integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= 1712 | 1713 | strip-json-comments@^2.0.0: 1714 | version "2.0.1" 1715 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1716 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1717 | 1718 | strip-json-comments@^3.1.1: 1719 | version "3.1.1" 1720 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 1721 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 1722 | 1723 | supports-color@^5.3.0: 1724 | version "5.5.0" 1725 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1726 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1727 | dependencies: 1728 | has-flag "^3.0.0" 1729 | 1730 | swagger-jsdoc@^6.1.0: 1731 | version "6.1.0" 1732 | resolved "https://registry.yarnpkg.com/swagger-jsdoc/-/swagger-jsdoc-6.1.0.tgz#c2b86321f2c4dde8947b418fe8a4bc94431d5522" 1733 | integrity sha512-xgep5M8Gq31MxpCbQLvJZpNqHfGPfI+sILCzujZbEXIQp2COtkZgoGASs0gacRs4xHmLDH+GuMGdorPITSG4tA== 1734 | dependencies: 1735 | commander "6.2.0" 1736 | doctrine "3.0.0" 1737 | glob "7.1.6" 1738 | lodash.mergewith "^4.6.2" 1739 | swagger-parser "10.0.2" 1740 | yaml "2.0.0-1" 1741 | 1742 | swagger-parser@10.0.2: 1743 | version "10.0.2" 1744 | resolved "https://registry.yarnpkg.com/swagger-parser/-/swagger-parser-10.0.2.tgz#d7f18faa09c9c145e938977c9bd6c3435998b667" 1745 | integrity sha512-9jHkHM+QXyLGFLk1DkXBwV+4HyNm0Za3b8/zk/+mjr8jgOSiqm3FOTHBSDsBjtn9scdL+8eWcHdupp2NLM8tDw== 1746 | dependencies: 1747 | "@apidevtools/swagger-parser" "10.0.2" 1748 | 1749 | swagger-ui-dist@^3.18.1: 1750 | version "3.52.5" 1751 | resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.52.5.tgz#9aa8101a2be751f5145195b9e048bc21b12fac60" 1752 | integrity sha512-8z18eX8G/jbTXYzyNIaobrnD7PSN7yU/YkSasMmajrXtw0FGS64XjrKn5v37d36qmU3o1xLeuYnktshRr7uIFw== 1753 | 1754 | swagger-ui-express@^4.1.6: 1755 | version "4.1.6" 1756 | resolved "https://registry.yarnpkg.com/swagger-ui-express/-/swagger-ui-express-4.1.6.tgz#682294af3d5c70f74a1fa4d6a9b503a9ee55ea82" 1757 | integrity sha512-Xs2BGGudvDBtL7RXcYtNvHsFtP1DBFPMJFRxHe5ez/VG/rzVOEjazJOOSc/kSCyxreCTKfJrII6MJlL9a6t8vw== 1758 | dependencies: 1759 | swagger-ui-dist "^3.18.1" 1760 | 1761 | tar@^6.1.0: 1762 | version "6.1.11" 1763 | resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" 1764 | integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== 1765 | dependencies: 1766 | chownr "^2.0.0" 1767 | fs-minipass "^2.0.0" 1768 | minipass "^3.0.0" 1769 | minizlib "^2.1.1" 1770 | mkdirp "^1.0.3" 1771 | yallist "^4.0.0" 1772 | 1773 | tdigest@^0.1.1: 1774 | version "0.1.1" 1775 | resolved "https://registry.yarnpkg.com/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" 1776 | integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE= 1777 | dependencies: 1778 | bintrees "1.0.1" 1779 | 1780 | thread-stream@^0.11.1: 1781 | version "0.11.1" 1782 | resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-0.11.1.tgz#9af0f4b4b9b44744729897bc1665decb2bad2315" 1783 | integrity sha512-YbZEIo+JcScRekY1bl7O717RZGA/1eT7t4n9uyKf5Fu7TYpZKuml185bQdV3l2pgoq0wCobkQySWxdNEORkghg== 1784 | 1785 | to-regex-range@^5.0.1: 1786 | version "5.0.1" 1787 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1788 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1789 | dependencies: 1790 | is-number "^7.0.0" 1791 | 1792 | toidentifier@1.0.0: 1793 | version "1.0.0" 1794 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 1795 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 1796 | 1797 | tr46@^2.1.0: 1798 | version "2.1.0" 1799 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" 1800 | integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== 1801 | dependencies: 1802 | punycode "^2.1.1" 1803 | 1804 | tr46@~0.0.3: 1805 | version "0.0.3" 1806 | resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 1807 | integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= 1808 | 1809 | tree-kill@^1.2.2: 1810 | version "1.2.2" 1811 | resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" 1812 | integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== 1813 | 1814 | ts-node-dev@^1.1.8: 1815 | version "1.1.8" 1816 | resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.1.8.tgz#95520d8ab9d45fffa854d6668e2f8f9286241066" 1817 | integrity sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg== 1818 | dependencies: 1819 | chokidar "^3.5.1" 1820 | dynamic-dedupe "^0.3.0" 1821 | minimist "^1.2.5" 1822 | mkdirp "^1.0.4" 1823 | resolve "^1.0.0" 1824 | rimraf "^2.6.1" 1825 | source-map-support "^0.5.12" 1826 | tree-kill "^1.2.2" 1827 | ts-node "^9.0.0" 1828 | tsconfig "^7.0.0" 1829 | 1830 | ts-node@^9.0.0: 1831 | version "9.1.1" 1832 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" 1833 | integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== 1834 | dependencies: 1835 | arg "^4.1.0" 1836 | create-require "^1.1.0" 1837 | diff "^4.0.1" 1838 | make-error "^1.1.1" 1839 | source-map-support "^0.5.17" 1840 | yn "3.1.1" 1841 | 1842 | tsconfig@^7.0.0: 1843 | version "7.0.0" 1844 | resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" 1845 | integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== 1846 | dependencies: 1847 | "@types/strip-bom" "^3.0.0" 1848 | "@types/strip-json-comments" "0.0.30" 1849 | strip-bom "^3.0.0" 1850 | strip-json-comments "^2.0.0" 1851 | 1852 | type-is@~1.6.17, type-is@~1.6.18: 1853 | version "1.6.18" 1854 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 1855 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1856 | dependencies: 1857 | media-typer "0.3.0" 1858 | mime-types "~2.1.24" 1859 | 1860 | typescript@^4.4.4: 1861 | version "4.4.4" 1862 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.4.tgz#2cd01a1a1f160704d3101fd5a58ff0f9fcb8030c" 1863 | integrity sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA== 1864 | 1865 | unpipe@1.0.0, unpipe@~1.0.0: 1866 | version "1.0.0" 1867 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1868 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 1869 | 1870 | util-deprecate@^1.0.1, util-deprecate@~1.0.1: 1871 | version "1.0.2" 1872 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1873 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1874 | 1875 | utils-merge@1.0.1: 1876 | version "1.0.1" 1877 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1878 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 1879 | 1880 | validator@^13.6.0: 1881 | version "13.7.0" 1882 | resolved "https://registry.yarnpkg.com/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" 1883 | integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== 1884 | 1885 | vary@^1, vary@~1.1.2: 1886 | version "1.1.2" 1887 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1888 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 1889 | 1890 | webidl-conversions@^3.0.0: 1891 | version "3.0.1" 1892 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 1893 | integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= 1894 | 1895 | webidl-conversions@^6.1.0: 1896 | version "6.1.0" 1897 | resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" 1898 | integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== 1899 | 1900 | whatwg-url@^5.0.0: 1901 | version "5.0.0" 1902 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 1903 | integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= 1904 | dependencies: 1905 | tr46 "~0.0.3" 1906 | webidl-conversions "^3.0.0" 1907 | 1908 | whatwg-url@^9.1.0: 1909 | version "9.1.0" 1910 | resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-9.1.0.tgz#1b112cf237d72cd64fa7882b9c3f6234a1c3050d" 1911 | integrity sha512-CQ0UcrPHyomtlOCot1TL77WyMIm/bCwrJ2D6AOKGwEczU9EpyoqAokfqrf/MioU9kHcMsmJZcg1egXix2KYEsA== 1912 | dependencies: 1913 | tr46 "^2.1.0" 1914 | webidl-conversions "^6.1.0" 1915 | 1916 | wide-align@^1.1.0: 1917 | version "1.1.5" 1918 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" 1919 | integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== 1920 | dependencies: 1921 | string-width "^1.0.2 || 2 || 3 || 4" 1922 | 1923 | wrappy@1: 1924 | version "1.0.2" 1925 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1926 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1927 | 1928 | xtend@^4.0.0: 1929 | version "4.0.2" 1930 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 1931 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 1932 | 1933 | yallist@^4.0.0: 1934 | version "4.0.0" 1935 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1936 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1937 | 1938 | yaml@2.0.0-1: 1939 | version "2.0.0-1" 1940 | resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.0.0-1.tgz#8c3029b3ee2028306d5bcf396980623115ff8d18" 1941 | integrity sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ== 1942 | 1943 | yn@3.1.1: 1944 | version "3.1.1" 1945 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 1946 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 1947 | 1948 | z-schema@^4.2.3: 1949 | version "4.2.4" 1950 | resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-4.2.4.tgz#73102a49512179b12a8ec50b1daa676b984da6e4" 1951 | integrity sha512-YvBeW5RGNeNzKOUJs3rTL4+9rpcvHXt5I051FJbOcitV8bl40pEfcG0Q+dWSwS0/BIYrMZ/9HHoqLllMkFhD0w== 1952 | dependencies: 1953 | lodash.get "^4.4.2" 1954 | lodash.isequal "^4.5.0" 1955 | validator "^13.6.0" 1956 | optionalDependencies: 1957 | commander "^2.7.1" 1958 | 1959 | zod@^3.9.8: 1960 | version "3.9.8" 1961 | resolved "https://registry.yarnpkg.com/zod/-/zod-3.9.8.tgz#562eda33925203542dea70100ce0d3766d04b0ab" 1962 | integrity sha512-pTNhdJd45PPOBpdxO8x00Tv+HhknYGx3WdgFQndazp+G1Gd2Cxf81L5yMfCIIcd/SA3VqrcTv/G4bFcr+DsZhA== 1963 | --------------------------------------------------------------------------------