├── .github └── workflows │ └── ci.yml ├── .gitignore ├── ARCHITECTURE.md ├── LICENSE ├── README.md ├── examples ├── express-app │ ├── package-lock.json │ ├── package.json │ └── server │ │ └── app.js └── express-ts-app │ ├── package-lock.json │ ├── package.json │ ├── server │ └── app.ts │ └── tsconfig.json ├── lib └── main.js ├── main.d.ts ├── package-lock.json ├── package.json ├── screenshots ├── showcase.png └── social-preview.png ├── src ├── cli.js ├── printer.js ├── routes.js └── utils.js └── test ├── express.test.js ├── fastify.test.js ├── hapi.test.js ├── koa.test.js └── utils.test.js /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | pull_request: 7 | branches: [master] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [18.x] 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Use Node.js ${{ matrix.node-version }} 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: ${{ matrix.node-version }} 23 | - name: Install dependencies 24 | run: npm ci 25 | - name: Run tests 26 | run: npm test 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tmp 3 | dist -------------------------------------------------------------------------------- /ARCHITECTURE.md: -------------------------------------------------------------------------------- 1 | # ARCHITECTURE 2 | 3 | ## Background 4 | 5 | Initially, the following implementation approaches were considered: 6 | 7 | - Runtime (requiring/importing app) 8 | - Static Analysis (crawling source code) 9 | 10 | However, due to fragmentation is Node's ecosystem of frameworks (Express, Hapi, 11 | Fastify...), module systems (ESM/CJS) and project structures, doing static 12 | analysis would be extremely difficult, slow and would probably not work for the 13 | majority of projects. 14 | 15 | ## Implementation 16 | 17 | Choosing runtime option made implementation straightforward and allows greater 18 | future project extensibility. The only thing we require is server app export 19 | which is usually done anyways in most projects. 20 | 21 | The program's flow can be broken down in the following steps: 22 | 23 | - CLI options and arguments validation 24 | - Initializing application's environment (.env) 25 | - (Optional) compiling TypeScript app.ts to app.js 26 | - Importing application 27 | - Detecting web framework 28 | - Parsing routes 29 | - Printing routes 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Vladimir Mikulic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # route-list 2 | 3 | ![Version](https://img.shields.io/npm/v/route-list) 4 | ![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg) 5 | [![CI](https://github.com/VladimirMikulic/route-list/actions/workflows/ci.yml/badge.svg)](https://github.com/VladimirMikulic/route-list/actions) 6 | [![Twitter: VladoDev](https://img.shields.io/twitter/follow/VladoDev.svg?style=social)](https://twitter.com/VladoDev) 7 | 8 | > ✨ Beautifully shows Express/Koa/Hapi/Fastify routes in CLI. 9 | 10 | ![route-list CLI example](./screenshots/showcase.png) 11 | 12 | ## 📦 Installation 13 | 14 | ```sh 15 | # Installs the package so it's globally accessible in terminal 16 | npm i route-list -g 17 | ``` 18 | 19 | ## 🔌 Configuration 20 | 21 | Before you can use `route-list` on your project, we first need to make sure it's configured properly. 22 | In order for `route-list` to work, we need to export server "app". 23 | The example below is for Express but it also applies to Koa (with @koa/router)/Hapi/Fastify. 24 | 25 | **app.js** / **app.ts** 26 | 27 | ```js 28 | const app = express(); 29 | 30 | app.get('/', (req, res) => res.sendStatus(200)); 31 | app.get('/products', (req, res) => res.sendStatus(200)); 32 | app.get('/products/:id', (req, res) => res.sendStatus(200)); 33 | 34 | // CJS 35 | // Option 1: module.exports = app; 36 | // Option 2: module.exports = { app, yourOtherExports... }; 37 | // Option 3: module.exports = functionThatReturnsApp; 38 | 39 | // ESM 40 | // Option 1: export default app; 41 | // Option 2: export default { app, yourOtherExports... }; 42 | // Option 3: export default functionThatReturnsApp; 43 | ``` 44 | 45 | > NOTE: In case you use [SocketIO with Express](https://socket.io/get-started/chat#the-web-framework), make sure to **export Express app**, not `http.createServer` server instance. 46 | 47 | ## ☁️ Usage 48 | 49 | ### Options 50 | 51 | - `-g, --group` - Display routes in groups separated with new line 52 | - `-m, --methods ` - Include routes registered for HTTP method(s) 53 | - `-i, --include-paths ` - Include routes starting with path(s) 54 | - `-e, --exclude-paths ` - Exclude routes starting with path(s) 55 | 56 | ### Examples 57 | 58 | ```sh 59 | route-list server/app.js 60 | ``` 61 | 62 | ```sh 63 | route-list --group server/app.js 64 | ``` 65 | 66 | ```sh 67 | route-list --methods GET,POST server/app.js 68 | ``` 69 | 70 | > NOTE: In case an app is part of NX monorepo, make sure to build it first. 71 | 72 | ## 💻 Programmatic Usage 73 | 74 | ```js 75 | import RouteList from 'route-list'; 76 | 77 | // Example result { "/": ["GET"], "/users": ["GET", "POST"] } 78 | const routesMap = RouteList.getRoutes(app, 'express'); 79 | 80 | // Print routes to console 81 | RouteList.printRoutes(routesMap); 82 | ``` 83 | 84 | ## 👨 Author 85 | 86 | **Vladimir Mikulic** 87 | 88 | - Twitter: [@VladoDev](https://twitter.com/VladoDev) 89 | - Github: [@VladimirMikulic](https://github.com/VladimirMikulic) 90 | - LinkedIn: [@vladimirmikulic](https://www.linkedin.com/in/vladimir-mikulic/) 91 | 92 | ## 🤝 Contributing 93 | 94 | Contributions, issues and feature requests are welcome! 95 | 96 | ## 🍻 Credits 97 | 98 | The project was inspired by new `route:list` command in Laravel 9. 99 | New [`route:list`](https://github.com/laravel/framework/pull/40269) itself was 100 | inspired by [`pretty-routes`](https://github.com/Wulfheart/pretty-routes) project. 101 | Big thanks to [Λlex Wulf](https://twitter.com/alexfwulf) for building 102 | `pretty-routes` and Laravel community for recognizing the usefulness of the project. 103 | 104 | ## ✏️ License 105 | 106 | This project is licensed under [MIT](https://opensource.org/licenses/MIT) license. 107 | 108 | ## 👨‍🚀 Show your support 109 | 110 | Give a ⭐️ if this project helped you! 111 | -------------------------------------------------------------------------------- /examples/express-app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "express-example", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "dependencies": { 12 | "express": "^4.18.2" 13 | } 14 | }, 15 | "node_modules/accepts": { 16 | "version": "1.3.8", 17 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 18 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 19 | "dependencies": { 20 | "mime-types": "~2.1.34", 21 | "negotiator": "0.6.3" 22 | }, 23 | "engines": { 24 | "node": ">= 0.6" 25 | } 26 | }, 27 | "node_modules/array-flatten": { 28 | "version": "1.1.1", 29 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 30 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 31 | }, 32 | "node_modules/body-parser": { 33 | "version": "1.20.1", 34 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 35 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 36 | "dependencies": { 37 | "bytes": "3.1.2", 38 | "content-type": "~1.0.4", 39 | "debug": "2.6.9", 40 | "depd": "2.0.0", 41 | "destroy": "1.2.0", 42 | "http-errors": "2.0.0", 43 | "iconv-lite": "0.4.24", 44 | "on-finished": "2.4.1", 45 | "qs": "6.11.0", 46 | "raw-body": "2.5.1", 47 | "type-is": "~1.6.18", 48 | "unpipe": "1.0.0" 49 | }, 50 | "engines": { 51 | "node": ">= 0.8", 52 | "npm": "1.2.8000 || >= 1.4.16" 53 | } 54 | }, 55 | "node_modules/bytes": { 56 | "version": "3.1.2", 57 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 58 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 59 | "engines": { 60 | "node": ">= 0.8" 61 | } 62 | }, 63 | "node_modules/call-bind": { 64 | "version": "1.0.2", 65 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 66 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 67 | "dependencies": { 68 | "function-bind": "^1.1.1", 69 | "get-intrinsic": "^1.0.2" 70 | }, 71 | "funding": { 72 | "url": "https://github.com/sponsors/ljharb" 73 | } 74 | }, 75 | "node_modules/content-disposition": { 76 | "version": "0.5.4", 77 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 78 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 79 | "dependencies": { 80 | "safe-buffer": "5.2.1" 81 | }, 82 | "engines": { 83 | "node": ">= 0.6" 84 | } 85 | }, 86 | "node_modules/content-type": { 87 | "version": "1.0.4", 88 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 89 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 90 | "engines": { 91 | "node": ">= 0.6" 92 | } 93 | }, 94 | "node_modules/cookie": { 95 | "version": "0.5.0", 96 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 97 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 98 | "engines": { 99 | "node": ">= 0.6" 100 | } 101 | }, 102 | "node_modules/cookie-signature": { 103 | "version": "1.0.6", 104 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 105 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 106 | }, 107 | "node_modules/debug": { 108 | "version": "2.6.9", 109 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 110 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 111 | "dependencies": { 112 | "ms": "2.0.0" 113 | } 114 | }, 115 | "node_modules/depd": { 116 | "version": "2.0.0", 117 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 118 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 119 | "engines": { 120 | "node": ">= 0.8" 121 | } 122 | }, 123 | "node_modules/destroy": { 124 | "version": "1.2.0", 125 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 126 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 127 | "engines": { 128 | "node": ">= 0.8", 129 | "npm": "1.2.8000 || >= 1.4.16" 130 | } 131 | }, 132 | "node_modules/ee-first": { 133 | "version": "1.1.1", 134 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 135 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 136 | }, 137 | "node_modules/encodeurl": { 138 | "version": "1.0.2", 139 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 140 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 141 | "engines": { 142 | "node": ">= 0.8" 143 | } 144 | }, 145 | "node_modules/escape-html": { 146 | "version": "1.0.3", 147 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 148 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 149 | }, 150 | "node_modules/etag": { 151 | "version": "1.8.1", 152 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 153 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 154 | "engines": { 155 | "node": ">= 0.6" 156 | } 157 | }, 158 | "node_modules/express": { 159 | "version": "4.18.2", 160 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 161 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 162 | "dependencies": { 163 | "accepts": "~1.3.8", 164 | "array-flatten": "1.1.1", 165 | "body-parser": "1.20.1", 166 | "content-disposition": "0.5.4", 167 | "content-type": "~1.0.4", 168 | "cookie": "0.5.0", 169 | "cookie-signature": "1.0.6", 170 | "debug": "2.6.9", 171 | "depd": "2.0.0", 172 | "encodeurl": "~1.0.2", 173 | "escape-html": "~1.0.3", 174 | "etag": "~1.8.1", 175 | "finalhandler": "1.2.0", 176 | "fresh": "0.5.2", 177 | "http-errors": "2.0.0", 178 | "merge-descriptors": "1.0.1", 179 | "methods": "~1.1.2", 180 | "on-finished": "2.4.1", 181 | "parseurl": "~1.3.3", 182 | "path-to-regexp": "0.1.7", 183 | "proxy-addr": "~2.0.7", 184 | "qs": "6.11.0", 185 | "range-parser": "~1.2.1", 186 | "safe-buffer": "5.2.1", 187 | "send": "0.18.0", 188 | "serve-static": "1.15.0", 189 | "setprototypeof": "1.2.0", 190 | "statuses": "2.0.1", 191 | "type-is": "~1.6.18", 192 | "utils-merge": "1.0.1", 193 | "vary": "~1.1.2" 194 | }, 195 | "engines": { 196 | "node": ">= 0.10.0" 197 | } 198 | }, 199 | "node_modules/finalhandler": { 200 | "version": "1.2.0", 201 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 202 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 203 | "dependencies": { 204 | "debug": "2.6.9", 205 | "encodeurl": "~1.0.2", 206 | "escape-html": "~1.0.3", 207 | "on-finished": "2.4.1", 208 | "parseurl": "~1.3.3", 209 | "statuses": "2.0.1", 210 | "unpipe": "~1.0.0" 211 | }, 212 | "engines": { 213 | "node": ">= 0.8" 214 | } 215 | }, 216 | "node_modules/forwarded": { 217 | "version": "0.2.0", 218 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 219 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 220 | "engines": { 221 | "node": ">= 0.6" 222 | } 223 | }, 224 | "node_modules/fresh": { 225 | "version": "0.5.2", 226 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 227 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 228 | "engines": { 229 | "node": ">= 0.6" 230 | } 231 | }, 232 | "node_modules/function-bind": { 233 | "version": "1.1.1", 234 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 235 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 236 | }, 237 | "node_modules/get-intrinsic": { 238 | "version": "1.1.3", 239 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 240 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 241 | "dependencies": { 242 | "function-bind": "^1.1.1", 243 | "has": "^1.0.3", 244 | "has-symbols": "^1.0.3" 245 | }, 246 | "funding": { 247 | "url": "https://github.com/sponsors/ljharb" 248 | } 249 | }, 250 | "node_modules/has": { 251 | "version": "1.0.3", 252 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 253 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 254 | "dependencies": { 255 | "function-bind": "^1.1.1" 256 | }, 257 | "engines": { 258 | "node": ">= 0.4.0" 259 | } 260 | }, 261 | "node_modules/has-symbols": { 262 | "version": "1.0.3", 263 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 264 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 265 | "engines": { 266 | "node": ">= 0.4" 267 | }, 268 | "funding": { 269 | "url": "https://github.com/sponsors/ljharb" 270 | } 271 | }, 272 | "node_modules/http-errors": { 273 | "version": "2.0.0", 274 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 275 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 276 | "dependencies": { 277 | "depd": "2.0.0", 278 | "inherits": "2.0.4", 279 | "setprototypeof": "1.2.0", 280 | "statuses": "2.0.1", 281 | "toidentifier": "1.0.1" 282 | }, 283 | "engines": { 284 | "node": ">= 0.8" 285 | } 286 | }, 287 | "node_modules/iconv-lite": { 288 | "version": "0.4.24", 289 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 290 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 291 | "dependencies": { 292 | "safer-buffer": ">= 2.1.2 < 3" 293 | }, 294 | "engines": { 295 | "node": ">=0.10.0" 296 | } 297 | }, 298 | "node_modules/inherits": { 299 | "version": "2.0.4", 300 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 301 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 302 | }, 303 | "node_modules/ipaddr.js": { 304 | "version": "1.9.1", 305 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 306 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 307 | "engines": { 308 | "node": ">= 0.10" 309 | } 310 | }, 311 | "node_modules/media-typer": { 312 | "version": "0.3.0", 313 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 314 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 315 | "engines": { 316 | "node": ">= 0.6" 317 | } 318 | }, 319 | "node_modules/merge-descriptors": { 320 | "version": "1.0.1", 321 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 322 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 323 | }, 324 | "node_modules/methods": { 325 | "version": "1.1.2", 326 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 327 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 328 | "engines": { 329 | "node": ">= 0.6" 330 | } 331 | }, 332 | "node_modules/mime": { 333 | "version": "1.6.0", 334 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 335 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 336 | "bin": { 337 | "mime": "cli.js" 338 | }, 339 | "engines": { 340 | "node": ">=4" 341 | } 342 | }, 343 | "node_modules/mime-db": { 344 | "version": "1.52.0", 345 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 346 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 347 | "engines": { 348 | "node": ">= 0.6" 349 | } 350 | }, 351 | "node_modules/mime-types": { 352 | "version": "2.1.35", 353 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 354 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 355 | "dependencies": { 356 | "mime-db": "1.52.0" 357 | }, 358 | "engines": { 359 | "node": ">= 0.6" 360 | } 361 | }, 362 | "node_modules/ms": { 363 | "version": "2.0.0", 364 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 365 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 366 | }, 367 | "node_modules/negotiator": { 368 | "version": "0.6.3", 369 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 370 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 371 | "engines": { 372 | "node": ">= 0.6" 373 | } 374 | }, 375 | "node_modules/object-inspect": { 376 | "version": "1.12.2", 377 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 378 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 379 | "funding": { 380 | "url": "https://github.com/sponsors/ljharb" 381 | } 382 | }, 383 | "node_modules/on-finished": { 384 | "version": "2.4.1", 385 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 386 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 387 | "dependencies": { 388 | "ee-first": "1.1.1" 389 | }, 390 | "engines": { 391 | "node": ">= 0.8" 392 | } 393 | }, 394 | "node_modules/parseurl": { 395 | "version": "1.3.3", 396 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 397 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 398 | "engines": { 399 | "node": ">= 0.8" 400 | } 401 | }, 402 | "node_modules/path-to-regexp": { 403 | "version": "0.1.7", 404 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 405 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 406 | }, 407 | "node_modules/proxy-addr": { 408 | "version": "2.0.7", 409 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 410 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 411 | "dependencies": { 412 | "forwarded": "0.2.0", 413 | "ipaddr.js": "1.9.1" 414 | }, 415 | "engines": { 416 | "node": ">= 0.10" 417 | } 418 | }, 419 | "node_modules/qs": { 420 | "version": "6.11.0", 421 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 422 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 423 | "dependencies": { 424 | "side-channel": "^1.0.4" 425 | }, 426 | "engines": { 427 | "node": ">=0.6" 428 | }, 429 | "funding": { 430 | "url": "https://github.com/sponsors/ljharb" 431 | } 432 | }, 433 | "node_modules/range-parser": { 434 | "version": "1.2.1", 435 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 436 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 437 | "engines": { 438 | "node": ">= 0.6" 439 | } 440 | }, 441 | "node_modules/raw-body": { 442 | "version": "2.5.1", 443 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 444 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 445 | "dependencies": { 446 | "bytes": "3.1.2", 447 | "http-errors": "2.0.0", 448 | "iconv-lite": "0.4.24", 449 | "unpipe": "1.0.0" 450 | }, 451 | "engines": { 452 | "node": ">= 0.8" 453 | } 454 | }, 455 | "node_modules/safe-buffer": { 456 | "version": "5.2.1", 457 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 458 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 459 | "funding": [ 460 | { 461 | "type": "github", 462 | "url": "https://github.com/sponsors/feross" 463 | }, 464 | { 465 | "type": "patreon", 466 | "url": "https://www.patreon.com/feross" 467 | }, 468 | { 469 | "type": "consulting", 470 | "url": "https://feross.org/support" 471 | } 472 | ] 473 | }, 474 | "node_modules/safer-buffer": { 475 | "version": "2.1.2", 476 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 477 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 478 | }, 479 | "node_modules/send": { 480 | "version": "0.18.0", 481 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 482 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 483 | "dependencies": { 484 | "debug": "2.6.9", 485 | "depd": "2.0.0", 486 | "destroy": "1.2.0", 487 | "encodeurl": "~1.0.2", 488 | "escape-html": "~1.0.3", 489 | "etag": "~1.8.1", 490 | "fresh": "0.5.2", 491 | "http-errors": "2.0.0", 492 | "mime": "1.6.0", 493 | "ms": "2.1.3", 494 | "on-finished": "2.4.1", 495 | "range-parser": "~1.2.1", 496 | "statuses": "2.0.1" 497 | }, 498 | "engines": { 499 | "node": ">= 0.8.0" 500 | } 501 | }, 502 | "node_modules/send/node_modules/ms": { 503 | "version": "2.1.3", 504 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 505 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 506 | }, 507 | "node_modules/serve-static": { 508 | "version": "1.15.0", 509 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 510 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 511 | "dependencies": { 512 | "encodeurl": "~1.0.2", 513 | "escape-html": "~1.0.3", 514 | "parseurl": "~1.3.3", 515 | "send": "0.18.0" 516 | }, 517 | "engines": { 518 | "node": ">= 0.8.0" 519 | } 520 | }, 521 | "node_modules/setprototypeof": { 522 | "version": "1.2.0", 523 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 524 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 525 | }, 526 | "node_modules/side-channel": { 527 | "version": "1.0.4", 528 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 529 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 530 | "dependencies": { 531 | "call-bind": "^1.0.0", 532 | "get-intrinsic": "^1.0.2", 533 | "object-inspect": "^1.9.0" 534 | }, 535 | "funding": { 536 | "url": "https://github.com/sponsors/ljharb" 537 | } 538 | }, 539 | "node_modules/statuses": { 540 | "version": "2.0.1", 541 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 542 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 543 | "engines": { 544 | "node": ">= 0.8" 545 | } 546 | }, 547 | "node_modules/toidentifier": { 548 | "version": "1.0.1", 549 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 550 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 551 | "engines": { 552 | "node": ">=0.6" 553 | } 554 | }, 555 | "node_modules/type-is": { 556 | "version": "1.6.18", 557 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 558 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 559 | "dependencies": { 560 | "media-typer": "0.3.0", 561 | "mime-types": "~2.1.24" 562 | }, 563 | "engines": { 564 | "node": ">= 0.6" 565 | } 566 | }, 567 | "node_modules/unpipe": { 568 | "version": "1.0.0", 569 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 570 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 571 | "engines": { 572 | "node": ">= 0.8" 573 | } 574 | }, 575 | "node_modules/utils-merge": { 576 | "version": "1.0.1", 577 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 578 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 579 | "engines": { 580 | "node": ">= 0.4.0" 581 | } 582 | }, 583 | "node_modules/vary": { 584 | "version": "1.1.2", 585 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 586 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 587 | "engines": { 588 | "node": ">= 0.8" 589 | } 590 | } 591 | }, 592 | "dependencies": { 593 | "accepts": { 594 | "version": "1.3.8", 595 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 596 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 597 | "requires": { 598 | "mime-types": "~2.1.34", 599 | "negotiator": "0.6.3" 600 | } 601 | }, 602 | "array-flatten": { 603 | "version": "1.1.1", 604 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 605 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 606 | }, 607 | "body-parser": { 608 | "version": "1.20.1", 609 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 610 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 611 | "requires": { 612 | "bytes": "3.1.2", 613 | "content-type": "~1.0.4", 614 | "debug": "2.6.9", 615 | "depd": "2.0.0", 616 | "destroy": "1.2.0", 617 | "http-errors": "2.0.0", 618 | "iconv-lite": "0.4.24", 619 | "on-finished": "2.4.1", 620 | "qs": "6.11.0", 621 | "raw-body": "2.5.1", 622 | "type-is": "~1.6.18", 623 | "unpipe": "1.0.0" 624 | } 625 | }, 626 | "bytes": { 627 | "version": "3.1.2", 628 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 629 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 630 | }, 631 | "call-bind": { 632 | "version": "1.0.2", 633 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 634 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 635 | "requires": { 636 | "function-bind": "^1.1.1", 637 | "get-intrinsic": "^1.0.2" 638 | } 639 | }, 640 | "content-disposition": { 641 | "version": "0.5.4", 642 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 643 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 644 | "requires": { 645 | "safe-buffer": "5.2.1" 646 | } 647 | }, 648 | "content-type": { 649 | "version": "1.0.4", 650 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 651 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 652 | }, 653 | "cookie": { 654 | "version": "0.5.0", 655 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 656 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" 657 | }, 658 | "cookie-signature": { 659 | "version": "1.0.6", 660 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 661 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 662 | }, 663 | "debug": { 664 | "version": "2.6.9", 665 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 666 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 667 | "requires": { 668 | "ms": "2.0.0" 669 | } 670 | }, 671 | "depd": { 672 | "version": "2.0.0", 673 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 674 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 675 | }, 676 | "destroy": { 677 | "version": "1.2.0", 678 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 679 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" 680 | }, 681 | "ee-first": { 682 | "version": "1.1.1", 683 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 684 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 685 | }, 686 | "encodeurl": { 687 | "version": "1.0.2", 688 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 689 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 690 | }, 691 | "escape-html": { 692 | "version": "1.0.3", 693 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 694 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 695 | }, 696 | "etag": { 697 | "version": "1.8.1", 698 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 699 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 700 | }, 701 | "express": { 702 | "version": "4.18.2", 703 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 704 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 705 | "requires": { 706 | "accepts": "~1.3.8", 707 | "array-flatten": "1.1.1", 708 | "body-parser": "1.20.1", 709 | "content-disposition": "0.5.4", 710 | "content-type": "~1.0.4", 711 | "cookie": "0.5.0", 712 | "cookie-signature": "1.0.6", 713 | "debug": "2.6.9", 714 | "depd": "2.0.0", 715 | "encodeurl": "~1.0.2", 716 | "escape-html": "~1.0.3", 717 | "etag": "~1.8.1", 718 | "finalhandler": "1.2.0", 719 | "fresh": "0.5.2", 720 | "http-errors": "2.0.0", 721 | "merge-descriptors": "1.0.1", 722 | "methods": "~1.1.2", 723 | "on-finished": "2.4.1", 724 | "parseurl": "~1.3.3", 725 | "path-to-regexp": "0.1.7", 726 | "proxy-addr": "~2.0.7", 727 | "qs": "6.11.0", 728 | "range-parser": "~1.2.1", 729 | "safe-buffer": "5.2.1", 730 | "send": "0.18.0", 731 | "serve-static": "1.15.0", 732 | "setprototypeof": "1.2.0", 733 | "statuses": "2.0.1", 734 | "type-is": "~1.6.18", 735 | "utils-merge": "1.0.1", 736 | "vary": "~1.1.2" 737 | } 738 | }, 739 | "finalhandler": { 740 | "version": "1.2.0", 741 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 742 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 743 | "requires": { 744 | "debug": "2.6.9", 745 | "encodeurl": "~1.0.2", 746 | "escape-html": "~1.0.3", 747 | "on-finished": "2.4.1", 748 | "parseurl": "~1.3.3", 749 | "statuses": "2.0.1", 750 | "unpipe": "~1.0.0" 751 | } 752 | }, 753 | "forwarded": { 754 | "version": "0.2.0", 755 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 756 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 757 | }, 758 | "fresh": { 759 | "version": "0.5.2", 760 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 761 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 762 | }, 763 | "function-bind": { 764 | "version": "1.1.1", 765 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 766 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 767 | }, 768 | "get-intrinsic": { 769 | "version": "1.1.3", 770 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 771 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 772 | "requires": { 773 | "function-bind": "^1.1.1", 774 | "has": "^1.0.3", 775 | "has-symbols": "^1.0.3" 776 | } 777 | }, 778 | "has": { 779 | "version": "1.0.3", 780 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 781 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 782 | "requires": { 783 | "function-bind": "^1.1.1" 784 | } 785 | }, 786 | "has-symbols": { 787 | "version": "1.0.3", 788 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 789 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 790 | }, 791 | "http-errors": { 792 | "version": "2.0.0", 793 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 794 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 795 | "requires": { 796 | "depd": "2.0.0", 797 | "inherits": "2.0.4", 798 | "setprototypeof": "1.2.0", 799 | "statuses": "2.0.1", 800 | "toidentifier": "1.0.1" 801 | } 802 | }, 803 | "iconv-lite": { 804 | "version": "0.4.24", 805 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 806 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 807 | "requires": { 808 | "safer-buffer": ">= 2.1.2 < 3" 809 | } 810 | }, 811 | "inherits": { 812 | "version": "2.0.4", 813 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 814 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 815 | }, 816 | "ipaddr.js": { 817 | "version": "1.9.1", 818 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 819 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 820 | }, 821 | "media-typer": { 822 | "version": "0.3.0", 823 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 824 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 825 | }, 826 | "merge-descriptors": { 827 | "version": "1.0.1", 828 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 829 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 830 | }, 831 | "methods": { 832 | "version": "1.1.2", 833 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 834 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 835 | }, 836 | "mime": { 837 | "version": "1.6.0", 838 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 839 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 840 | }, 841 | "mime-db": { 842 | "version": "1.52.0", 843 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 844 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 845 | }, 846 | "mime-types": { 847 | "version": "2.1.35", 848 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 849 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 850 | "requires": { 851 | "mime-db": "1.52.0" 852 | } 853 | }, 854 | "ms": { 855 | "version": "2.0.0", 856 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 857 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 858 | }, 859 | "negotiator": { 860 | "version": "0.6.3", 861 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 862 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 863 | }, 864 | "object-inspect": { 865 | "version": "1.12.2", 866 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 867 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" 868 | }, 869 | "on-finished": { 870 | "version": "2.4.1", 871 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 872 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 873 | "requires": { 874 | "ee-first": "1.1.1" 875 | } 876 | }, 877 | "parseurl": { 878 | "version": "1.3.3", 879 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 880 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 881 | }, 882 | "path-to-regexp": { 883 | "version": "0.1.7", 884 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 885 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 886 | }, 887 | "proxy-addr": { 888 | "version": "2.0.7", 889 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 890 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 891 | "requires": { 892 | "forwarded": "0.2.0", 893 | "ipaddr.js": "1.9.1" 894 | } 895 | }, 896 | "qs": { 897 | "version": "6.11.0", 898 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 899 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 900 | "requires": { 901 | "side-channel": "^1.0.4" 902 | } 903 | }, 904 | "range-parser": { 905 | "version": "1.2.1", 906 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 907 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 908 | }, 909 | "raw-body": { 910 | "version": "2.5.1", 911 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 912 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 913 | "requires": { 914 | "bytes": "3.1.2", 915 | "http-errors": "2.0.0", 916 | "iconv-lite": "0.4.24", 917 | "unpipe": "1.0.0" 918 | } 919 | }, 920 | "safe-buffer": { 921 | "version": "5.2.1", 922 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 923 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 924 | }, 925 | "safer-buffer": { 926 | "version": "2.1.2", 927 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 928 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 929 | }, 930 | "send": { 931 | "version": "0.18.0", 932 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 933 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 934 | "requires": { 935 | "debug": "2.6.9", 936 | "depd": "2.0.0", 937 | "destroy": "1.2.0", 938 | "encodeurl": "~1.0.2", 939 | "escape-html": "~1.0.3", 940 | "etag": "~1.8.1", 941 | "fresh": "0.5.2", 942 | "http-errors": "2.0.0", 943 | "mime": "1.6.0", 944 | "ms": "2.1.3", 945 | "on-finished": "2.4.1", 946 | "range-parser": "~1.2.1", 947 | "statuses": "2.0.1" 948 | }, 949 | "dependencies": { 950 | "ms": { 951 | "version": "2.1.3", 952 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 953 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 954 | } 955 | } 956 | }, 957 | "serve-static": { 958 | "version": "1.15.0", 959 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 960 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 961 | "requires": { 962 | "encodeurl": "~1.0.2", 963 | "escape-html": "~1.0.3", 964 | "parseurl": "~1.3.3", 965 | "send": "0.18.0" 966 | } 967 | }, 968 | "setprototypeof": { 969 | "version": "1.2.0", 970 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 971 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 972 | }, 973 | "side-channel": { 974 | "version": "1.0.4", 975 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 976 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 977 | "requires": { 978 | "call-bind": "^1.0.0", 979 | "get-intrinsic": "^1.0.2", 980 | "object-inspect": "^1.9.0" 981 | } 982 | }, 983 | "statuses": { 984 | "version": "2.0.1", 985 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 986 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" 987 | }, 988 | "toidentifier": { 989 | "version": "1.0.1", 990 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 991 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 992 | }, 993 | "type-is": { 994 | "version": "1.6.18", 995 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 996 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 997 | "requires": { 998 | "media-typer": "0.3.0", 999 | "mime-types": "~2.1.24" 1000 | } 1001 | }, 1002 | "unpipe": { 1003 | "version": "1.0.0", 1004 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1005 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 1006 | }, 1007 | "utils-merge": { 1008 | "version": "1.0.1", 1009 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1010 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 1011 | }, 1012 | "vary": { 1013 | "version": "1.1.2", 1014 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1015 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 1016 | } 1017 | } 1018 | } 1019 | -------------------------------------------------------------------------------- /examples/express-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "Vladimir Mikulic", 11 | "license": "MIT", 12 | "dependencies": { 13 | "express": "^4.18.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /examples/express-app/server/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const app = express(); 4 | 5 | app.get('/admin', (req, res) => res.sendStatus(200)); 6 | app.get('/admin/members', (req, res) => res.sendStatus(200)); 7 | app.get('/admin/settings', (req, res) => res.sendStatus(200)); 8 | 9 | app.get('/users', (req, res) => res.sendStatus(200)); 10 | app.post('/users', (req, res) => res.sendStatus(200)); 11 | 12 | app.get('/users/:id', (req, res) => res.sendStatus(200)); 13 | app.patch('/users/:id', (req, res) => res.sendStatus(200)); 14 | 15 | app.get('/products', (req, res) => res.sendStatus(200)); 16 | app.post('/products', (req, res) => res.sendStatus(200)); 17 | 18 | app.get('/products/:id', (req, res) => res.sendStatus(200)); 19 | app.patch('/products/:id', (req, res) => res.sendStatus(200)); 20 | app.delete('/products/:id', (req, res) => res.sendStatus(200)); 21 | 22 | app.get('/blog', (req, res) => res.sendStatus(200)); 23 | app.post('/blog', (req, res) => res.sendStatus(200)); 24 | app.get('/blog/:id', (req, res) => res.sendStatus(200)); 25 | app.patch('/blog/:id', (req, res) => res.sendStatus(200)); 26 | app.delete('/blog/:id', (req, res) => res.sendStatus(200)); 27 | 28 | app.listen(3000); 29 | 30 | module.exports = app; 31 | -------------------------------------------------------------------------------- /examples/express-ts-app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "express-example", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "express": "^4.18.2" 13 | }, 14 | "devDependencies": { 15 | "@types/express": "^4.17.14", 16 | "@types/node": "^18.11.2", 17 | "typescript": "^4.8.4" 18 | } 19 | }, 20 | "node_modules/@types/body-parser": { 21 | "version": "1.19.2", 22 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", 23 | "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", 24 | "dev": true, 25 | "dependencies": { 26 | "@types/connect": "*", 27 | "@types/node": "*" 28 | } 29 | }, 30 | "node_modules/@types/connect": { 31 | "version": "3.4.35", 32 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", 33 | "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", 34 | "dev": true, 35 | "dependencies": { 36 | "@types/node": "*" 37 | } 38 | }, 39 | "node_modules/@types/express": { 40 | "version": "4.17.14", 41 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", 42 | "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", 43 | "dev": true, 44 | "dependencies": { 45 | "@types/body-parser": "*", 46 | "@types/express-serve-static-core": "^4.17.18", 47 | "@types/qs": "*", 48 | "@types/serve-static": "*" 49 | } 50 | }, 51 | "node_modules/@types/express-serve-static-core": { 52 | "version": "4.17.31", 53 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", 54 | "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", 55 | "dev": true, 56 | "dependencies": { 57 | "@types/node": "*", 58 | "@types/qs": "*", 59 | "@types/range-parser": "*" 60 | } 61 | }, 62 | "node_modules/@types/mime": { 63 | "version": "3.0.1", 64 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", 65 | "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", 66 | "dev": true 67 | }, 68 | "node_modules/@types/node": { 69 | "version": "18.11.2", 70 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.2.tgz", 71 | "integrity": "sha512-BWN3M23gLO2jVG8g/XHIRFWiiV4/GckeFIqbU/C4V3xpoBBWSMk4OZomouN0wCkfQFPqgZikyLr7DOYDysIkkw==", 72 | "dev": true 73 | }, 74 | "node_modules/@types/qs": { 75 | "version": "6.9.7", 76 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", 77 | "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", 78 | "dev": true 79 | }, 80 | "node_modules/@types/range-parser": { 81 | "version": "1.2.4", 82 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", 83 | "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", 84 | "dev": true 85 | }, 86 | "node_modules/@types/serve-static": { 87 | "version": "1.15.0", 88 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", 89 | "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", 90 | "dev": true, 91 | "dependencies": { 92 | "@types/mime": "*", 93 | "@types/node": "*" 94 | } 95 | }, 96 | "node_modules/accepts": { 97 | "version": "1.3.8", 98 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 99 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 100 | "dependencies": { 101 | "mime-types": "~2.1.34", 102 | "negotiator": "0.6.3" 103 | }, 104 | "engines": { 105 | "node": ">= 0.6" 106 | } 107 | }, 108 | "node_modules/array-flatten": { 109 | "version": "1.1.1", 110 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 111 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 112 | }, 113 | "node_modules/body-parser": { 114 | "version": "1.20.1", 115 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 116 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 117 | "dependencies": { 118 | "bytes": "3.1.2", 119 | "content-type": "~1.0.4", 120 | "debug": "2.6.9", 121 | "depd": "2.0.0", 122 | "destroy": "1.2.0", 123 | "http-errors": "2.0.0", 124 | "iconv-lite": "0.4.24", 125 | "on-finished": "2.4.1", 126 | "qs": "6.11.0", 127 | "raw-body": "2.5.1", 128 | "type-is": "~1.6.18", 129 | "unpipe": "1.0.0" 130 | }, 131 | "engines": { 132 | "node": ">= 0.8", 133 | "npm": "1.2.8000 || >= 1.4.16" 134 | } 135 | }, 136 | "node_modules/bytes": { 137 | "version": "3.1.2", 138 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 139 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 140 | "engines": { 141 | "node": ">= 0.8" 142 | } 143 | }, 144 | "node_modules/call-bind": { 145 | "version": "1.0.2", 146 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 147 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 148 | "dependencies": { 149 | "function-bind": "^1.1.1", 150 | "get-intrinsic": "^1.0.2" 151 | }, 152 | "funding": { 153 | "url": "https://github.com/sponsors/ljharb" 154 | } 155 | }, 156 | "node_modules/content-disposition": { 157 | "version": "0.5.4", 158 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 159 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 160 | "dependencies": { 161 | "safe-buffer": "5.2.1" 162 | }, 163 | "engines": { 164 | "node": ">= 0.6" 165 | } 166 | }, 167 | "node_modules/content-type": { 168 | "version": "1.0.4", 169 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 170 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 171 | "engines": { 172 | "node": ">= 0.6" 173 | } 174 | }, 175 | "node_modules/cookie": { 176 | "version": "0.5.0", 177 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 178 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 179 | "engines": { 180 | "node": ">= 0.6" 181 | } 182 | }, 183 | "node_modules/cookie-signature": { 184 | "version": "1.0.6", 185 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 186 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 187 | }, 188 | "node_modules/debug": { 189 | "version": "2.6.9", 190 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 191 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 192 | "dependencies": { 193 | "ms": "2.0.0" 194 | } 195 | }, 196 | "node_modules/depd": { 197 | "version": "2.0.0", 198 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 199 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 200 | "engines": { 201 | "node": ">= 0.8" 202 | } 203 | }, 204 | "node_modules/destroy": { 205 | "version": "1.2.0", 206 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 207 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 208 | "engines": { 209 | "node": ">= 0.8", 210 | "npm": "1.2.8000 || >= 1.4.16" 211 | } 212 | }, 213 | "node_modules/ee-first": { 214 | "version": "1.1.1", 215 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 216 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 217 | }, 218 | "node_modules/encodeurl": { 219 | "version": "1.0.2", 220 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 221 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 222 | "engines": { 223 | "node": ">= 0.8" 224 | } 225 | }, 226 | "node_modules/escape-html": { 227 | "version": "1.0.3", 228 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 229 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 230 | }, 231 | "node_modules/etag": { 232 | "version": "1.8.1", 233 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 234 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 235 | "engines": { 236 | "node": ">= 0.6" 237 | } 238 | }, 239 | "node_modules/express": { 240 | "version": "4.18.2", 241 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 242 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 243 | "dependencies": { 244 | "accepts": "~1.3.8", 245 | "array-flatten": "1.1.1", 246 | "body-parser": "1.20.1", 247 | "content-disposition": "0.5.4", 248 | "content-type": "~1.0.4", 249 | "cookie": "0.5.0", 250 | "cookie-signature": "1.0.6", 251 | "debug": "2.6.9", 252 | "depd": "2.0.0", 253 | "encodeurl": "~1.0.2", 254 | "escape-html": "~1.0.3", 255 | "etag": "~1.8.1", 256 | "finalhandler": "1.2.0", 257 | "fresh": "0.5.2", 258 | "http-errors": "2.0.0", 259 | "merge-descriptors": "1.0.1", 260 | "methods": "~1.1.2", 261 | "on-finished": "2.4.1", 262 | "parseurl": "~1.3.3", 263 | "path-to-regexp": "0.1.7", 264 | "proxy-addr": "~2.0.7", 265 | "qs": "6.11.0", 266 | "range-parser": "~1.2.1", 267 | "safe-buffer": "5.2.1", 268 | "send": "0.18.0", 269 | "serve-static": "1.15.0", 270 | "setprototypeof": "1.2.0", 271 | "statuses": "2.0.1", 272 | "type-is": "~1.6.18", 273 | "utils-merge": "1.0.1", 274 | "vary": "~1.1.2" 275 | }, 276 | "engines": { 277 | "node": ">= 0.10.0" 278 | } 279 | }, 280 | "node_modules/finalhandler": { 281 | "version": "1.2.0", 282 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 283 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 284 | "dependencies": { 285 | "debug": "2.6.9", 286 | "encodeurl": "~1.0.2", 287 | "escape-html": "~1.0.3", 288 | "on-finished": "2.4.1", 289 | "parseurl": "~1.3.3", 290 | "statuses": "2.0.1", 291 | "unpipe": "~1.0.0" 292 | }, 293 | "engines": { 294 | "node": ">= 0.8" 295 | } 296 | }, 297 | "node_modules/forwarded": { 298 | "version": "0.2.0", 299 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 300 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 301 | "engines": { 302 | "node": ">= 0.6" 303 | } 304 | }, 305 | "node_modules/fresh": { 306 | "version": "0.5.2", 307 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 308 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 309 | "engines": { 310 | "node": ">= 0.6" 311 | } 312 | }, 313 | "node_modules/function-bind": { 314 | "version": "1.1.1", 315 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 316 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 317 | }, 318 | "node_modules/get-intrinsic": { 319 | "version": "1.1.3", 320 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 321 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 322 | "dependencies": { 323 | "function-bind": "^1.1.1", 324 | "has": "^1.0.3", 325 | "has-symbols": "^1.0.3" 326 | }, 327 | "funding": { 328 | "url": "https://github.com/sponsors/ljharb" 329 | } 330 | }, 331 | "node_modules/has": { 332 | "version": "1.0.3", 333 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 334 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 335 | "dependencies": { 336 | "function-bind": "^1.1.1" 337 | }, 338 | "engines": { 339 | "node": ">= 0.4.0" 340 | } 341 | }, 342 | "node_modules/has-symbols": { 343 | "version": "1.0.3", 344 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 345 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 346 | "engines": { 347 | "node": ">= 0.4" 348 | }, 349 | "funding": { 350 | "url": "https://github.com/sponsors/ljharb" 351 | } 352 | }, 353 | "node_modules/http-errors": { 354 | "version": "2.0.0", 355 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 356 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 357 | "dependencies": { 358 | "depd": "2.0.0", 359 | "inherits": "2.0.4", 360 | "setprototypeof": "1.2.0", 361 | "statuses": "2.0.1", 362 | "toidentifier": "1.0.1" 363 | }, 364 | "engines": { 365 | "node": ">= 0.8" 366 | } 367 | }, 368 | "node_modules/iconv-lite": { 369 | "version": "0.4.24", 370 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 371 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 372 | "dependencies": { 373 | "safer-buffer": ">= 2.1.2 < 3" 374 | }, 375 | "engines": { 376 | "node": ">=0.10.0" 377 | } 378 | }, 379 | "node_modules/inherits": { 380 | "version": "2.0.4", 381 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 382 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 383 | }, 384 | "node_modules/ipaddr.js": { 385 | "version": "1.9.1", 386 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 387 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 388 | "engines": { 389 | "node": ">= 0.10" 390 | } 391 | }, 392 | "node_modules/media-typer": { 393 | "version": "0.3.0", 394 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 395 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 396 | "engines": { 397 | "node": ">= 0.6" 398 | } 399 | }, 400 | "node_modules/merge-descriptors": { 401 | "version": "1.0.1", 402 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 403 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 404 | }, 405 | "node_modules/methods": { 406 | "version": "1.1.2", 407 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 408 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 409 | "engines": { 410 | "node": ">= 0.6" 411 | } 412 | }, 413 | "node_modules/mime": { 414 | "version": "1.6.0", 415 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 416 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 417 | "bin": { 418 | "mime": "cli.js" 419 | }, 420 | "engines": { 421 | "node": ">=4" 422 | } 423 | }, 424 | "node_modules/mime-db": { 425 | "version": "1.52.0", 426 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 427 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 428 | "engines": { 429 | "node": ">= 0.6" 430 | } 431 | }, 432 | "node_modules/mime-types": { 433 | "version": "2.1.35", 434 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 435 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 436 | "dependencies": { 437 | "mime-db": "1.52.0" 438 | }, 439 | "engines": { 440 | "node": ">= 0.6" 441 | } 442 | }, 443 | "node_modules/ms": { 444 | "version": "2.0.0", 445 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 446 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 447 | }, 448 | "node_modules/negotiator": { 449 | "version": "0.6.3", 450 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 451 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 452 | "engines": { 453 | "node": ">= 0.6" 454 | } 455 | }, 456 | "node_modules/object-inspect": { 457 | "version": "1.12.2", 458 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 459 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 460 | "funding": { 461 | "url": "https://github.com/sponsors/ljharb" 462 | } 463 | }, 464 | "node_modules/on-finished": { 465 | "version": "2.4.1", 466 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 467 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 468 | "dependencies": { 469 | "ee-first": "1.1.1" 470 | }, 471 | "engines": { 472 | "node": ">= 0.8" 473 | } 474 | }, 475 | "node_modules/parseurl": { 476 | "version": "1.3.3", 477 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 478 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 479 | "engines": { 480 | "node": ">= 0.8" 481 | } 482 | }, 483 | "node_modules/path-to-regexp": { 484 | "version": "0.1.7", 485 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 486 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 487 | }, 488 | "node_modules/proxy-addr": { 489 | "version": "2.0.7", 490 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 491 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 492 | "dependencies": { 493 | "forwarded": "0.2.0", 494 | "ipaddr.js": "1.9.1" 495 | }, 496 | "engines": { 497 | "node": ">= 0.10" 498 | } 499 | }, 500 | "node_modules/qs": { 501 | "version": "6.11.0", 502 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 503 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 504 | "dependencies": { 505 | "side-channel": "^1.0.4" 506 | }, 507 | "engines": { 508 | "node": ">=0.6" 509 | }, 510 | "funding": { 511 | "url": "https://github.com/sponsors/ljharb" 512 | } 513 | }, 514 | "node_modules/range-parser": { 515 | "version": "1.2.1", 516 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 517 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 518 | "engines": { 519 | "node": ">= 0.6" 520 | } 521 | }, 522 | "node_modules/raw-body": { 523 | "version": "2.5.1", 524 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 525 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 526 | "dependencies": { 527 | "bytes": "3.1.2", 528 | "http-errors": "2.0.0", 529 | "iconv-lite": "0.4.24", 530 | "unpipe": "1.0.0" 531 | }, 532 | "engines": { 533 | "node": ">= 0.8" 534 | } 535 | }, 536 | "node_modules/safe-buffer": { 537 | "version": "5.2.1", 538 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 539 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 540 | "funding": [ 541 | { 542 | "type": "github", 543 | "url": "https://github.com/sponsors/feross" 544 | }, 545 | { 546 | "type": "patreon", 547 | "url": "https://www.patreon.com/feross" 548 | }, 549 | { 550 | "type": "consulting", 551 | "url": "https://feross.org/support" 552 | } 553 | ] 554 | }, 555 | "node_modules/safer-buffer": { 556 | "version": "2.1.2", 557 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 558 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 559 | }, 560 | "node_modules/send": { 561 | "version": "0.18.0", 562 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 563 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 564 | "dependencies": { 565 | "debug": "2.6.9", 566 | "depd": "2.0.0", 567 | "destroy": "1.2.0", 568 | "encodeurl": "~1.0.2", 569 | "escape-html": "~1.0.3", 570 | "etag": "~1.8.1", 571 | "fresh": "0.5.2", 572 | "http-errors": "2.0.0", 573 | "mime": "1.6.0", 574 | "ms": "2.1.3", 575 | "on-finished": "2.4.1", 576 | "range-parser": "~1.2.1", 577 | "statuses": "2.0.1" 578 | }, 579 | "engines": { 580 | "node": ">= 0.8.0" 581 | } 582 | }, 583 | "node_modules/send/node_modules/ms": { 584 | "version": "2.1.3", 585 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 586 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 587 | }, 588 | "node_modules/serve-static": { 589 | "version": "1.15.0", 590 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 591 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 592 | "dependencies": { 593 | "encodeurl": "~1.0.2", 594 | "escape-html": "~1.0.3", 595 | "parseurl": "~1.3.3", 596 | "send": "0.18.0" 597 | }, 598 | "engines": { 599 | "node": ">= 0.8.0" 600 | } 601 | }, 602 | "node_modules/setprototypeof": { 603 | "version": "1.2.0", 604 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 605 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 606 | }, 607 | "node_modules/side-channel": { 608 | "version": "1.0.4", 609 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 610 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 611 | "dependencies": { 612 | "call-bind": "^1.0.0", 613 | "get-intrinsic": "^1.0.2", 614 | "object-inspect": "^1.9.0" 615 | }, 616 | "funding": { 617 | "url": "https://github.com/sponsors/ljharb" 618 | } 619 | }, 620 | "node_modules/statuses": { 621 | "version": "2.0.1", 622 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 623 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 624 | "engines": { 625 | "node": ">= 0.8" 626 | } 627 | }, 628 | "node_modules/toidentifier": { 629 | "version": "1.0.1", 630 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 631 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 632 | "engines": { 633 | "node": ">=0.6" 634 | } 635 | }, 636 | "node_modules/type-is": { 637 | "version": "1.6.18", 638 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 639 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 640 | "dependencies": { 641 | "media-typer": "0.3.0", 642 | "mime-types": "~2.1.24" 643 | }, 644 | "engines": { 645 | "node": ">= 0.6" 646 | } 647 | }, 648 | "node_modules/typescript": { 649 | "version": "4.8.4", 650 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 651 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 652 | "dev": true, 653 | "bin": { 654 | "tsc": "bin/tsc", 655 | "tsserver": "bin/tsserver" 656 | }, 657 | "engines": { 658 | "node": ">=4.2.0" 659 | } 660 | }, 661 | "node_modules/unpipe": { 662 | "version": "1.0.0", 663 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 664 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 665 | "engines": { 666 | "node": ">= 0.8" 667 | } 668 | }, 669 | "node_modules/utils-merge": { 670 | "version": "1.0.1", 671 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 672 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 673 | "engines": { 674 | "node": ">= 0.4.0" 675 | } 676 | }, 677 | "node_modules/vary": { 678 | "version": "1.1.2", 679 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 680 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 681 | "engines": { 682 | "node": ">= 0.8" 683 | } 684 | } 685 | }, 686 | "dependencies": { 687 | "@types/body-parser": { 688 | "version": "1.19.2", 689 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", 690 | "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", 691 | "dev": true, 692 | "requires": { 693 | "@types/connect": "*", 694 | "@types/node": "*" 695 | } 696 | }, 697 | "@types/connect": { 698 | "version": "3.4.35", 699 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", 700 | "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", 701 | "dev": true, 702 | "requires": { 703 | "@types/node": "*" 704 | } 705 | }, 706 | "@types/express": { 707 | "version": "4.17.14", 708 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", 709 | "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", 710 | "dev": true, 711 | "requires": { 712 | "@types/body-parser": "*", 713 | "@types/express-serve-static-core": "^4.17.18", 714 | "@types/qs": "*", 715 | "@types/serve-static": "*" 716 | } 717 | }, 718 | "@types/express-serve-static-core": { 719 | "version": "4.17.31", 720 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", 721 | "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", 722 | "dev": true, 723 | "requires": { 724 | "@types/node": "*", 725 | "@types/qs": "*", 726 | "@types/range-parser": "*" 727 | } 728 | }, 729 | "@types/mime": { 730 | "version": "3.0.1", 731 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", 732 | "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", 733 | "dev": true 734 | }, 735 | "@types/node": { 736 | "version": "18.11.2", 737 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.2.tgz", 738 | "integrity": "sha512-BWN3M23gLO2jVG8g/XHIRFWiiV4/GckeFIqbU/C4V3xpoBBWSMk4OZomouN0wCkfQFPqgZikyLr7DOYDysIkkw==", 739 | "dev": true 740 | }, 741 | "@types/qs": { 742 | "version": "6.9.7", 743 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", 744 | "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", 745 | "dev": true 746 | }, 747 | "@types/range-parser": { 748 | "version": "1.2.4", 749 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", 750 | "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", 751 | "dev": true 752 | }, 753 | "@types/serve-static": { 754 | "version": "1.15.0", 755 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", 756 | "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", 757 | "dev": true, 758 | "requires": { 759 | "@types/mime": "*", 760 | "@types/node": "*" 761 | } 762 | }, 763 | "accepts": { 764 | "version": "1.3.8", 765 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 766 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 767 | "requires": { 768 | "mime-types": "~2.1.34", 769 | "negotiator": "0.6.3" 770 | } 771 | }, 772 | "array-flatten": { 773 | "version": "1.1.1", 774 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 775 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 776 | }, 777 | "body-parser": { 778 | "version": "1.20.1", 779 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 780 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 781 | "requires": { 782 | "bytes": "3.1.2", 783 | "content-type": "~1.0.4", 784 | "debug": "2.6.9", 785 | "depd": "2.0.0", 786 | "destroy": "1.2.0", 787 | "http-errors": "2.0.0", 788 | "iconv-lite": "0.4.24", 789 | "on-finished": "2.4.1", 790 | "qs": "6.11.0", 791 | "raw-body": "2.5.1", 792 | "type-is": "~1.6.18", 793 | "unpipe": "1.0.0" 794 | } 795 | }, 796 | "bytes": { 797 | "version": "3.1.2", 798 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 799 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 800 | }, 801 | "call-bind": { 802 | "version": "1.0.2", 803 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 804 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 805 | "requires": { 806 | "function-bind": "^1.1.1", 807 | "get-intrinsic": "^1.0.2" 808 | } 809 | }, 810 | "content-disposition": { 811 | "version": "0.5.4", 812 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 813 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 814 | "requires": { 815 | "safe-buffer": "5.2.1" 816 | } 817 | }, 818 | "content-type": { 819 | "version": "1.0.4", 820 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 821 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 822 | }, 823 | "cookie": { 824 | "version": "0.5.0", 825 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 826 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" 827 | }, 828 | "cookie-signature": { 829 | "version": "1.0.6", 830 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 831 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 832 | }, 833 | "debug": { 834 | "version": "2.6.9", 835 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 836 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 837 | "requires": { 838 | "ms": "2.0.0" 839 | } 840 | }, 841 | "depd": { 842 | "version": "2.0.0", 843 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 844 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 845 | }, 846 | "destroy": { 847 | "version": "1.2.0", 848 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 849 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" 850 | }, 851 | "ee-first": { 852 | "version": "1.1.1", 853 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 854 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 855 | }, 856 | "encodeurl": { 857 | "version": "1.0.2", 858 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 859 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 860 | }, 861 | "escape-html": { 862 | "version": "1.0.3", 863 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 864 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 865 | }, 866 | "etag": { 867 | "version": "1.8.1", 868 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 869 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 870 | }, 871 | "express": { 872 | "version": "4.18.2", 873 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 874 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 875 | "requires": { 876 | "accepts": "~1.3.8", 877 | "array-flatten": "1.1.1", 878 | "body-parser": "1.20.1", 879 | "content-disposition": "0.5.4", 880 | "content-type": "~1.0.4", 881 | "cookie": "0.5.0", 882 | "cookie-signature": "1.0.6", 883 | "debug": "2.6.9", 884 | "depd": "2.0.0", 885 | "encodeurl": "~1.0.2", 886 | "escape-html": "~1.0.3", 887 | "etag": "~1.8.1", 888 | "finalhandler": "1.2.0", 889 | "fresh": "0.5.2", 890 | "http-errors": "2.0.0", 891 | "merge-descriptors": "1.0.1", 892 | "methods": "~1.1.2", 893 | "on-finished": "2.4.1", 894 | "parseurl": "~1.3.3", 895 | "path-to-regexp": "0.1.7", 896 | "proxy-addr": "~2.0.7", 897 | "qs": "6.11.0", 898 | "range-parser": "~1.2.1", 899 | "safe-buffer": "5.2.1", 900 | "send": "0.18.0", 901 | "serve-static": "1.15.0", 902 | "setprototypeof": "1.2.0", 903 | "statuses": "2.0.1", 904 | "type-is": "~1.6.18", 905 | "utils-merge": "1.0.1", 906 | "vary": "~1.1.2" 907 | } 908 | }, 909 | "finalhandler": { 910 | "version": "1.2.0", 911 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 912 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 913 | "requires": { 914 | "debug": "2.6.9", 915 | "encodeurl": "~1.0.2", 916 | "escape-html": "~1.0.3", 917 | "on-finished": "2.4.1", 918 | "parseurl": "~1.3.3", 919 | "statuses": "2.0.1", 920 | "unpipe": "~1.0.0" 921 | } 922 | }, 923 | "forwarded": { 924 | "version": "0.2.0", 925 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 926 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 927 | }, 928 | "fresh": { 929 | "version": "0.5.2", 930 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 931 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 932 | }, 933 | "function-bind": { 934 | "version": "1.1.1", 935 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 936 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 937 | }, 938 | "get-intrinsic": { 939 | "version": "1.1.3", 940 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 941 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 942 | "requires": { 943 | "function-bind": "^1.1.1", 944 | "has": "^1.0.3", 945 | "has-symbols": "^1.0.3" 946 | } 947 | }, 948 | "has": { 949 | "version": "1.0.3", 950 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 951 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 952 | "requires": { 953 | "function-bind": "^1.1.1" 954 | } 955 | }, 956 | "has-symbols": { 957 | "version": "1.0.3", 958 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 959 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 960 | }, 961 | "http-errors": { 962 | "version": "2.0.0", 963 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 964 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 965 | "requires": { 966 | "depd": "2.0.0", 967 | "inherits": "2.0.4", 968 | "setprototypeof": "1.2.0", 969 | "statuses": "2.0.1", 970 | "toidentifier": "1.0.1" 971 | } 972 | }, 973 | "iconv-lite": { 974 | "version": "0.4.24", 975 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 976 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 977 | "requires": { 978 | "safer-buffer": ">= 2.1.2 < 3" 979 | } 980 | }, 981 | "inherits": { 982 | "version": "2.0.4", 983 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 984 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 985 | }, 986 | "ipaddr.js": { 987 | "version": "1.9.1", 988 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 989 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 990 | }, 991 | "media-typer": { 992 | "version": "0.3.0", 993 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 994 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 995 | }, 996 | "merge-descriptors": { 997 | "version": "1.0.1", 998 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 999 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 1000 | }, 1001 | "methods": { 1002 | "version": "1.1.2", 1003 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1004 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 1005 | }, 1006 | "mime": { 1007 | "version": "1.6.0", 1008 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1009 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 1010 | }, 1011 | "mime-db": { 1012 | "version": "1.52.0", 1013 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1014 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 1015 | }, 1016 | "mime-types": { 1017 | "version": "2.1.35", 1018 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1019 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1020 | "requires": { 1021 | "mime-db": "1.52.0" 1022 | } 1023 | }, 1024 | "ms": { 1025 | "version": "2.0.0", 1026 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1027 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 1028 | }, 1029 | "negotiator": { 1030 | "version": "0.6.3", 1031 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 1032 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 1033 | }, 1034 | "object-inspect": { 1035 | "version": "1.12.2", 1036 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 1037 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" 1038 | }, 1039 | "on-finished": { 1040 | "version": "2.4.1", 1041 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 1042 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 1043 | "requires": { 1044 | "ee-first": "1.1.1" 1045 | } 1046 | }, 1047 | "parseurl": { 1048 | "version": "1.3.3", 1049 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1050 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 1051 | }, 1052 | "path-to-regexp": { 1053 | "version": "0.1.7", 1054 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1055 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 1056 | }, 1057 | "proxy-addr": { 1058 | "version": "2.0.7", 1059 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 1060 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 1061 | "requires": { 1062 | "forwarded": "0.2.0", 1063 | "ipaddr.js": "1.9.1" 1064 | } 1065 | }, 1066 | "qs": { 1067 | "version": "6.11.0", 1068 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 1069 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 1070 | "requires": { 1071 | "side-channel": "^1.0.4" 1072 | } 1073 | }, 1074 | "range-parser": { 1075 | "version": "1.2.1", 1076 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1077 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 1078 | }, 1079 | "raw-body": { 1080 | "version": "2.5.1", 1081 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 1082 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 1083 | "requires": { 1084 | "bytes": "3.1.2", 1085 | "http-errors": "2.0.0", 1086 | "iconv-lite": "0.4.24", 1087 | "unpipe": "1.0.0" 1088 | } 1089 | }, 1090 | "safe-buffer": { 1091 | "version": "5.2.1", 1092 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1093 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 1094 | }, 1095 | "safer-buffer": { 1096 | "version": "2.1.2", 1097 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1098 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1099 | }, 1100 | "send": { 1101 | "version": "0.18.0", 1102 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 1103 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 1104 | "requires": { 1105 | "debug": "2.6.9", 1106 | "depd": "2.0.0", 1107 | "destroy": "1.2.0", 1108 | "encodeurl": "~1.0.2", 1109 | "escape-html": "~1.0.3", 1110 | "etag": "~1.8.1", 1111 | "fresh": "0.5.2", 1112 | "http-errors": "2.0.0", 1113 | "mime": "1.6.0", 1114 | "ms": "2.1.3", 1115 | "on-finished": "2.4.1", 1116 | "range-parser": "~1.2.1", 1117 | "statuses": "2.0.1" 1118 | }, 1119 | "dependencies": { 1120 | "ms": { 1121 | "version": "2.1.3", 1122 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1123 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1124 | } 1125 | } 1126 | }, 1127 | "serve-static": { 1128 | "version": "1.15.0", 1129 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 1130 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 1131 | "requires": { 1132 | "encodeurl": "~1.0.2", 1133 | "escape-html": "~1.0.3", 1134 | "parseurl": "~1.3.3", 1135 | "send": "0.18.0" 1136 | } 1137 | }, 1138 | "setprototypeof": { 1139 | "version": "1.2.0", 1140 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1141 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 1142 | }, 1143 | "side-channel": { 1144 | "version": "1.0.4", 1145 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 1146 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 1147 | "requires": { 1148 | "call-bind": "^1.0.0", 1149 | "get-intrinsic": "^1.0.2", 1150 | "object-inspect": "^1.9.0" 1151 | } 1152 | }, 1153 | "statuses": { 1154 | "version": "2.0.1", 1155 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1156 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" 1157 | }, 1158 | "toidentifier": { 1159 | "version": "1.0.1", 1160 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1161 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 1162 | }, 1163 | "type-is": { 1164 | "version": "1.6.18", 1165 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1166 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1167 | "requires": { 1168 | "media-typer": "0.3.0", 1169 | "mime-types": "~2.1.24" 1170 | } 1171 | }, 1172 | "typescript": { 1173 | "version": "4.8.4", 1174 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", 1175 | "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", 1176 | "dev": true 1177 | }, 1178 | "unpipe": { 1179 | "version": "1.0.0", 1180 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1181 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 1182 | }, 1183 | "utils-merge": { 1184 | "version": "1.0.1", 1185 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1186 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 1187 | }, 1188 | "vary": { 1189 | "version": "1.1.2", 1190 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1191 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 1192 | } 1193 | } 1194 | } 1195 | -------------------------------------------------------------------------------- /examples/express-ts-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "Vladimir Mikulic", 12 | "license": "MIT", 13 | "dependencies": { 14 | "express": "^4.18.2" 15 | }, 16 | "devDependencies": { 17 | "@types/express": "^4.17.14", 18 | "@types/node": "^18.11.2", 19 | "typescript": "^4.8.4" 20 | } 21 | } -------------------------------------------------------------------------------- /examples/express-ts-app/server/app.ts: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const app = express(); 4 | 5 | app.get('/admin', (req, res) => res.sendStatus(200)); 6 | app.get('/admin/members', (req, res) => res.sendStatus(200)); 7 | app.get('/admin/settings', (req, res) => res.sendStatus(200)); 8 | 9 | app.get('/users', (req, res) => res.sendStatus(200)); 10 | app.post('/users', (req, res) => res.sendStatus(200)); 11 | 12 | app.get('/users/:id', (req, res) => res.sendStatus(200)); 13 | app.patch('/users/:id', (req, res) => res.sendStatus(200)); 14 | 15 | app.get('/products', (req, res) => res.sendStatus(200)); 16 | app.post('/products', (req, res) => res.sendStatus(200)); 17 | 18 | app.get('/products/:id', (req, res) => res.sendStatus(200)); 19 | app.patch('/products/:id', (req, res) => res.sendStatus(200)); 20 | app.delete('/products/:id', (req, res) => res.sendStatus(200)); 21 | 22 | app.get('/blog', (req, res) => res.sendStatus(200)); 23 | app.post('/blog', (req, res) => res.sendStatus(200)); 24 | app.get('/blog/:id', (req, res) => res.sendStatus(200)); 25 | app.patch('/blog/:id', (req, res) => res.sendStatus(200)); 26 | app.delete('/blog/:id', (req, res) => res.sendStatus(200)); 27 | 28 | app.listen(3000); 29 | 30 | module.exports = app; 31 | -------------------------------------------------------------------------------- /examples/express-ts-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2016", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": false, 8 | "skipLibCheck": true, 9 | "rootDir": "./", 10 | "outDir": "./dist" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | import { getRoutes } from '../src/routes.js'; 2 | import { printRoutes } from '../src/printer.js'; 3 | 4 | export default { 5 | getRoutes, 6 | printRoutes, 7 | }; 8 | -------------------------------------------------------------------------------- /main.d.ts: -------------------------------------------------------------------------------- 1 | type HTTPMethod = 'HEAD' | 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE'; 2 | 3 | type RoutesMap = { 4 | [route: string]: Array; 5 | }; 6 | 7 | declare namespace RouteList { 8 | function getRoutes( 9 | app: unknown, 10 | framework: 'express' | 'koa' | 'hapi' | 'fastify' 11 | ): RoutesMap; 12 | 13 | function printRoutes( 14 | routesMap: RoutesMap, 15 | options?: { 16 | includePaths?: string[]; 17 | excludePaths?: string[]; 18 | methods?: HTTPMethod[]; 19 | group?: boolean; 20 | } 21 | ): void; 22 | } 23 | 24 | export default RouteList; 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "route-list", 3 | "version": "1.3.5", 4 | "description": "Beautifully shows Express/Koa/Hapi/Fastify routes in CLI.", 5 | "bin": "./src/cli.js", 6 | "main": "./lib/main.js", 7 | "types": "./main.d.ts", 8 | "type": "module", 9 | "engines": { 10 | "node": ">=16" 11 | }, 12 | "engineStrict": true, 13 | "scripts": { 14 | "test": "node --test" 15 | }, 16 | "keywords": [ 17 | "express", 18 | "koa", 19 | "hapi", 20 | "fastify", 21 | "paths", 22 | "routes", 23 | "endpoints", 24 | "list" 25 | ], 26 | "author": "Vladimir Mikulic", 27 | "license": "MIT", 28 | "files": [ 29 | "src", 30 | "lib", 31 | "main.d.ts" 32 | ], 33 | "funding": "https://ko-fi.com/vladimirmikulic", 34 | "homepage": "https://github.com/VladimirMikulic/route-list#readme", 35 | "repository": { 36 | "type": "git", 37 | "url": "https://github.com/VladimirMikulic/route-list.git" 38 | }, 39 | "dependencies": { 40 | "chalk": "^5.3.0", 41 | "commander": "^12.1.0", 42 | "express-list-endpoints": "^7.1.0" 43 | }, 44 | "devDependencies": { 45 | "@hapi/hapi": "^21.3.11", 46 | "@koa/router": "^13.1.0", 47 | "express": "^4.21.1", 48 | "fastify": "^5.0.0", 49 | "koa": "^2.15.3" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /screenshots/showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VladimirMikulic/route-list/4ac2e3c98eea704a6cb4cdda3eff0d94e8d46037/screenshots/showcase.png -------------------------------------------------------------------------------- /screenshots/social-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VladimirMikulic/route-list/4ac2e3c98eea704a6cb4cdda3eff0d94e8d46037/screenshots/social-preview.png -------------------------------------------------------------------------------- /src/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { execSync } from 'child_process'; 4 | import { program } from 'commander'; 5 | import fs from 'fs'; 6 | import path from 'path'; 7 | import { fileURLToPath, pathToFileURL } from 'url'; 8 | import { printRoutes } from './printer.js'; 9 | import { getRoutes } from './routes.js'; 10 | import { getApp, getAppWorkingDirPath, getFrameworkName } from './utils.js'; 11 | 12 | const __dirname = fileURLToPath(new URL('.', import.meta.url)); 13 | const pkgJSONFilePath = path.resolve(__dirname, '../package.json'); 14 | const pkgJSON = JSON.parse(fs.readFileSync(pkgJSONFilePath)); 15 | 16 | const examples = [ 17 | ' $ route-list server/app.js', 18 | ' $ route-list --methods GET,POST server/app.js', 19 | ' $ route-list --include-paths /users,/events server/app.js', 20 | ]; 21 | 22 | program 23 | .name(pkgJSON.name) 24 | .description(pkgJSON.description) 25 | .argument('') 26 | .option('-g, --group', 'Display routes in groups separated with new line') 27 | .option( 28 | '-m, --methods ', 29 | 'Include routes registered for HTTP method(s)', 30 | value => value.split(',').map(method => method.toUpperCase()) 31 | ) 32 | .option( 33 | '-i, --include-paths ', 34 | 'Include routes starting with path(s)', 35 | value => value.split(',') 36 | ) 37 | .option( 38 | '-e, --exclude-paths ', 39 | 'Exclude routes starting with path(s)', 40 | value => value.split(',') 41 | ) 42 | .addHelpText('after', `\nExamples:\n${examples.join('\n')}`) 43 | .showHelpAfterError() 44 | .version(pkgJSON.version) 45 | .parse(); 46 | 47 | try { 48 | const appFilePath = path.resolve(process.cwd(), program.args[0]); 49 | 50 | if (!fs.existsSync(appFilePath)) 51 | throw new Error('No such file, invalid path provided.'); 52 | 53 | const isPathFile = fs.statSync(appFilePath).isFile(); 54 | if (!isPathFile) 55 | throw new Error(`${appFilePath} is directory, but file expected.`); 56 | 57 | const fileExtension = path.extname(appFilePath); 58 | const isFileExtValid = ['.ts', '.js', '.mjs'].includes(fileExtension); 59 | if (!isFileExtValid) 60 | throw new Error('Please specify application .ts/.js/.mjs file.'); 61 | 62 | const appWorkingDirPath = getAppWorkingDirPath(appFilePath); 63 | if (!appWorkingDirPath) 64 | throw new Error('Please initialize local package.json.'); 65 | 66 | const frameworkName = getFrameworkName(appWorkingDirPath); 67 | if (!frameworkName) 68 | throw new Error("Couldn't detect supported back-end framework."); 69 | 70 | const envFilePath = `${appWorkingDirPath}/.env`; 71 | if (fs.existsSync(envFilePath)) { 72 | // Loads environment vars in the current process so application 73 | // that depends on them can be loaded properly below 74 | const dotEnvFilePath = `${appWorkingDirPath}/node_modules/dotenv/lib/main.js`; 75 | const dotenv = await import(pathToFileURL(dotEnvFilePath)); 76 | dotenv.config({ path: envFilePath }); 77 | } 78 | 79 | const isTypeScriptApp = fileExtension === '.ts'; 80 | const tscPath = path.join(appWorkingDirPath, 'node_modules/.bin/tsc'); 81 | if (isTypeScriptApp && !fs.existsSync(tscPath)) 82 | throw new Error(`Please install typescript in ${appWorkingDirPath}`); 83 | 84 | if (isTypeScriptApp) { 85 | // || rm -r ./routelist removes routelist directory in case tsc fails 86 | const tscErrorMsg = `TSC compilation failed. Please resolve issues in your project.`; 87 | execSync( 88 | `${tscPath} --outDir routelist || rm -r ./routelist && echo "${tscErrorMsg}" >&2`, 89 | { cwd: appWorkingDirPath } 90 | ); 91 | } 92 | 93 | const appJsFilePath = isTypeScriptApp 94 | ? path.join( 95 | appWorkingDirPath, 96 | 'routelist', 97 | appFilePath.replace(appWorkingDirPath, '').replace('.ts', '.js') 98 | ) 99 | : appFilePath; 100 | 101 | const { default: defaultExport } = await import(pathToFileURL(appJsFilePath)); 102 | const isDefaultExportFunction = ['AsyncFunction', 'Function'].includes( 103 | defaultExport.constructor.name 104 | ); 105 | 106 | const app = isDefaultExportFunction 107 | ? await defaultExport() 108 | : getApp(defaultExport, frameworkName); 109 | 110 | const routesMap = getRoutes(app, frameworkName); 111 | printRoutes(routesMap, program.opts()); 112 | 113 | if (isTypeScriptApp) 114 | fs.rmSync(path.join(appWorkingDirPath, 'routelist'), { recursive: true }); 115 | process.exit(); 116 | } catch (error) { 117 | console.error(error.message); 118 | process.exitCode = 1; 119 | } 120 | -------------------------------------------------------------------------------- /src/printer.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | const printRoute = (method, route) => { 4 | const colorMap = { 5 | GET: chalk.greenBright, 6 | POST: chalk.yellowBright, 7 | PATCH: chalk.yellowBright, 8 | PUT: chalk.yellowBright, 9 | DELETE: chalk.redBright, 10 | }; 11 | 12 | const coloredMethod = colorMap[method](method); 13 | const methodText = 14 | method === 'GET' ? `${coloredMethod}${chalk.grey('|HEAD')}` : coloredMethod; 15 | 16 | const spacesCount = method === 'GET' ? 6 : 14 - method.length; 17 | const spaces = Array(spacesCount).fill(' ').join(''); 18 | 19 | const dotsCount = process.stdout.columns - 16 - route.length - 4; 20 | const dots = dotsCount > 0 ? Array(dotsCount).fill('.').join('') : 0; 21 | 22 | const routeText = route 23 | .split('/') 24 | .map(segment => { 25 | // { - Hapi, : - Express, Koa, Fastify 26 | const isDynamicSegment = ['{', ':'].includes(segment[0]); 27 | return isDynamicSegment ? chalk.yellowBright(segment) : segment; 28 | }) 29 | .join('/'); 30 | 31 | console.log(` ${methodText}${spaces}${routeText}${chalk.grey(dots)}`); 32 | }; 33 | 34 | export const printRoutes = (routesMap, options) => { 35 | const { includePaths, excludePaths, methods, group } = options || {}; 36 | const routesMapToPrint = Object.keys(routesMap) 37 | .sort() 38 | .filter(route => { 39 | if (includePaths) 40 | return includePaths.some(path => route.startsWith(path)); 41 | if (excludePaths) 42 | return !excludePaths.some(path => route.startsWith(path)); 43 | return true; 44 | }) 45 | .reduce((map, route) => { 46 | // We currently don't display only HEAD routes (without GET) 47 | // That case is probably very rare, might revisit in the future if enough interest from the community 48 | const methodsToPrint = routesMap[route].filter( 49 | method => method !== 'HEAD' && (!methods || methods.includes(method)) 50 | ); 51 | if (methodsToPrint.length === 0) return map; 52 | map[route] = methodsToPrint; 53 | return map; 54 | }, {}); 55 | 56 | const printedRoutesCount = Object.values(routesMapToPrint).flat().length; 57 | 58 | console.log(); 59 | let previousRoute; 60 | for (const [route, methods] of Object.entries(routesMapToPrint)) { 61 | if (group) { 62 | const basePath = `/${route.split('/')[1]}`; 63 | const isGroupBreak = 64 | previousRoute && !previousRoute?.startsWith(basePath); 65 | 66 | if (isGroupBreak) console.log(); 67 | previousRoute = route; 68 | } 69 | 70 | if (methods.includes('GET')) printRoute('GET', route); 71 | if (methods.includes('POST')) printRoute('POST', route); 72 | if (methods.includes('PATCH')) printRoute('PATCH', route); 73 | if (methods.includes('PUT')) printRoute('PUT', route); 74 | if (methods.includes('DELETE')) printRoute('DELETE', route); 75 | } 76 | console.log( 77 | `\n Listed ${chalk.greenBright(printedRoutesCount)} HTTP routes.\n` 78 | ); 79 | }; 80 | -------------------------------------------------------------------------------- /src/routes.js: -------------------------------------------------------------------------------- 1 | import _getExpressRoutes from 'express-list-endpoints'; 2 | 3 | export const getRoutes = (app, frameworkName) => { 4 | if (frameworkName === 'express') return getExpressRoutes(app); 5 | if (frameworkName === 'koa') return getKoaRoutes(app); 6 | if (frameworkName === 'hapi') return getHapiRoutes(app); 7 | if (frameworkName === 'fastify') return getFastifyRoutes(app); 8 | }; 9 | 10 | const getExpressRoutes = app => 11 | _getExpressRoutes(app).reduce( 12 | (routesMap, result) => ({ 13 | ...routesMap, 14 | [result.path]: result.methods 15 | }), 16 | {} 17 | ); 18 | 19 | const getKoaRoutes = app => 20 | app.middleware 21 | .filter(middlewareFn => middlewareFn.router) 22 | .flatMap(middlewareFn => middlewareFn.router.stack) 23 | .reduce((routesMap, route) => { 24 | if (!routesMap[route.path]) routesMap[route.path] = []; 25 | routesMap[route.path].push(...route.methods); 26 | return routesMap; 27 | }, {}); 28 | 29 | const getHapiRoutes = app => 30 | Array.from(app._core.router.routes.keys()).reduce((routesMap, method) => { 31 | const routes = app._core.router.routes.get(method).routes.map(r => r.path); 32 | 33 | for (const route of routes) { 34 | if (!routesMap[route]) routesMap[route] = []; 35 | routesMap[route].push(method.toUpperCase()); 36 | } 37 | 38 | return routesMap; 39 | }, {}); 40 | 41 | const getFastifyRoutes = app => { 42 | const printedRoutes = app 43 | .printRoutes() 44 | .replace(/─|└|│|├/g, ' ') 45 | .trimEnd(); 46 | 47 | const lines = printedRoutes.split('\n'); 48 | 49 | // " activity (GET)" -> "activity" 50 | const getSegment = line => line.replace(/ \(.*\)/g, '').trim(); 51 | 52 | // " activity (GET)" -> ["GET"] <= v4.13 53 | // " activity (POST)" -> ["POST"] <= v4.13 54 | // " activity (GET, POST)" -> ["GET", "POST"] > v4.13 55 | const getMethods = line => line.trim().split(' (')[1].slice(0,-1).split(", "); 56 | 57 | const segments = lines.reduce((allSegments, line, index) => { 58 | const segment = getSegment(line); 59 | const prevSegment = getSegment(lines[index - 1] || ''); 60 | 61 | if (prevSegment === segment) { 62 | const entries = allSegments.filter( 63 | item => item.index < index && item.segment === segment 64 | ); 65 | entries[entries.length - 1].methods.push(...getMethods(line)); 66 | return allSegments; 67 | } 68 | 69 | // spaces preceding segment / not counting single space between segment and (METHOD) 70 | const spaces = line.replace(/ \(.*\)/g, '').match(/ /g).length; 71 | const depth = spaces / 4; 72 | const isRoute = line.includes('('); 73 | const methods = isRoute ? getMethods(line) : null; 74 | 75 | allSegments.push({ segment, index, depth, isRoute, methods }); 76 | return allSegments; 77 | }, []); 78 | 79 | const routesMap = segments 80 | .filter(item => item.isRoute) 81 | .reduce((routesMap, item) => { 82 | const ancestorSegments = segments 83 | .filter(seg => seg.index < item.index && seg.depth < item.depth) 84 | .filter( 85 | (seg, index, prevArr) => 86 | !prevArr.find( 87 | item => item.depth === seg.depth && item.index > seg.index 88 | ) 89 | ); 90 | 91 | const route = [ 92 | ...ancestorSegments.map(r => r.segment), 93 | item.segment 94 | ].join(''); 95 | 96 | routesMap[route] = item.methods; 97 | return routesMap; 98 | }, {}); 99 | 100 | return routesMap; 101 | }; 102 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | 4 | export const getAppWorkingDirPath = appFilePath => { 5 | let lastParsedPath = path.parse(appFilePath); 6 | 7 | // Once the following condition returns false it means we traversed the whole file system 8 | while (lastParsedPath.base && lastParsedPath.root !== lastParsedPath.dir) { 9 | const parentDirItems = fs.readdirSync(lastParsedPath.dir); 10 | 11 | const pkgJSON = parentDirItems.find(item => item === 'package.json'); 12 | if (pkgJSON) return lastParsedPath.dir; 13 | else lastParsedPath = path.parse(lastParsedPath.dir); 14 | } 15 | 16 | return null; 17 | }; 18 | 19 | export const getFrameworkName = appWorkingDirPath => { 20 | const pkgJSONFilePath = `${appWorkingDirPath}/package.json`; 21 | const pkgJSON = JSON.parse(fs.readFileSync(pkgJSONFilePath)); 22 | const { dependencies } = pkgJSON; 23 | 24 | if (dependencies.express) return 'express'; 25 | if (dependencies.koa && dependencies['@koa/router']) return 'koa'; 26 | if (dependencies.koa && dependencies['koa-router']) return 'koa'; 27 | if (dependencies['@hapi/hapi']) return 'hapi'; 28 | if (dependencies.fastify) return 'fastify'; 29 | return null; 30 | }; 31 | 32 | // See README for different export options 33 | export const getApp = (appExport, frameworkName) => { 34 | // hapi app instance also has an internal "app" property 35 | if (frameworkName === 'hapi') 36 | return appExport.app?.app ? appExport.app : appExport; 37 | return appExport.app || appExport; 38 | }; 39 | -------------------------------------------------------------------------------- /test/express.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import express from 'express'; 3 | import test from 'node:test'; 4 | import { getRoutes } from '../src/routes.js'; 5 | 6 | const app = express(); 7 | 8 | app.get('/', (req, res) => res.sendStatus(200)); 9 | app.get('/activity', (req, res) => res.sendStatus(200)); 10 | app.get('/activity/:id', (req, res) => res.sendStatus(200)); 11 | 12 | app.get('/users', (req, res) => res.sendStatus(200)); 13 | app.get('/users/:id', (req, res) => res.sendStatus(200)); 14 | app.put('/users/:id', (req, res) => res.sendStatus(200)); 15 | app.get('/users/following', (req, res) => res.sendStatus(200)); 16 | 17 | test('Express Routes', () => { 18 | const actualRoutesMap = getRoutes(app, "express"); 19 | const expectedRoutesMap = { 20 | '/': ['GET'], 21 | '/activity': ['GET'], 22 | '/activity/:id': ['GET'], 23 | '/users': ['GET'], 24 | '/users/:id': ['GET', 'PUT'], 25 | '/users/following': ['GET'] 26 | }; 27 | 28 | assert.deepStrictEqual(actualRoutesMap, expectedRoutesMap); 29 | }); 30 | -------------------------------------------------------------------------------- /test/fastify.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import fastify from 'fastify'; 3 | import test from 'node:test'; 4 | import { getRoutes } from '../src/routes.js'; 5 | 6 | const app = fastify(); 7 | 8 | app.get('/', (req, res) => res.status(200)); 9 | app.get('/activity', (req, res) => res.status(200)); 10 | app.get('/activity/:id', (req, res) => res.status(200)); 11 | 12 | app.get('/users', (req, res) => res.status(200)); 13 | app.get('/users/:id', (req, res) => res.status(200)); 14 | app.put('/users/:id', (req, res) => res.status(200)); 15 | app.get('/users/following', (req, res) => res.status(200)); 16 | 17 | test('Fastify Routes', () => { 18 | const actualRoutesMap = getRoutes(app, "fastify"); 19 | const expectedRoutesMap = { 20 | '/': ['GET', 'HEAD'], 21 | '/activity': ['GET', 'HEAD'], 22 | '/activity/:id': ['GET', 'HEAD'], 23 | '/users': ['GET', 'HEAD'], 24 | '/users/:id': ['GET', 'HEAD', 'PUT'], 25 | '/users/following': ['GET', 'HEAD'] 26 | }; 27 | 28 | assert.deepStrictEqual(actualRoutesMap, expectedRoutesMap); 29 | }); 30 | -------------------------------------------------------------------------------- /test/hapi.test.js: -------------------------------------------------------------------------------- 1 | import Hapi from '@hapi/hapi'; 2 | import assert from 'assert'; 3 | import test from 'node:test'; 4 | import { getRoutes } from '../src/routes.js'; 5 | 6 | const server = Hapi.server({ 7 | port: 8080, 8 | host: 'localhost' 9 | }); 10 | 11 | server.route({ 12 | method: 'GET', 13 | path: '/', 14 | handler: (request, h) => null 15 | }); 16 | 17 | server.route({ 18 | method: 'GET', 19 | path: '/activity', 20 | handler: (request, h) => null 21 | }); 22 | 23 | server.route({ 24 | method: 'GET', 25 | path: '/activity/:id', 26 | handler: (request, h) => null 27 | }); 28 | 29 | server.route({ 30 | method: 'GET', 31 | path: '/users', 32 | handler: (request, h) => null 33 | }); 34 | 35 | server.route({ 36 | method: ['GET', 'PUT'], 37 | path: '/users/:id', 38 | handler: (request, h) => null 39 | }); 40 | 41 | server.route({ 42 | method: 'GET', 43 | path: '/users/following', 44 | handler: (request, h) => null 45 | }); 46 | 47 | test('Hapi Routes', () => { 48 | const actualRoutesMap = getRoutes(server, "hapi"); 49 | const expectedRoutesMap = { 50 | '/activity': ['GET'], 51 | '/users': ['GET'], 52 | '/': ['GET'], 53 | '/activity/:id': ['GET'], 54 | '/users/:id': ['GET', 'PUT'], 55 | '/users/following': ['GET'] 56 | }; 57 | 58 | assert.deepStrictEqual(actualRoutesMap, expectedRoutesMap); 59 | }); 60 | -------------------------------------------------------------------------------- /test/koa.test.js: -------------------------------------------------------------------------------- 1 | import Router from '@koa/router'; 2 | import assert from 'assert'; 3 | import Koa from 'koa'; 4 | import test from 'node:test'; 5 | import { getRoutes } from '../src/routes.js'; 6 | 7 | const app = new Koa(); 8 | const router = new Router(); 9 | 10 | router.get('/', (req, res) => (ctx.status = 200)); 11 | router.get('/activity', (req, res) => (ctx.status = 200)); 12 | router.get('/activity/:id', (req, res) => (ctx.status = 200)); 13 | 14 | router.get('/users', (req, res) => (ctx.status = 200)); 15 | router.get('/users/:id', (req, res) => (ctx.status = 200)); 16 | router.put('/users/:id', (req, res) => (ctx.status = 200)); 17 | router.get('/users/following', (req, res) => (ctx.status = 200)); 18 | 19 | app.use(router.routes()); 20 | app.use(ctx => console.log('Non-router middleware')); 21 | 22 | test('Koa Routes', () => { 23 | const actualRoutesMap = getRoutes(app, "koa"); 24 | const expectedRoutesMap = { 25 | '/': ['HEAD', 'GET'], 26 | '/activity': ['HEAD', 'GET'], 27 | '/activity/:id': ['HEAD', 'GET'], 28 | '/users': ['HEAD', 'GET'], 29 | '/users/:id': ['HEAD', 'GET', 'PUT'], 30 | '/users/following': ['HEAD', 'GET'] 31 | }; 32 | 33 | assert.deepStrictEqual(actualRoutesMap, expectedRoutesMap); 34 | }); 35 | -------------------------------------------------------------------------------- /test/utils.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'assert'; 2 | import test from 'node:test'; 3 | import path from 'path'; 4 | import { getAppWorkingDirPath, getFrameworkName } from '../src/utils.js'; 5 | 6 | const appFilePath = path.join( 7 | process.cwd(), 8 | 'examples/express-app/server/app.js' 9 | ); 10 | 11 | test('getAppWorkingDirPath', () => { 12 | const actualWorkingDirPath = getAppWorkingDirPath(appFilePath); 13 | const expectedWorkingDirPath = path.join( 14 | process.cwd(), 15 | 'examples/express-app' 16 | ); 17 | 18 | assert.strictEqual(actualWorkingDirPath, expectedWorkingDirPath); 19 | }); 20 | 21 | test('getFrameworkName', () => { 22 | const workingDirPath = getAppWorkingDirPath(appFilePath); 23 | const actualFrameworkName = getFrameworkName(workingDirPath); 24 | const expectedFrameworkName = 'express'; 25 | 26 | assert.strictEqual(actualFrameworkName, expectedFrameworkName); 27 | }); 28 | --------------------------------------------------------------------------------