├── .editorconfig ├── .github └── workflows │ └── tests.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── biome.json ├── docs ├── README.md └── api-reference │ ├── .nojekyll │ ├── README.md │ └── classes │ └── Composer.md ├── logo.svg ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── compose.ts ├── composer.ts ├── helpers.ts ├── index.ts ├── snippets.ts └── types.ts ├── test ├── benchmark.bench.ts ├── composer.test.ts ├── middleware.test.ts └── snippets.test.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | indent_style = space 7 | indent_size = 4 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.{yaml,yml}] 13 | indent_size = 2 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Middleware-IO CI 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | node-version: 11 | # - 14.x 12 | # - 16.x 13 | - 18.x 14 | - 20.x 15 | - 22.x 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | - run: npm ci 23 | - run: npm run build 24 | - run: npm run test 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | 4 | # Dependency directories 5 | node_modules/ 6 | 7 | # Build 8 | lib/ 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | Please refer to the changelog in [GitHub Releases](https://github.com/negezor/middleware-io/releases) 3 | 4 | ## [2.8.0] - 2021.06.10 5 | ### Breaking Change 6 | - Drop support Node.JS 10 7 | 8 | ## [2.7.0] - 2021.06.10 9 | ### Feature 10 | - Using [exports](https://nodejs.org/api/packages.html#packages_package_entry_points) in `package.json` 11 | 12 | ### Updated 13 | - Updated dev dependencies 14 | - Updated generated docs 15 | 16 | ## [2.6.0] - 2021.03.28 17 | ### Updated 18 | - Now uses `UnknownObject` instead of `object` type 19 | - Updated dev dependencies 20 | - Updated generated docs 21 | 22 | ## [2.5.0] - 2020.02.21 23 | ### Added 24 | - Composer now has an inherited generic 25 | 26 | ### Updated 27 | - Compose correspond koa-compose 28 | - Updated dev dependencies 29 | - Updated generated docs 30 | 31 | ## [2.4.0] - 2020.01.20 32 | ### BREAKING CHNAGE 33 | - In snippets `getBeforeMiddleware` and `getEnforceMiddleware` the order of the arguments has changed 34 | - Composer now requires generic with object restriction 35 | 36 | ### Fixed 37 | - Multiple next calls in compose now throw an asynchronous error 38 | - In snippets `getBeforeMiddleware`, `getAfterMiddleware`, `getEnforceMiddleware` and `getConcurrencyMiddleware` an error will be thrown for several calls next 39 | - Comments typos fixed 40 | 41 | ### Updated 42 | - Types `NextMiddlewareReturn` and `MiddlewareReturn` now unknown instead of any 43 | - Updated dev dependencies 44 | - Updated generated docs 45 | 46 | ## [2.3.0] - 2020.01.03 47 | ### Added 48 | - Added `builder` static method for `Composer` 49 | - Added `length` getter for `Composer` 50 | 51 | ### Updated 52 | - Updated generated docs 53 | 54 | ## [2.2.0] - 2020.01.03 55 | ### BREAKING CHNAGE 56 | - Drop support `Node.js 8` 57 | 58 | ### Added 59 | - Added `clone` method for `Composer` 60 | 61 | ### Fixed 62 | - Snippet `stopMiddleware` now return `Promise` 63 | 64 | ### Updated 65 | - Updated dev dependencies 66 | - Updated generated docs 67 | - Updated TypeScript config 68 | 69 | ## [2.1.0] - 2019.10.06 70 | ### Added 71 | - Added `getCaughtMiddleware` snippet 72 | - Added tests for `getCaughtMiddleware` and `getLazyMiddleware` 73 | 74 | ### Fixed 75 | - Fixed missing cache in `getLazyMiddleware` 76 | - Fixed example in README.md 77 | 78 | ### Updated 79 | - Updated dev dependencies 80 | - Updated generated docs 81 | 82 | ## [2.0.0] - 2019.06.19 83 | ### Added 84 | - Added `Composer`, a simple middleware compose builder 85 | - Added `getLazyMiddleware`, `getTapMiddleware`, `getForkMiddleware`, `getEnforceMiddleware`, `getConcurrencyMiddleware` snippets 86 | - Added mini-optimization for `compose` 87 | - Added tests for snippets 88 | - Added tests for `Composer` 89 | 90 | ### Updated 91 | - Rewrited code with full types 92 | - Now using eslint instead of tslint 93 | - Rewritten benchmark with matcha on benchmark.js 94 | 95 | ### Major 96 | - Export compose by default 97 | - Deleted `MiddlewareStatus`, use compose 98 | 99 | ## [1.0.0] - 2019.01.13 100 | ### Added 101 | - Added compose functions 102 | - Added snippets middleware 103 | 104 | ### Updated 105 | - Switch to TypeScript 106 | 107 | ### Major 108 | - Delete multiple input contexts 109 | - Usage only array for added middleware 110 | 111 | ## [0.0.8] - 2018.09.11 112 | ### Added 113 | - Added length 114 | - Added custom tag in toString() 115 | 116 | ### Updated 117 | - Updated dependencies 118 | - Improved build 119 | 120 | ## [0.0.7] - 2018.07.25 121 | ### Updated 122 | - Updated dependencies 123 | - Migrating to jest 124 | - Optimization of the status 125 | 126 | ## [0.0.6] - 2018.04.11 127 | ### Added 128 | - Support `--experimental-modules` 129 | - Using [rollupjs](https://github.com/rollup/rollup) for build 130 | 131 | ### Updated 132 | - Refactoring 133 | 134 | ## [0.0.5] - 2018.03.01 135 | ### Updated 136 | - Switch CLRF to LF 137 | 138 | ## [0.0.4] - 2018.02.24 139 | ### Updated 140 | - All dependencies 141 | - Now mjs files are used 142 | - Fixed README.md install 143 | 144 | ## [0.0.1] - 2017.10.29 145 | ### Added 146 | - Initial commit 147 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2024 Negezor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | Build Status 4 | NPM version 5 | NPM downloads 6 |

7 | 8 | > **Middleware-IO** - Modern middleware on Promise 9 | 10 | | 📖 [Documentation](docs/) | 11 | |---------------------------| 12 | 13 | ## Features 14 | 15 | 1. **Self-Sufficient.** The library has zero dependencies. 16 | 2. **Reliable.** The library is written in **TypeScript** and covered by tests. 17 | 3. **Modern.** The library comes with native ESM support 18 | 3. **Powerful.** Supports following additional features: 19 | - The library has enough built-in snippets; 20 | - The middleware chain builder; 21 | 22 | ## Installation 23 | > **[Node.js](https://nodejs.org/) 12.0.0 or newer is required** 24 | 25 | - **Using `npm`** (recommended) 26 | ```shell 27 | npm i middleware-io 28 | ``` 29 | - **Using `Yarn`** 30 | ```shell 31 | yarn add middleware-io 32 | ``` 33 | - **Using `pnpm`** 34 | ```shell 35 | pnpm add middleware-io 36 | ``` 37 | 38 | ## Example usage 39 | 40 | ```js 41 | import { compose } from 'middleware-io'; 42 | 43 | const composedMiddleware = compose([ 44 | async (context, next) => { 45 | // Step 1 46 | 47 | await next(); 48 | 49 | // Step 4 50 | 51 | // Print the current date from the next middleware 52 | console.log(context.now); 53 | }, 54 | async (context, next) => { 55 | // Step 2 56 | 57 | context.now = Date.now(); 58 | 59 | await next(); 60 | 61 | // Step 3 62 | } 63 | ]); 64 | 65 | composedMiddleware({}, () => { /* Last handler (next) */ }) 66 | .then(() => { 67 | console.log('Middleware finished work'); 68 | }) 69 | .catch(console.error); 70 | ``` 71 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", 3 | "formatter": { 4 | "indentStyle": "space", 5 | "indentWidth": 4, 6 | "lineWidth": 120, 7 | "lineEnding": "lf" 8 | }, 9 | "javascript": { 10 | "formatter": { 11 | "quoteStyle": "single", 12 | "semicolons": "always", 13 | "arrowParentheses": "asNeeded" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Middleware IO Docs 2 | 3 | | 📖 [API Reference](api-reference/) | 4 | |------------------------------------ | 5 | -------------------------------------------------------------------------------- /docs/api-reference/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /docs/api-reference/README.md: -------------------------------------------------------------------------------- 1 | middleware-io 2 | 3 | # middleware-io 4 | 5 | ## Table of contents 6 | 7 | ### References 8 | 9 | - [default](README.md#default) 10 | 11 | ### Classes 12 | 13 | - [Composer](classes/Composer.md) 14 | 15 | ### Type Aliases 16 | 17 | - [BranchMiddlewareCondition](README.md#branchmiddlewarecondition) 18 | - [BranchMiddlewareConditionFunction](README.md#branchmiddlewareconditionfunction) 19 | - [CaughtMiddlewareHandler](README.md#caughtmiddlewarehandler) 20 | - [LazyMiddlewareFactory](README.md#lazymiddlewarefactory) 21 | - [Middleware](README.md#middleware) 22 | - [MiddlewareReturn](README.md#middlewarereturn) 23 | - [NextMiddleware](README.md#nextmiddleware) 24 | - [NextMiddlewareReturn](README.md#nextmiddlewarereturn) 25 | - [UnknownObject](README.md#unknownobject) 26 | 27 | ### Functions 28 | 29 | - [compose](README.md#compose) 30 | - [getAfterMiddleware](README.md#getaftermiddleware) 31 | - [getBeforeMiddleware](README.md#getbeforemiddleware) 32 | - [getBranchMiddleware](README.md#getbranchmiddleware) 33 | - [getCaughtMiddleware](README.md#getcaughtmiddleware) 34 | - [getConcurrencyMiddleware](README.md#getconcurrencymiddleware) 35 | - [getEnforceMiddleware](README.md#getenforcemiddleware) 36 | - [getFilterMiddleware](README.md#getfiltermiddleware) 37 | - [getForkMiddleware](README.md#getforkmiddleware) 38 | - [getLazyMiddleware](README.md#getlazymiddleware) 39 | - [getOptionalMiddleware](README.md#getoptionalmiddleware) 40 | - [getTapMiddleware](README.md#gettapmiddleware) 41 | - [noopNext](README.md#noopnext) 42 | - [skipMiddleware](README.md#skipmiddleware) 43 | - [stopMiddleware](README.md#stopmiddleware) 44 | 45 | ## References 46 | 47 | ### default 48 | 49 | Renames and re-exports [compose](README.md#compose) 50 | 51 | ## Type Aliases 52 | 53 | ### BranchMiddlewareCondition 54 | 55 | Ƭ **BranchMiddlewareCondition**\<`T`\>: [`BranchMiddlewareConditionFunction`](README.md#branchmiddlewareconditionfunction)\<`T`\> \| `boolean` 56 | 57 | Possible types for branch condition 58 | 59 | #### Type parameters 60 | 61 | | Name | 62 | | :------ | 63 | | `T` | 64 | 65 | #### Defined in 66 | 67 | [types.ts:34](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L34) 68 | 69 | ___ 70 | 71 | ### BranchMiddlewareConditionFunction 72 | 73 | Ƭ **BranchMiddlewareConditionFunction**\<`T`\>: (`context`: `T`) => `Promise`\<`boolean`\> \| `boolean` 74 | 75 | Asynchronous function for branch condition 76 | 77 | #### Type parameters 78 | 79 | | Name | 80 | | :------ | 81 | | `T` | 82 | 83 | #### Type declaration 84 | 85 | ▸ (`context`): `Promise`\<`boolean`\> \| `boolean` 86 | 87 | ##### Parameters 88 | 89 | | Name | Type | 90 | | :------ | :------ | 91 | | `context` | `T` | 92 | 93 | ##### Returns 94 | 95 | `Promise`\<`boolean`\> \| `boolean` 96 | 97 | #### Defined in 98 | 99 | [types.ts:29](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L29) 100 | 101 | ___ 102 | 103 | ### CaughtMiddlewareHandler 104 | 105 | Ƭ **CaughtMiddlewareHandler**\<`T`\>: (`context`: `T`, `error`: `Error`) => [`MiddlewareReturn`](README.md#middlewarereturn) 106 | 107 | Handler for catching errors in middleware chains 108 | 109 | #### Type parameters 110 | 111 | | Name | 112 | | :------ | 113 | | `T` | 114 | 115 | #### Type declaration 116 | 117 | ▸ (`context`, `error`): [`MiddlewareReturn`](README.md#middlewarereturn) 118 | 119 | ##### Parameters 120 | 121 | | Name | Type | 122 | | :------ | :------ | 123 | | `context` | `T` | 124 | | `error` | `Error` | 125 | 126 | ##### Returns 127 | 128 | [`MiddlewareReturn`](README.md#middlewarereturn) 129 | 130 | #### Defined in 131 | 132 | [types.ts:44](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L44) 133 | 134 | ___ 135 | 136 | ### LazyMiddlewareFactory 137 | 138 | Ƭ **LazyMiddlewareFactory**\<`T`\>: (`context`: `T`) => `Promise`\<[`Middleware`](README.md#middleware)\<`T`\>\> \| [`Middleware`](README.md#middleware)\<`T`\> 139 | 140 | Asynchronous factory to create middleware 141 | 142 | #### Type parameters 143 | 144 | | Name | 145 | | :------ | 146 | | `T` | 147 | 148 | #### Type declaration 149 | 150 | ▸ (`context`): `Promise`\<[`Middleware`](README.md#middleware)\<`T`\>\> \| [`Middleware`](README.md#middleware)\<`T`\> 151 | 152 | ##### Parameters 153 | 154 | | Name | Type | 155 | | :------ | :------ | 156 | | `context` | `T` | 157 | 158 | ##### Returns 159 | 160 | `Promise`\<[`Middleware`](README.md#middleware)\<`T`\>\> \| [`Middleware`](README.md#middleware)\<`T`\> 161 | 162 | #### Defined in 163 | 164 | [types.ts:39](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L39) 165 | 166 | ___ 167 | 168 | ### Middleware 169 | 170 | Ƭ **Middleware**\<`T`\>: (`context`: `T`, `next`: [`NextMiddleware`](README.md#nextmiddleware)) => [`MiddlewareReturn`](README.md#middlewarereturn) 171 | 172 | Basic middleware 173 | 174 | #### Type parameters 175 | 176 | | Name | 177 | | :------ | 178 | | `T` | 179 | 180 | #### Type declaration 181 | 182 | ▸ (`context`, `next`): [`MiddlewareReturn`](README.md#middlewarereturn) 183 | 184 | ##### Parameters 185 | 186 | | Name | Type | 187 | | :------ | :------ | 188 | | `context` | `T` | 189 | | `next` | [`NextMiddleware`](README.md#nextmiddleware) | 190 | 191 | ##### Returns 192 | 193 | [`MiddlewareReturn`](README.md#middlewarereturn) 194 | 195 | #### Defined in 196 | 197 | [types.ts:24](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L24) 198 | 199 | ___ 200 | 201 | ### MiddlewareReturn 202 | 203 | Ƭ **MiddlewareReturn**: `unknown` 204 | 205 | Returns the type of response middleware 206 | 207 | #### Defined in 208 | 209 | [types.ts:14](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L14) 210 | 211 | ___ 212 | 213 | ### NextMiddleware 214 | 215 | Ƭ **NextMiddleware**: () => `Promise`\<[`NextMiddlewareReturn`](README.md#nextmiddlewarereturn)\> 216 | 217 | Call the next middleware from the chain 218 | 219 | #### Type declaration 220 | 221 | ▸ (): `Promise`\<[`NextMiddlewareReturn`](README.md#nextmiddlewarereturn)\> 222 | 223 | ##### Returns 224 | 225 | `Promise`\<[`NextMiddlewareReturn`](README.md#nextmiddlewarereturn)\> 226 | 227 | #### Defined in 228 | 229 | [types.ts:9](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L9) 230 | 231 | ___ 232 | 233 | ### NextMiddlewareReturn 234 | 235 | Ƭ **NextMiddlewareReturn**: `unknown` 236 | 237 | Returns the type of response middleware 238 | 239 | #### Defined in 240 | 241 | [types.ts:4](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L4) 242 | 243 | ___ 244 | 245 | ### UnknownObject 246 | 247 | Ƭ **UnknownObject**: `Record`\<`string`, `unknown`\> 248 | 249 | Instead of object 250 | 251 | #### Defined in 252 | 253 | [types.ts:19](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/types.ts#L19) 254 | 255 | ## Functions 256 | 257 | ### compose 258 | 259 | ▸ **compose**\<`T`\>(`middlewares`): [`Middleware`](README.md#middleware)\<`T`\> 260 | 261 | Compose an array of middleware handlers into a single handler 262 | 263 | #### Type parameters 264 | 265 | | Name | 266 | | :------ | 267 | | `T` | 268 | 269 | #### Parameters 270 | 271 | | Name | Type | Description | 272 | | :------ | :------ | :------ | 273 | | `middlewares` | [`Middleware`](README.md#middleware)\<`T`\>[] | The array of middleware | 274 | 275 | #### Returns 276 | 277 | [`Middleware`](README.md#middleware)\<`T`\> 278 | 279 | Composed middleware 280 | 281 | #### Defined in 282 | 283 | [compose.ts:12](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/compose.ts#L12) 284 | 285 | ___ 286 | 287 | ### getAfterMiddleware 288 | 289 | ▸ **getAfterMiddleware**\<`T`\>(`middleware`, `afterMiddleware`): [`Middleware`](README.md#middleware)\<`T`\> 290 | 291 | Runs the second middleware after the main 292 | 293 | Example: 294 | 295 | ```ts 296 | getAfterMiddleware( 297 | sendSecureData, 298 | clearSecurityData 299 | ); 300 | ``` 301 | 302 | #### Type parameters 303 | 304 | | Name | 305 | | :------ | 306 | | `T` | 307 | 308 | #### Parameters 309 | 310 | | Name | Type | 311 | | :------ | :------ | 312 | | `middleware` | [`Middleware`](README.md#middleware)\<`T`\> | 313 | | `afterMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 314 | 315 | #### Returns 316 | 317 | [`Middleware`](README.md#middleware)\<`T`\> 318 | 319 | #### Defined in 320 | 321 | [snippets.ts:192](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L192) 322 | 323 | ___ 324 | 325 | ### getBeforeMiddleware 326 | 327 | ▸ **getBeforeMiddleware**\<`T`\>(`beforeMiddleware`, `middleware`): [`Middleware`](README.md#middleware)\<`T`\> 328 | 329 | Runs the second middleware before the main 330 | 331 | Example: 332 | 333 | ```ts 334 | getBeforeMiddleware( 335 | myMockMiddleware, 336 | ouputUserData 337 | ); 338 | ``` 339 | 340 | #### Type parameters 341 | 342 | | Name | 343 | | :------ | 344 | | `T` | 345 | 346 | #### Parameters 347 | 348 | | Name | Type | 349 | | :------ | :------ | 350 | | `beforeMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 351 | | `middleware` | [`Middleware`](README.md#middleware)\<`T`\> | 352 | 353 | #### Returns 354 | 355 | [`Middleware`](README.md#middleware)\<`T`\> 356 | 357 | #### Defined in 358 | 359 | [snippets.ts:170](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L170) 360 | 361 | ___ 362 | 363 | ### getBranchMiddleware 364 | 365 | ▸ **getBranchMiddleware**\<`T`\>(`condition`, `trueMiddleware`, `falseMiddleware`): [`Middleware`](README.md#middleware)\<`T`\> 366 | 367 | By condition splits the middleware 368 | 369 | Example: 370 | 371 | ```ts 372 | getBranchMiddleware( 373 | async context => context.is('Content-Type', 'json'), 374 | myBodyParser.json(), 375 | myBodyParser.urlencoded() 376 | ); 377 | ``` 378 | 379 | Static condition 380 | 381 | ```ts 382 | getBranchMiddleware( 383 | process.env.NODE_ENV === 'production', 384 | logger.loggedContextToFile(), 385 | logger.loggedContextToConsole() 386 | ); 387 | ``` 388 | 389 | #### Type parameters 390 | 391 | | Name | 392 | | :------ | 393 | | `T` | 394 | 395 | #### Parameters 396 | 397 | | Name | Type | 398 | | :------ | :------ | 399 | | `condition` | [`BranchMiddlewareCondition`](README.md#branchmiddlewarecondition)\<`T`\> | 400 | | `trueMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 401 | | `falseMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 402 | 403 | #### Returns 404 | 405 | [`Middleware`](README.md#middleware)\<`T`\> 406 | 407 | #### Defined in 408 | 409 | [snippets.ts:109](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L109) 410 | 411 | ___ 412 | 413 | ### getCaughtMiddleware 414 | 415 | ▸ **getCaughtMiddleware**\<`T`\>(`errorHandler`): [`Middleware`](README.md#middleware)\<`T`\> 416 | 417 | Catches errors in the middleware chain 418 | 419 | Example: 420 | ```js 421 | getCaughtMiddleware((context, error) => { 422 | if (error instanceof NetworkError) { 423 | return context.send('Sorry, network issues 😔'); 424 | } 425 | 426 | throw error; 427 | }) 428 | ``` 429 | 430 | Without a snippet, it would look like this: 431 | 432 | ```js 433 | async (context, next) => { 434 | try { 435 | await next(); 436 | } catch (error) { 437 | if (error instanceof NetworkError) { 438 | return context.send('Sorry, network issues 😔'); 439 | } 440 | 441 | throw error; 442 | } 443 | }; 444 | ``` 445 | 446 | #### Type parameters 447 | 448 | | Name | 449 | | :------ | 450 | | `T` | 451 | 452 | #### Parameters 453 | 454 | | Name | Type | 455 | | :------ | :------ | 456 | | `errorHandler` | [`CaughtMiddlewareHandler`](README.md#caughtmiddlewarehandler)\<`T`\> | 457 | 458 | #### Returns 459 | 460 | [`Middleware`](README.md#middleware)\<`T`\> 461 | 462 | #### Defined in 463 | 464 | [snippets.ts:262](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L262) 465 | 466 | ___ 467 | 468 | ### getConcurrencyMiddleware 469 | 470 | ▸ **getConcurrencyMiddleware**\<`T`\>(`middlewares`): [`Middleware`](README.md#middleware)\<`T`\> 471 | 472 | Concurrently launches middleware, 473 | the chain will continue if `next()` is called in all middlewares 474 | 475 | **Warning: Error interrupts all others** 476 | 477 | Example: 478 | 479 | ```ts 480 | getConcurrencyMiddleware( 481 | initializeUser, 482 | initializeSession, 483 | initializeDatabase 484 | ); 485 | ``` 486 | 487 | #### Type parameters 488 | 489 | | Name | 490 | | :------ | 491 | | `T` | 492 | 493 | #### Parameters 494 | 495 | | Name | Type | 496 | | :------ | :------ | 497 | | `middlewares` | [`Middleware`](README.md#middleware)\<`T`\>[] | 498 | 499 | #### Returns 500 | 501 | [`Middleware`](README.md#middleware)\<`T`\> 502 | 503 | #### Defined in 504 | 505 | [snippets.ts:288](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L288) 506 | 507 | ___ 508 | 509 | ### getEnforceMiddleware 510 | 511 | ▸ **getEnforceMiddleware**\<`T`\>(`beforeMiddleware`, `middleware`, `afterMiddleware`): [`Middleware`](README.md#middleware)\<`T`\> 512 | 513 | Runs middleware before and after the main 514 | 515 | Example: 516 | 517 | ```ts 518 | getEnforceMiddleware( 519 | prepareData, 520 | sendData, 521 | clearData 522 | ); 523 | 524 | #### Type parameters 525 | 526 | | Name | 527 | | :------ | 528 | | `T` | 529 | 530 | #### Parameters 531 | 532 | | Name | Type | 533 | | :------ | :------ | 534 | | `beforeMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 535 | | `middleware` | [`Middleware`](README.md#middleware)\<`T`\> | 536 | | `afterMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 537 | 538 | #### Returns 539 | 540 | [`Middleware`](README.md#middleware)\<`T`\> 541 | 542 | #### Defined in 543 | 544 | [snippets.ts:214](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L214) 545 | 546 | ___ 547 | 548 | ### getFilterMiddleware 549 | 550 | ▸ **getFilterMiddleware**\<`T`\>(`condition`, `filterMiddleware`): [`Middleware`](README.md#middleware)\<`T`\> 551 | 552 | Conditionally runs middleware or stops the chain 553 | 554 | Example: 555 | 556 | ```ts 557 | getFilterMiddleware( 558 | context => context.authorized, 559 | middlewareForAuthorized 560 | ); 561 | ``` 562 | 563 | #### Type parameters 564 | 565 | | Name | 566 | | :------ | 567 | | `T` | 568 | 569 | #### Parameters 570 | 571 | | Name | Type | 572 | | :------ | :------ | 573 | | `condition` | [`BranchMiddlewareCondition`](README.md#branchmiddlewarecondition)\<`T`\> | 574 | | `filterMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 575 | 576 | #### Returns 577 | 578 | [`Middleware`](README.md#middleware)\<`T`\> 579 | 580 | #### Defined in 581 | 582 | [snippets.ts:152](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L152) 583 | 584 | ___ 585 | 586 | ### getForkMiddleware 587 | 588 | ▸ **getForkMiddleware**\<`T`\>(`middleware`): [`Middleware`](README.md#middleware)\<`T`\> 589 | 590 | Runs the middleware at the next event loop and force call `next()` 591 | 592 | Example: 593 | 594 | ```ts 595 | getForkMiddleware((context) => { 596 | statisticsMiddlewares(context).catch(console.error); 597 | }); 598 | ``` 599 | 600 | #### Type parameters 601 | 602 | | Name | 603 | | :------ | 604 | | `T` | 605 | 606 | #### Parameters 607 | 608 | | Name | Type | 609 | | :------ | :------ | 610 | | `middleware` | [`Middleware`](README.md#middleware)\<`T`\> | 611 | 612 | #### Returns 613 | 614 | [`Middleware`](README.md#middleware)\<`T`\> 615 | 616 | #### Defined in 617 | 618 | [snippets.ts:79](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L79) 619 | 620 | ___ 621 | 622 | ### getLazyMiddleware 623 | 624 | ▸ **getLazyMiddleware**\<`T`\>(`factory`): [`Middleware`](README.md#middleware)\<`T`\> 625 | 626 | Lazily asynchronously gets middleware 627 | 628 | Example: 629 | 630 | ```ts 631 | getLazyMiddleware(async (context) => { 632 | const route = await getSomeRoute(context.path) // Promise; 633 | 634 | return route; 635 | }); 636 | ``` 637 | 638 | #### Type parameters 639 | 640 | | Name | 641 | | :------ | 642 | | `T` | 643 | 644 | #### Parameters 645 | 646 | | Name | Type | 647 | | :------ | :------ | 648 | | `factory` | [`LazyMiddlewareFactory`](README.md#lazymiddlewarefactory)\<`T`\> | 649 | 650 | #### Returns 651 | 652 | [`Middleware`](README.md#middleware)\<`T`\> 653 | 654 | #### Defined in 655 | 656 | [snippets.ts:36](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L36) 657 | 658 | ___ 659 | 660 | ### getOptionalMiddleware 661 | 662 | ▸ **getOptionalMiddleware**\<`T`\>(`condition`, `optionalMiddleware`): [`Middleware`](README.md#middleware)\<`T`\> 663 | 664 | Conditionally runs optional middleware or skips middleware 665 | 666 | Example: 667 | 668 | ```ts 669 | getOptionalMiddleware( 670 | context => context.user.isAdmin, 671 | addFieldsForAdmin 672 | ); 673 | ``` 674 | 675 | #### Type parameters 676 | 677 | | Name | 678 | | :------ | 679 | | `T` | 680 | 681 | #### Parameters 682 | 683 | | Name | Type | 684 | | :------ | :------ | 685 | | `condition` | [`BranchMiddlewareCondition`](README.md#branchmiddlewarecondition)\<`T`\> | 686 | | `optionalMiddleware` | [`Middleware`](README.md#middleware)\<`T`\> | 687 | 688 | #### Returns 689 | 690 | [`Middleware`](README.md#middleware)\<`T`\> 691 | 692 | #### Defined in 693 | 694 | [snippets.ts:135](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L135) 695 | 696 | ___ 697 | 698 | ### getTapMiddleware 699 | 700 | ▸ **getTapMiddleware**\<`T`\>(`middleware`): [`Middleware`](README.md#middleware)\<`T`\> 701 | 702 | Runs the middleware and force call `next()` 703 | 704 | Example: 705 | 706 | ```ts 707 | getTapMiddleware((context) => { 708 | console.log('Context', context); 709 | }); 710 | ``` 711 | 712 | #### Type parameters 713 | 714 | | Name | 715 | | :------ | 716 | | `T` | 717 | 718 | #### Parameters 719 | 720 | | Name | Type | 721 | | :------ | :------ | 722 | | `middleware` | [`Middleware`](README.md#middleware)\<`T`\> | 723 | 724 | #### Returns 725 | 726 | [`Middleware`](README.md#middleware)\<`T`\> 727 | 728 | #### Defined in 729 | 730 | [snippets.ts:60](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L60) 731 | 732 | ___ 733 | 734 | ### noopNext 735 | 736 | ▸ **noopNext**(): `Promise`\<`unknown`\> 737 | 738 | Noop for call `next()` in middleware 739 | 740 | #### Returns 741 | 742 | `Promise`\<`unknown`\> 743 | 744 | #### Defined in 745 | 746 | [helpers.ts:30](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/helpers.ts#L30) 747 | 748 | ___ 749 | 750 | ### skipMiddleware 751 | 752 | ▸ **skipMiddleware**\<`T`\>(`context`, `next`): `Promise`\<`unknown`\> 753 | 754 | Call `next()` in middleware 755 | 756 | #### Type parameters 757 | 758 | | Name | 759 | | :------ | 760 | | `T` | 761 | 762 | #### Parameters 763 | 764 | | Name | Type | 765 | | :------ | :------ | 766 | | `context` | `T` | 767 | | `next` | [`NextMiddleware`](README.md#nextmiddleware) | 768 | 769 | #### Returns 770 | 771 | `Promise`\<`unknown`\> 772 | 773 | #### Defined in 774 | 775 | [snippets.ts:16](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L16) 776 | 777 | ___ 778 | 779 | ### stopMiddleware 780 | 781 | ▸ **stopMiddleware**\<`T`\>(`context`, `next`): `Promise`\<`void`\> 782 | 783 | Does not call `next()` in middleware 784 | 785 | #### Type parameters 786 | 787 | | Name | 788 | | :------ | 789 | | `T` | 790 | 791 | #### Parameters 792 | 793 | | Name | Type | 794 | | :------ | :------ | 795 | | `context` | `T` | 796 | | `next` | [`NextMiddleware`](README.md#nextmiddleware) | 797 | 798 | #### Returns 799 | 800 | `Promise`\<`void`\> 801 | 802 | #### Defined in 803 | 804 | [snippets.ts:21](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/snippets.ts#L21) 805 | -------------------------------------------------------------------------------- /docs/api-reference/classes/Composer.md: -------------------------------------------------------------------------------- 1 | [middleware-io](../README.md) / Composer 2 | 3 | # Class: Composer\ 4 | 5 | A simple middleware compose builder 6 | 7 | ## Type parameters 8 | 9 | | Name | Type | 10 | | :------ | :------ | 11 | | `T` | extends [`UnknownObject`](../README.md#unknownobject) | 12 | | `R` | `T` | 13 | 14 | ## Table of contents 15 | 16 | ### Constructors 17 | 18 | - [constructor](Composer.md#constructor) 19 | 20 | ### Properties 21 | 22 | - [middlewares](Composer.md#middlewares) 23 | 24 | ### Accessors 25 | 26 | - [length](Composer.md#length) 27 | 28 | ### Methods 29 | 30 | - [after](Composer.md#after) 31 | - [before](Composer.md#before) 32 | - [branch](Composer.md#branch) 33 | - [caught](Composer.md#caught) 34 | - [clone](Composer.md#clone) 35 | - [compose](Composer.md#compose) 36 | - [concurrency](Composer.md#concurrency) 37 | - [enforce](Composer.md#enforce) 38 | - [filter](Composer.md#filter) 39 | - [fork](Composer.md#fork) 40 | - [lazy](Composer.md#lazy) 41 | - [optional](Composer.md#optional) 42 | - [tap](Composer.md#tap) 43 | - [use](Composer.md#use) 44 | - [builder](Composer.md#builder) 45 | 46 | ## Constructors 47 | 48 | ### constructor 49 | 50 | • **new Composer**\<`T`, `R`\>(): [`Composer`](Composer.md)\<`T`, `R`\> 51 | 52 | #### Type parameters 53 | 54 | | Name | Type | 55 | | :------ | :------ | 56 | | `T` | extends [`UnknownObject`](../README.md#unknownobject) | 57 | | `R` | `T` | 58 | 59 | #### Returns 60 | 61 | [`Composer`](Composer.md)\<`T`, `R`\> 62 | 63 | ## Properties 64 | 65 | ### middlewares 66 | 67 | • `Protected` **middlewares**: [`Middleware`](../README.md#middleware)\<`R`\>[] = `[]` 68 | 69 | #### Defined in 70 | 71 | [composer.ts:30](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L30) 72 | 73 | ## Accessors 74 | 75 | ### length 76 | 77 | • `get` **length**(): `number` 78 | 79 | The number of middleware installed in Composer 80 | 81 | #### Returns 82 | 83 | `number` 84 | 85 | #### Defined in 86 | 87 | [composer.ts:42](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L42) 88 | 89 | ## Methods 90 | 91 | ### after 92 | 93 | ▸ **after**\<`V`\>(`middleware`, `afterMiddleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 94 | 95 | Runs the second middleware after the main 96 | 97 | #### Type parameters 98 | 99 | | Name | Type | 100 | | :------ | :------ | 101 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 102 | 103 | #### Parameters 104 | 105 | | Name | Type | 106 | | :------ | :------ | 107 | | `middleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 108 | | `afterMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 109 | 110 | #### Returns 111 | 112 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 113 | 114 | #### Defined in 115 | 116 | [composer.ts:141](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L141) 117 | 118 | ___ 119 | 120 | ### before 121 | 122 | ▸ **before**\<`V`\>(`beforeMiddleware`, `middleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 123 | 124 | Runs the second middleware before the main 125 | 126 | #### Type parameters 127 | 128 | | Name | Type | 129 | | :------ | :------ | 130 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 131 | 132 | #### Parameters 133 | 134 | | Name | Type | 135 | | :------ | :------ | 136 | | `beforeMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 137 | | `middleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 138 | 139 | #### Returns 140 | 141 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 142 | 143 | #### Defined in 144 | 145 | [composer.ts:131](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L131) 146 | 147 | ___ 148 | 149 | ### branch 150 | 151 | ▸ **branch**\<`V`\>(`condition`, `trueMiddleware`, `falseMiddleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 152 | 153 | By condition splits the middleware 154 | 155 | #### Type parameters 156 | 157 | | Name | Type | 158 | | :------ | :------ | 159 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 160 | 161 | #### Parameters 162 | 163 | | Name | Type | 164 | | :------ | :------ | 165 | | `condition` | [`BranchMiddlewareCondition`](../README.md#branchmiddlewarecondition)\<`T` & `V`\> | 166 | | `trueMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 167 | | `falseMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 168 | 169 | #### Returns 170 | 171 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 172 | 173 | #### Defined in 174 | 175 | [composer.ts:92](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L92) 176 | 177 | ___ 178 | 179 | ### caught 180 | 181 | ▸ **caught**\<`V`\>(`errorHandler`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 182 | 183 | Catches errors in the middleware chain 184 | 185 | #### Type parameters 186 | 187 | | Name | Type | 188 | | :------ | :------ | 189 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 190 | 191 | #### Parameters 192 | 193 | | Name | Type | 194 | | :------ | :------ | 195 | | `errorHandler` | [`CaughtMiddlewareHandler`](../README.md#caughtmiddlewarehandler)\<`T` & `V`\> | 196 | 197 | #### Returns 198 | 199 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 200 | 201 | #### Defined in 202 | 203 | [composer.ts:162](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L162) 204 | 205 | ___ 206 | 207 | ### clone 208 | 209 | ▸ **clone**(): [`Composer`](Composer.md)\<`T`, `R`\> 210 | 211 | Clones a composer object 212 | 213 | #### Returns 214 | 215 | [`Composer`](Composer.md)\<`T`, `R`\> 216 | 217 | #### Defined in 218 | 219 | [composer.ts:49](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L49) 220 | 221 | ___ 222 | 223 | ### compose 224 | 225 | ▸ **compose**(): [`Middleware`](../README.md#middleware)\<`R`\> 226 | 227 | Compose middleware handlers into a single handler 228 | 229 | #### Returns 230 | 231 | [`Middleware`](../README.md#middleware)\<`R`\> 232 | 233 | #### Defined in 234 | 235 | [composer.ts:177](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L177) 236 | 237 | ___ 238 | 239 | ### concurrency 240 | 241 | ▸ **concurrency**\<`V`\>(`middlewares`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 242 | 243 | Concurrently launches middleware, 244 | the chain will continue if `next()` is called in all middlewares 245 | 246 | #### Type parameters 247 | 248 | | Name | Type | 249 | | :------ | :------ | 250 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 251 | 252 | #### Parameters 253 | 254 | | Name | Type | 255 | | :------ | :------ | 256 | | `middlewares` | [`Middleware`](../README.md#middleware)\<`T` & `V`\>[] | 257 | 258 | #### Returns 259 | 260 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 261 | 262 | #### Defined in 263 | 264 | [composer.ts:170](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L170) 265 | 266 | ___ 267 | 268 | ### enforce 269 | 270 | ▸ **enforce**\<`V`\>(`beforeMiddleware`, `middleware`, `afterMiddleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 271 | 272 | Runs middleware before and after the main 273 | 274 | #### Type parameters 275 | 276 | | Name | Type | 277 | | :------ | :------ | 278 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 279 | 280 | #### Parameters 281 | 282 | | Name | Type | 283 | | :------ | :------ | 284 | | `beforeMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 285 | | `middleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 286 | | `afterMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 287 | 288 | #### Returns 289 | 290 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 291 | 292 | #### Defined in 293 | 294 | [composer.ts:151](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L151) 295 | 296 | ___ 297 | 298 | ### filter 299 | 300 | ▸ **filter**\<`V`\>(`condition`, `filterMiddleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 301 | 302 | Conditionally runs middleware or stops the chain 303 | 304 | #### Type parameters 305 | 306 | | Name | Type | 307 | | :------ | :------ | 308 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 309 | 310 | #### Parameters 311 | 312 | | Name | Type | 313 | | :------ | :------ | 314 | | `condition` | [`BranchMiddlewareCondition`](../README.md#branchmiddlewarecondition)\<`T` & `V`\> | 315 | | `filterMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 316 | 317 | #### Returns 318 | 319 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 320 | 321 | #### Defined in 322 | 323 | [composer.ts:121](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L121) 324 | 325 | ___ 326 | 327 | ### fork 328 | 329 | ▸ **fork**\<`V`\>(`middleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 330 | 331 | Runs the middleware at the next event loop and force call `next()` 332 | 333 | #### Type parameters 334 | 335 | | Name | Type | 336 | | :------ | :------ | 337 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 338 | 339 | #### Parameters 340 | 341 | | Name | Type | 342 | | :------ | :------ | 343 | | `middleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 344 | 345 | #### Returns 346 | 347 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 348 | 349 | #### Defined in 350 | 351 | [composer.ts:85](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L85) 352 | 353 | ___ 354 | 355 | ### lazy 356 | 357 | ▸ **lazy**\<`V`\>(`factory`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 358 | 359 | Lazily asynchronously gets middleware 360 | 361 | #### Type parameters 362 | 363 | | Name | Type | 364 | | :------ | :------ | 365 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 366 | 367 | #### Parameters 368 | 369 | | Name | Type | 370 | | :------ | :------ | 371 | | `factory` | [`LazyMiddlewareFactory`](../README.md#lazymiddlewarefactory)\<`T` & `V`\> | 372 | 373 | #### Returns 374 | 375 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 376 | 377 | #### Defined in 378 | 379 | [composer.ts:71](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L71) 380 | 381 | ___ 382 | 383 | ### optional 384 | 385 | ▸ **optional**\<`V`\>(`condition`, `optionalMiddleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 386 | 387 | Conditionally runs optional middleware or skips middleware 388 | 389 | #### Type parameters 390 | 391 | | Name | Type | 392 | | :------ | :------ | 393 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 394 | 395 | #### Parameters 396 | 397 | | Name | Type | 398 | | :------ | :------ | 399 | | `condition` | [`BranchMiddlewareCondition`](../README.md#branchmiddlewarecondition)\<`T` & `V`\> | 400 | | `optionalMiddleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 401 | 402 | #### Returns 403 | 404 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 405 | 406 | #### Defined in 407 | 408 | [composer.ts:111](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L111) 409 | 410 | ___ 411 | 412 | ### tap 413 | 414 | ▸ **tap**\<`V`\>(`middleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 415 | 416 | Runs the middleware and force call `next()` 417 | 418 | #### Type parameters 419 | 420 | | Name | Type | 421 | | :------ | :------ | 422 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 423 | 424 | #### Parameters 425 | 426 | | Name | Type | 427 | | :------ | :------ | 428 | | `middleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 429 | 430 | #### Returns 431 | 432 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 433 | 434 | #### Defined in 435 | 436 | [composer.ts:78](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L78) 437 | 438 | ___ 439 | 440 | ### use 441 | 442 | ▸ **use**\<`V`\>(`middleware`): [`Composer`](Composer.md)\<`T` & `V`, `R`\> 443 | 444 | Adds middleware to the chain 445 | 446 | #### Type parameters 447 | 448 | | Name | Type | 449 | | :------ | :------ | 450 | | `V` | [`UnknownObject`](../README.md#unknownobject) | 451 | 452 | #### Parameters 453 | 454 | | Name | Type | 455 | | :------ | :------ | 456 | | `middleware` | [`Middleware`](../README.md#middleware)\<`T` & `V`\> | 457 | 458 | #### Returns 459 | 460 | [`Composer`](Composer.md)\<`T` & `V`, `R`\> 461 | 462 | #### Defined in 463 | 464 | [composer.ts:60](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L60) 465 | 466 | ___ 467 | 468 | ### builder 469 | 470 | ▸ **builder**\<`Context`\>(): [`Composer`](Composer.md)\<`Context`, `Context`\> 471 | 472 | Invokes a new instance of the Composer class 473 | 474 | #### Type parameters 475 | 476 | | Name | Type | 477 | | :------ | :------ | 478 | | `Context` | extends [`UnknownObject`](../README.md#unknownobject) | 479 | 480 | #### Returns 481 | 482 | [`Composer`](Composer.md)\<`Context`, `Context`\> 483 | 484 | #### Defined in 485 | 486 | [composer.ts:35](https://github.com/negezor/middleware-io/blob/cfc102d315382709d9f9d43771812ee5ab488e62/src/composer.ts#L35) 487 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-io", 3 | "version": "2.8.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "middleware-io", 9 | "version": "2.8.1", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@biomejs/biome": "^1.8.1", 13 | "@types/node": "^20.14.2", 14 | "rollup": "^4.18.0", 15 | "rollup-plugin-typescript2": "^0.36.0", 16 | "tinybench": "^2.8.0", 17 | "tsx": "^4.15.5", 18 | "typedoc": "^0.25.13", 19 | "typedoc-plugin-markdown": "^4.0.3", 20 | "typescript": "^5.4.5" 21 | }, 22 | "engines": { 23 | "node": ">=12.0.0" 24 | } 25 | }, 26 | "node_modules/@biomejs/biome": { 27 | "version": "1.8.1", 28 | "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.1.tgz", 29 | "integrity": "sha512-fQXGfvq6DIXem12dGQCM2tNF+vsNHH1qs3C7WeOu75Pd0trduoTmoO7G4ntLJ2qDs5wuw981H+cxQhi1uHnAtA==", 30 | "dev": true, 31 | "hasInstallScript": true, 32 | "license": "MIT OR Apache-2.0", 33 | "bin": { 34 | "biome": "bin/biome" 35 | }, 36 | "engines": { 37 | "node": ">=14.21.3" 38 | }, 39 | "funding": { 40 | "type": "opencollective", 41 | "url": "https://opencollective.com/biome" 42 | }, 43 | "optionalDependencies": { 44 | "@biomejs/cli-darwin-arm64": "1.8.1", 45 | "@biomejs/cli-darwin-x64": "1.8.1", 46 | "@biomejs/cli-linux-arm64": "1.8.1", 47 | "@biomejs/cli-linux-arm64-musl": "1.8.1", 48 | "@biomejs/cli-linux-x64": "1.8.1", 49 | "@biomejs/cli-linux-x64-musl": "1.8.1", 50 | "@biomejs/cli-win32-arm64": "1.8.1", 51 | "@biomejs/cli-win32-x64": "1.8.1" 52 | } 53 | }, 54 | "node_modules/@biomejs/cli-darwin-arm64": { 55 | "version": "1.8.1", 56 | "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.1.tgz", 57 | "integrity": "sha512-XLiB7Uu6GALIOBWzQ2aMD0ru4Ly5/qSeQF7kk3AabzJ/kwsEWSe33iVySBP/SS2qv25cgqNiLksjGcw2bHT3mw==", 58 | "cpu": [ 59 | "arm64" 60 | ], 61 | "dev": true, 62 | "license": "MIT OR Apache-2.0", 63 | "optional": true, 64 | "os": [ 65 | "darwin" 66 | ], 67 | "engines": { 68 | "node": ">=14.21.3" 69 | } 70 | }, 71 | "node_modules/@biomejs/cli-darwin-x64": { 72 | "version": "1.8.1", 73 | "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.1.tgz", 74 | "integrity": "sha512-uMTSxVLMfqkBVqyc25hSn83jBbp+wtWjzM/pHFlKXt3htJuw7FErVGW0nmQ9Sxa9vJ7GcqoltLMl28VQRIMYzg==", 75 | "cpu": [ 76 | "x64" 77 | ], 78 | "dev": true, 79 | "license": "MIT OR Apache-2.0", 80 | "optional": true, 81 | "os": [ 82 | "darwin" 83 | ], 84 | "engines": { 85 | "node": ">=14.21.3" 86 | } 87 | }, 88 | "node_modules/@biomejs/cli-linux-arm64": { 89 | "version": "1.8.1", 90 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.1.tgz", 91 | "integrity": "sha512-3SzZRuC/9Oi2P2IBNPsEj0KXxSXUEYRR2kfRF/Ve8QAfGgrt4qnwuWd6QQKKN5R+oYH691qjm+cXBKEcrP1v/Q==", 92 | "cpu": [ 93 | "arm64" 94 | ], 95 | "dev": true, 96 | "license": "MIT OR Apache-2.0", 97 | "optional": true, 98 | "os": [ 99 | "linux" 100 | ], 101 | "engines": { 102 | "node": ">=14.21.3" 103 | } 104 | }, 105 | "node_modules/@biomejs/cli-linux-arm64-musl": { 106 | "version": "1.8.1", 107 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.1.tgz", 108 | "integrity": "sha512-UQ8Wc01J0wQL+5AYOc7qkJn20B4PZmQL1KrmDZh7ot0DvD6aX4+8mmfd/dG5b6Zjo/44QvCKcvkFGCMRYuhWZA==", 109 | "cpu": [ 110 | "arm64" 111 | ], 112 | "dev": true, 113 | "license": "MIT OR Apache-2.0", 114 | "optional": true, 115 | "os": [ 116 | "linux" 117 | ], 118 | "engines": { 119 | "node": ">=14.21.3" 120 | } 121 | }, 122 | "node_modules/@biomejs/cli-linux-x64": { 123 | "version": "1.8.1", 124 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.1.tgz", 125 | "integrity": "sha512-AeBycVdNrTzsyYKEOtR2R0Ph0hCD0sCshcp2aOnfGP0hCZbtFg09D0SdKLbyzKntisY41HxKVrydYiaApp+2uw==", 126 | "cpu": [ 127 | "x64" 128 | ], 129 | "dev": true, 130 | "license": "MIT OR Apache-2.0", 131 | "optional": true, 132 | "os": [ 133 | "linux" 134 | ], 135 | "engines": { 136 | "node": ">=14.21.3" 137 | } 138 | }, 139 | "node_modules/@biomejs/cli-linux-x64-musl": { 140 | "version": "1.8.1", 141 | "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.1.tgz", 142 | "integrity": "sha512-fYbP/kNu/rtZ4kKzWVocIdqZOtBSUEg9qUhZaao3dy3CRzafR6u6KDtBeSCnt47O+iLnks1eOR1TUxzr5+QuqA==", 143 | "cpu": [ 144 | "x64" 145 | ], 146 | "dev": true, 147 | "license": "MIT OR Apache-2.0", 148 | "optional": true, 149 | "os": [ 150 | "linux" 151 | ], 152 | "engines": { 153 | "node": ">=14.21.3" 154 | } 155 | }, 156 | "node_modules/@biomejs/cli-win32-arm64": { 157 | "version": "1.8.1", 158 | "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.1.tgz", 159 | "integrity": "sha512-6tEd1H/iFKpgpE3OIB7oNgW5XkjiVMzMRPL8zYoZ036YfuJ5nMYm9eB9H/y81+8Z76vL48fiYzMPotJwukGPqQ==", 160 | "cpu": [ 161 | "arm64" 162 | ], 163 | "dev": true, 164 | "license": "MIT OR Apache-2.0", 165 | "optional": true, 166 | "os": [ 167 | "win32" 168 | ], 169 | "engines": { 170 | "node": ">=14.21.3" 171 | } 172 | }, 173 | "node_modules/@biomejs/cli-win32-x64": { 174 | "version": "1.8.1", 175 | "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.1.tgz", 176 | "integrity": "sha512-g2H31jJzYmS4jkvl6TiyEjEX+Nv79a5km/xn+5DARTp5MBFzC9gwceusSSB2AkJKqZzY131AiACAWjKrVt5Ijw==", 177 | "cpu": [ 178 | "x64" 179 | ], 180 | "dev": true, 181 | "license": "MIT OR Apache-2.0", 182 | "optional": true, 183 | "os": [ 184 | "win32" 185 | ], 186 | "engines": { 187 | "node": ">=14.21.3" 188 | } 189 | }, 190 | "node_modules/@esbuild/aix-ppc64": { 191 | "version": "0.21.5", 192 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", 193 | "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", 194 | "cpu": [ 195 | "ppc64" 196 | ], 197 | "dev": true, 198 | "license": "MIT", 199 | "optional": true, 200 | "os": [ 201 | "aix" 202 | ], 203 | "engines": { 204 | "node": ">=12" 205 | } 206 | }, 207 | "node_modules/@esbuild/android-arm": { 208 | "version": "0.21.5", 209 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", 210 | "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", 211 | "cpu": [ 212 | "arm" 213 | ], 214 | "dev": true, 215 | "license": "MIT", 216 | "optional": true, 217 | "os": [ 218 | "android" 219 | ], 220 | "engines": { 221 | "node": ">=12" 222 | } 223 | }, 224 | "node_modules/@esbuild/android-arm64": { 225 | "version": "0.21.5", 226 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", 227 | "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", 228 | "cpu": [ 229 | "arm64" 230 | ], 231 | "dev": true, 232 | "license": "MIT", 233 | "optional": true, 234 | "os": [ 235 | "android" 236 | ], 237 | "engines": { 238 | "node": ">=12" 239 | } 240 | }, 241 | "node_modules/@esbuild/android-x64": { 242 | "version": "0.21.5", 243 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", 244 | "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", 245 | "cpu": [ 246 | "x64" 247 | ], 248 | "dev": true, 249 | "license": "MIT", 250 | "optional": true, 251 | "os": [ 252 | "android" 253 | ], 254 | "engines": { 255 | "node": ">=12" 256 | } 257 | }, 258 | "node_modules/@esbuild/darwin-arm64": { 259 | "version": "0.21.5", 260 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", 261 | "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", 262 | "cpu": [ 263 | "arm64" 264 | ], 265 | "dev": true, 266 | "license": "MIT", 267 | "optional": true, 268 | "os": [ 269 | "darwin" 270 | ], 271 | "engines": { 272 | "node": ">=12" 273 | } 274 | }, 275 | "node_modules/@esbuild/darwin-x64": { 276 | "version": "0.21.5", 277 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", 278 | "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", 279 | "cpu": [ 280 | "x64" 281 | ], 282 | "dev": true, 283 | "license": "MIT", 284 | "optional": true, 285 | "os": [ 286 | "darwin" 287 | ], 288 | "engines": { 289 | "node": ">=12" 290 | } 291 | }, 292 | "node_modules/@esbuild/freebsd-arm64": { 293 | "version": "0.21.5", 294 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", 295 | "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", 296 | "cpu": [ 297 | "arm64" 298 | ], 299 | "dev": true, 300 | "license": "MIT", 301 | "optional": true, 302 | "os": [ 303 | "freebsd" 304 | ], 305 | "engines": { 306 | "node": ">=12" 307 | } 308 | }, 309 | "node_modules/@esbuild/freebsd-x64": { 310 | "version": "0.21.5", 311 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", 312 | "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", 313 | "cpu": [ 314 | "x64" 315 | ], 316 | "dev": true, 317 | "license": "MIT", 318 | "optional": true, 319 | "os": [ 320 | "freebsd" 321 | ], 322 | "engines": { 323 | "node": ">=12" 324 | } 325 | }, 326 | "node_modules/@esbuild/linux-arm": { 327 | "version": "0.21.5", 328 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", 329 | "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", 330 | "cpu": [ 331 | "arm" 332 | ], 333 | "dev": true, 334 | "license": "MIT", 335 | "optional": true, 336 | "os": [ 337 | "linux" 338 | ], 339 | "engines": { 340 | "node": ">=12" 341 | } 342 | }, 343 | "node_modules/@esbuild/linux-arm64": { 344 | "version": "0.21.5", 345 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", 346 | "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", 347 | "cpu": [ 348 | "arm64" 349 | ], 350 | "dev": true, 351 | "license": "MIT", 352 | "optional": true, 353 | "os": [ 354 | "linux" 355 | ], 356 | "engines": { 357 | "node": ">=12" 358 | } 359 | }, 360 | "node_modules/@esbuild/linux-ia32": { 361 | "version": "0.21.5", 362 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", 363 | "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", 364 | "cpu": [ 365 | "ia32" 366 | ], 367 | "dev": true, 368 | "license": "MIT", 369 | "optional": true, 370 | "os": [ 371 | "linux" 372 | ], 373 | "engines": { 374 | "node": ">=12" 375 | } 376 | }, 377 | "node_modules/@esbuild/linux-loong64": { 378 | "version": "0.21.5", 379 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", 380 | "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", 381 | "cpu": [ 382 | "loong64" 383 | ], 384 | "dev": true, 385 | "license": "MIT", 386 | "optional": true, 387 | "os": [ 388 | "linux" 389 | ], 390 | "engines": { 391 | "node": ">=12" 392 | } 393 | }, 394 | "node_modules/@esbuild/linux-mips64el": { 395 | "version": "0.21.5", 396 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", 397 | "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", 398 | "cpu": [ 399 | "mips64el" 400 | ], 401 | "dev": true, 402 | "license": "MIT", 403 | "optional": true, 404 | "os": [ 405 | "linux" 406 | ], 407 | "engines": { 408 | "node": ">=12" 409 | } 410 | }, 411 | "node_modules/@esbuild/linux-ppc64": { 412 | "version": "0.21.5", 413 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", 414 | "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", 415 | "cpu": [ 416 | "ppc64" 417 | ], 418 | "dev": true, 419 | "license": "MIT", 420 | "optional": true, 421 | "os": [ 422 | "linux" 423 | ], 424 | "engines": { 425 | "node": ">=12" 426 | } 427 | }, 428 | "node_modules/@esbuild/linux-riscv64": { 429 | "version": "0.21.5", 430 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", 431 | "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", 432 | "cpu": [ 433 | "riscv64" 434 | ], 435 | "dev": true, 436 | "license": "MIT", 437 | "optional": true, 438 | "os": [ 439 | "linux" 440 | ], 441 | "engines": { 442 | "node": ">=12" 443 | } 444 | }, 445 | "node_modules/@esbuild/linux-s390x": { 446 | "version": "0.21.5", 447 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", 448 | "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", 449 | "cpu": [ 450 | "s390x" 451 | ], 452 | "dev": true, 453 | "license": "MIT", 454 | "optional": true, 455 | "os": [ 456 | "linux" 457 | ], 458 | "engines": { 459 | "node": ">=12" 460 | } 461 | }, 462 | "node_modules/@esbuild/linux-x64": { 463 | "version": "0.21.5", 464 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", 465 | "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", 466 | "cpu": [ 467 | "x64" 468 | ], 469 | "dev": true, 470 | "license": "MIT", 471 | "optional": true, 472 | "os": [ 473 | "linux" 474 | ], 475 | "engines": { 476 | "node": ">=12" 477 | } 478 | }, 479 | "node_modules/@esbuild/netbsd-x64": { 480 | "version": "0.21.5", 481 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", 482 | "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", 483 | "cpu": [ 484 | "x64" 485 | ], 486 | "dev": true, 487 | "license": "MIT", 488 | "optional": true, 489 | "os": [ 490 | "netbsd" 491 | ], 492 | "engines": { 493 | "node": ">=12" 494 | } 495 | }, 496 | "node_modules/@esbuild/openbsd-x64": { 497 | "version": "0.21.5", 498 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", 499 | "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", 500 | "cpu": [ 501 | "x64" 502 | ], 503 | "dev": true, 504 | "license": "MIT", 505 | "optional": true, 506 | "os": [ 507 | "openbsd" 508 | ], 509 | "engines": { 510 | "node": ">=12" 511 | } 512 | }, 513 | "node_modules/@esbuild/sunos-x64": { 514 | "version": "0.21.5", 515 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", 516 | "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", 517 | "cpu": [ 518 | "x64" 519 | ], 520 | "dev": true, 521 | "license": "MIT", 522 | "optional": true, 523 | "os": [ 524 | "sunos" 525 | ], 526 | "engines": { 527 | "node": ">=12" 528 | } 529 | }, 530 | "node_modules/@esbuild/win32-arm64": { 531 | "version": "0.21.5", 532 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", 533 | "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", 534 | "cpu": [ 535 | "arm64" 536 | ], 537 | "dev": true, 538 | "license": "MIT", 539 | "optional": true, 540 | "os": [ 541 | "win32" 542 | ], 543 | "engines": { 544 | "node": ">=12" 545 | } 546 | }, 547 | "node_modules/@esbuild/win32-ia32": { 548 | "version": "0.21.5", 549 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", 550 | "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", 551 | "cpu": [ 552 | "ia32" 553 | ], 554 | "dev": true, 555 | "license": "MIT", 556 | "optional": true, 557 | "os": [ 558 | "win32" 559 | ], 560 | "engines": { 561 | "node": ">=12" 562 | } 563 | }, 564 | "node_modules/@esbuild/win32-x64": { 565 | "version": "0.21.5", 566 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", 567 | "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", 568 | "cpu": [ 569 | "x64" 570 | ], 571 | "dev": true, 572 | "license": "MIT", 573 | "optional": true, 574 | "os": [ 575 | "win32" 576 | ], 577 | "engines": { 578 | "node": ">=12" 579 | } 580 | }, 581 | "node_modules/@rollup/pluginutils": { 582 | "version": "4.2.1", 583 | "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", 584 | "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", 585 | "dev": true, 586 | "license": "MIT", 587 | "dependencies": { 588 | "estree-walker": "^2.0.1", 589 | "picomatch": "^2.2.2" 590 | }, 591 | "engines": { 592 | "node": ">= 8.0.0" 593 | } 594 | }, 595 | "node_modules/@rollup/rollup-android-arm-eabi": { 596 | "version": "4.18.0", 597 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", 598 | "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", 599 | "cpu": [ 600 | "arm" 601 | ], 602 | "dev": true, 603 | "license": "MIT", 604 | "optional": true, 605 | "os": [ 606 | "android" 607 | ] 608 | }, 609 | "node_modules/@rollup/rollup-android-arm64": { 610 | "version": "4.18.0", 611 | "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", 612 | "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", 613 | "cpu": [ 614 | "arm64" 615 | ], 616 | "dev": true, 617 | "license": "MIT", 618 | "optional": true, 619 | "os": [ 620 | "android" 621 | ] 622 | }, 623 | "node_modules/@rollup/rollup-darwin-arm64": { 624 | "version": "4.18.0", 625 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", 626 | "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", 627 | "cpu": [ 628 | "arm64" 629 | ], 630 | "dev": true, 631 | "license": "MIT", 632 | "optional": true, 633 | "os": [ 634 | "darwin" 635 | ] 636 | }, 637 | "node_modules/@rollup/rollup-darwin-x64": { 638 | "version": "4.18.0", 639 | "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", 640 | "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", 641 | "cpu": [ 642 | "x64" 643 | ], 644 | "dev": true, 645 | "license": "MIT", 646 | "optional": true, 647 | "os": [ 648 | "darwin" 649 | ] 650 | }, 651 | "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 652 | "version": "4.18.0", 653 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", 654 | "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", 655 | "cpu": [ 656 | "arm" 657 | ], 658 | "dev": true, 659 | "license": "MIT", 660 | "optional": true, 661 | "os": [ 662 | "linux" 663 | ] 664 | }, 665 | "node_modules/@rollup/rollup-linux-arm-musleabihf": { 666 | "version": "4.18.0", 667 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", 668 | "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", 669 | "cpu": [ 670 | "arm" 671 | ], 672 | "dev": true, 673 | "license": "MIT", 674 | "optional": true, 675 | "os": [ 676 | "linux" 677 | ] 678 | }, 679 | "node_modules/@rollup/rollup-linux-arm64-gnu": { 680 | "version": "4.18.0", 681 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", 682 | "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", 683 | "cpu": [ 684 | "arm64" 685 | ], 686 | "dev": true, 687 | "license": "MIT", 688 | "optional": true, 689 | "os": [ 690 | "linux" 691 | ] 692 | }, 693 | "node_modules/@rollup/rollup-linux-arm64-musl": { 694 | "version": "4.18.0", 695 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", 696 | "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", 697 | "cpu": [ 698 | "arm64" 699 | ], 700 | "dev": true, 701 | "license": "MIT", 702 | "optional": true, 703 | "os": [ 704 | "linux" 705 | ] 706 | }, 707 | "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { 708 | "version": "4.18.0", 709 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", 710 | "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", 711 | "cpu": [ 712 | "ppc64" 713 | ], 714 | "dev": true, 715 | "license": "MIT", 716 | "optional": true, 717 | "os": [ 718 | "linux" 719 | ] 720 | }, 721 | "node_modules/@rollup/rollup-linux-riscv64-gnu": { 722 | "version": "4.18.0", 723 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", 724 | "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", 725 | "cpu": [ 726 | "riscv64" 727 | ], 728 | "dev": true, 729 | "license": "MIT", 730 | "optional": true, 731 | "os": [ 732 | "linux" 733 | ] 734 | }, 735 | "node_modules/@rollup/rollup-linux-s390x-gnu": { 736 | "version": "4.18.0", 737 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", 738 | "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", 739 | "cpu": [ 740 | "s390x" 741 | ], 742 | "dev": true, 743 | "license": "MIT", 744 | "optional": true, 745 | "os": [ 746 | "linux" 747 | ] 748 | }, 749 | "node_modules/@rollup/rollup-linux-x64-gnu": { 750 | "version": "4.18.0", 751 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", 752 | "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", 753 | "cpu": [ 754 | "x64" 755 | ], 756 | "dev": true, 757 | "license": "MIT", 758 | "optional": true, 759 | "os": [ 760 | "linux" 761 | ] 762 | }, 763 | "node_modules/@rollup/rollup-linux-x64-musl": { 764 | "version": "4.18.0", 765 | "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", 766 | "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", 767 | "cpu": [ 768 | "x64" 769 | ], 770 | "dev": true, 771 | "license": "MIT", 772 | "optional": true, 773 | "os": [ 774 | "linux" 775 | ] 776 | }, 777 | "node_modules/@rollup/rollup-win32-arm64-msvc": { 778 | "version": "4.18.0", 779 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", 780 | "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", 781 | "cpu": [ 782 | "arm64" 783 | ], 784 | "dev": true, 785 | "license": "MIT", 786 | "optional": true, 787 | "os": [ 788 | "win32" 789 | ] 790 | }, 791 | "node_modules/@rollup/rollup-win32-ia32-msvc": { 792 | "version": "4.18.0", 793 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", 794 | "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", 795 | "cpu": [ 796 | "ia32" 797 | ], 798 | "dev": true, 799 | "license": "MIT", 800 | "optional": true, 801 | "os": [ 802 | "win32" 803 | ] 804 | }, 805 | "node_modules/@rollup/rollup-win32-x64-msvc": { 806 | "version": "4.18.0", 807 | "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", 808 | "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", 809 | "cpu": [ 810 | "x64" 811 | ], 812 | "dev": true, 813 | "license": "MIT", 814 | "optional": true, 815 | "os": [ 816 | "win32" 817 | ] 818 | }, 819 | "node_modules/@types/estree": { 820 | "version": "1.0.5", 821 | "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", 822 | "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", 823 | "dev": true, 824 | "license": "MIT" 825 | }, 826 | "node_modules/@types/node": { 827 | "version": "20.14.2", 828 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.2.tgz", 829 | "integrity": "sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==", 830 | "dev": true, 831 | "license": "MIT", 832 | "dependencies": { 833 | "undici-types": "~5.26.4" 834 | } 835 | }, 836 | "node_modules/ansi-sequence-parser": { 837 | "version": "1.1.1", 838 | "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", 839 | "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", 840 | "dev": true, 841 | "license": "MIT" 842 | }, 843 | "node_modules/balanced-match": { 844 | "version": "1.0.2", 845 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 846 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 847 | "dev": true, 848 | "license": "MIT" 849 | }, 850 | "node_modules/brace-expansion": { 851 | "version": "2.0.1", 852 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 853 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 854 | "dev": true, 855 | "license": "MIT", 856 | "dependencies": { 857 | "balanced-match": "^1.0.0" 858 | } 859 | }, 860 | "node_modules/commondir": { 861 | "version": "1.0.1", 862 | "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", 863 | "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", 864 | "dev": true, 865 | "license": "MIT" 866 | }, 867 | "node_modules/esbuild": { 868 | "version": "0.21.5", 869 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", 870 | "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", 871 | "dev": true, 872 | "hasInstallScript": true, 873 | "license": "MIT", 874 | "bin": { 875 | "esbuild": "bin/esbuild" 876 | }, 877 | "engines": { 878 | "node": ">=12" 879 | }, 880 | "optionalDependencies": { 881 | "@esbuild/aix-ppc64": "0.21.5", 882 | "@esbuild/android-arm": "0.21.5", 883 | "@esbuild/android-arm64": "0.21.5", 884 | "@esbuild/android-x64": "0.21.5", 885 | "@esbuild/darwin-arm64": "0.21.5", 886 | "@esbuild/darwin-x64": "0.21.5", 887 | "@esbuild/freebsd-arm64": "0.21.5", 888 | "@esbuild/freebsd-x64": "0.21.5", 889 | "@esbuild/linux-arm": "0.21.5", 890 | "@esbuild/linux-arm64": "0.21.5", 891 | "@esbuild/linux-ia32": "0.21.5", 892 | "@esbuild/linux-loong64": "0.21.5", 893 | "@esbuild/linux-mips64el": "0.21.5", 894 | "@esbuild/linux-ppc64": "0.21.5", 895 | "@esbuild/linux-riscv64": "0.21.5", 896 | "@esbuild/linux-s390x": "0.21.5", 897 | "@esbuild/linux-x64": "0.21.5", 898 | "@esbuild/netbsd-x64": "0.21.5", 899 | "@esbuild/openbsd-x64": "0.21.5", 900 | "@esbuild/sunos-x64": "0.21.5", 901 | "@esbuild/win32-arm64": "0.21.5", 902 | "@esbuild/win32-ia32": "0.21.5", 903 | "@esbuild/win32-x64": "0.21.5" 904 | } 905 | }, 906 | "node_modules/estree-walker": { 907 | "version": "2.0.2", 908 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 909 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", 910 | "dev": true, 911 | "license": "MIT" 912 | }, 913 | "node_modules/find-cache-dir": { 914 | "version": "3.3.2", 915 | "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", 916 | "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", 917 | "dev": true, 918 | "license": "MIT", 919 | "dependencies": { 920 | "commondir": "^1.0.1", 921 | "make-dir": "^3.0.2", 922 | "pkg-dir": "^4.1.0" 923 | }, 924 | "engines": { 925 | "node": ">=8" 926 | }, 927 | "funding": { 928 | "url": "https://github.com/avajs/find-cache-dir?sponsor=1" 929 | } 930 | }, 931 | "node_modules/find-up": { 932 | "version": "4.1.0", 933 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", 934 | "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", 935 | "dev": true, 936 | "license": "MIT", 937 | "dependencies": { 938 | "locate-path": "^5.0.0", 939 | "path-exists": "^4.0.0" 940 | }, 941 | "engines": { 942 | "node": ">=8" 943 | } 944 | }, 945 | "node_modules/fs-extra": { 946 | "version": "10.1.0", 947 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", 948 | "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", 949 | "dev": true, 950 | "license": "MIT", 951 | "dependencies": { 952 | "graceful-fs": "^4.2.0", 953 | "jsonfile": "^6.0.1", 954 | "universalify": "^2.0.0" 955 | }, 956 | "engines": { 957 | "node": ">=12" 958 | } 959 | }, 960 | "node_modules/fsevents": { 961 | "version": "2.3.3", 962 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 963 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 964 | "dev": true, 965 | "hasInstallScript": true, 966 | "license": "MIT", 967 | "optional": true, 968 | "os": [ 969 | "darwin" 970 | ], 971 | "engines": { 972 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 973 | } 974 | }, 975 | "node_modules/get-tsconfig": { 976 | "version": "4.7.5", 977 | "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", 978 | "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", 979 | "dev": true, 980 | "license": "MIT", 981 | "dependencies": { 982 | "resolve-pkg-maps": "^1.0.0" 983 | }, 984 | "funding": { 985 | "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" 986 | } 987 | }, 988 | "node_modules/graceful-fs": { 989 | "version": "4.2.11", 990 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", 991 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", 992 | "dev": true, 993 | "license": "ISC" 994 | }, 995 | "node_modules/jsonc-parser": { 996 | "version": "3.2.1", 997 | "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", 998 | "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", 999 | "dev": true, 1000 | "license": "MIT" 1001 | }, 1002 | "node_modules/jsonfile": { 1003 | "version": "6.1.0", 1004 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 1005 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 1006 | "dev": true, 1007 | "license": "MIT", 1008 | "dependencies": { 1009 | "universalify": "^2.0.0" 1010 | }, 1011 | "optionalDependencies": { 1012 | "graceful-fs": "^4.1.6" 1013 | } 1014 | }, 1015 | "node_modules/locate-path": { 1016 | "version": "5.0.0", 1017 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", 1018 | "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", 1019 | "dev": true, 1020 | "license": "MIT", 1021 | "dependencies": { 1022 | "p-locate": "^4.1.0" 1023 | }, 1024 | "engines": { 1025 | "node": ">=8" 1026 | } 1027 | }, 1028 | "node_modules/lunr": { 1029 | "version": "2.3.9", 1030 | "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", 1031 | "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", 1032 | "dev": true, 1033 | "license": "MIT" 1034 | }, 1035 | "node_modules/make-dir": { 1036 | "version": "3.1.0", 1037 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", 1038 | "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", 1039 | "dev": true, 1040 | "license": "MIT", 1041 | "dependencies": { 1042 | "semver": "^6.0.0" 1043 | }, 1044 | "engines": { 1045 | "node": ">=8" 1046 | }, 1047 | "funding": { 1048 | "url": "https://github.com/sponsors/sindresorhus" 1049 | } 1050 | }, 1051 | "node_modules/make-dir/node_modules/semver": { 1052 | "version": "6.3.1", 1053 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 1054 | "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 1055 | "dev": true, 1056 | "license": "ISC", 1057 | "bin": { 1058 | "semver": "bin/semver.js" 1059 | } 1060 | }, 1061 | "node_modules/marked": { 1062 | "version": "4.3.0", 1063 | "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", 1064 | "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", 1065 | "dev": true, 1066 | "license": "MIT", 1067 | "bin": { 1068 | "marked": "bin/marked.js" 1069 | }, 1070 | "engines": { 1071 | "node": ">= 12" 1072 | } 1073 | }, 1074 | "node_modules/minimatch": { 1075 | "version": "9.0.4", 1076 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", 1077 | "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", 1078 | "dev": true, 1079 | "license": "ISC", 1080 | "dependencies": { 1081 | "brace-expansion": "^2.0.1" 1082 | }, 1083 | "engines": { 1084 | "node": ">=16 || 14 >=14.17" 1085 | }, 1086 | "funding": { 1087 | "url": "https://github.com/sponsors/isaacs" 1088 | } 1089 | }, 1090 | "node_modules/p-limit": { 1091 | "version": "2.3.0", 1092 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", 1093 | "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", 1094 | "dev": true, 1095 | "license": "MIT", 1096 | "dependencies": { 1097 | "p-try": "^2.0.0" 1098 | }, 1099 | "engines": { 1100 | "node": ">=6" 1101 | }, 1102 | "funding": { 1103 | "url": "https://github.com/sponsors/sindresorhus" 1104 | } 1105 | }, 1106 | "node_modules/p-locate": { 1107 | "version": "4.1.0", 1108 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", 1109 | "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", 1110 | "dev": true, 1111 | "license": "MIT", 1112 | "dependencies": { 1113 | "p-limit": "^2.2.0" 1114 | }, 1115 | "engines": { 1116 | "node": ">=8" 1117 | } 1118 | }, 1119 | "node_modules/p-try": { 1120 | "version": "2.2.0", 1121 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", 1122 | "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", 1123 | "dev": true, 1124 | "license": "MIT", 1125 | "engines": { 1126 | "node": ">=6" 1127 | } 1128 | }, 1129 | "node_modules/path-exists": { 1130 | "version": "4.0.0", 1131 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1132 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 1133 | "dev": true, 1134 | "license": "MIT", 1135 | "engines": { 1136 | "node": ">=8" 1137 | } 1138 | }, 1139 | "node_modules/picomatch": { 1140 | "version": "2.3.1", 1141 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 1142 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 1143 | "dev": true, 1144 | "license": "MIT", 1145 | "engines": { 1146 | "node": ">=8.6" 1147 | }, 1148 | "funding": { 1149 | "url": "https://github.com/sponsors/jonschlinkert" 1150 | } 1151 | }, 1152 | "node_modules/pkg-dir": { 1153 | "version": "4.2.0", 1154 | "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", 1155 | "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", 1156 | "dev": true, 1157 | "license": "MIT", 1158 | "dependencies": { 1159 | "find-up": "^4.0.0" 1160 | }, 1161 | "engines": { 1162 | "node": ">=8" 1163 | } 1164 | }, 1165 | "node_modules/resolve-pkg-maps": { 1166 | "version": "1.0.0", 1167 | "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", 1168 | "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", 1169 | "dev": true, 1170 | "license": "MIT", 1171 | "funding": { 1172 | "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" 1173 | } 1174 | }, 1175 | "node_modules/rollup": { 1176 | "version": "4.18.0", 1177 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", 1178 | "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", 1179 | "dev": true, 1180 | "license": "MIT", 1181 | "dependencies": { 1182 | "@types/estree": "1.0.5" 1183 | }, 1184 | "bin": { 1185 | "rollup": "dist/bin/rollup" 1186 | }, 1187 | "engines": { 1188 | "node": ">=18.0.0", 1189 | "npm": ">=8.0.0" 1190 | }, 1191 | "optionalDependencies": { 1192 | "@rollup/rollup-android-arm-eabi": "4.18.0", 1193 | "@rollup/rollup-android-arm64": "4.18.0", 1194 | "@rollup/rollup-darwin-arm64": "4.18.0", 1195 | "@rollup/rollup-darwin-x64": "4.18.0", 1196 | "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", 1197 | "@rollup/rollup-linux-arm-musleabihf": "4.18.0", 1198 | "@rollup/rollup-linux-arm64-gnu": "4.18.0", 1199 | "@rollup/rollup-linux-arm64-musl": "4.18.0", 1200 | "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", 1201 | "@rollup/rollup-linux-riscv64-gnu": "4.18.0", 1202 | "@rollup/rollup-linux-s390x-gnu": "4.18.0", 1203 | "@rollup/rollup-linux-x64-gnu": "4.18.0", 1204 | "@rollup/rollup-linux-x64-musl": "4.18.0", 1205 | "@rollup/rollup-win32-arm64-msvc": "4.18.0", 1206 | "@rollup/rollup-win32-ia32-msvc": "4.18.0", 1207 | "@rollup/rollup-win32-x64-msvc": "4.18.0", 1208 | "fsevents": "~2.3.2" 1209 | } 1210 | }, 1211 | "node_modules/rollup-plugin-typescript2": { 1212 | "version": "0.36.0", 1213 | "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.36.0.tgz", 1214 | "integrity": "sha512-NB2CSQDxSe9+Oe2ahZbf+B4bh7pHwjV5L+RSYpCu7Q5ROuN94F9b6ioWwKfz3ueL3KTtmX4o2MUH2cgHDIEUsw==", 1215 | "dev": true, 1216 | "license": "MIT", 1217 | "dependencies": { 1218 | "@rollup/pluginutils": "^4.1.2", 1219 | "find-cache-dir": "^3.3.2", 1220 | "fs-extra": "^10.0.0", 1221 | "semver": "^7.5.4", 1222 | "tslib": "^2.6.2" 1223 | }, 1224 | "peerDependencies": { 1225 | "rollup": ">=1.26.3", 1226 | "typescript": ">=2.4.0" 1227 | } 1228 | }, 1229 | "node_modules/semver": { 1230 | "version": "7.6.2", 1231 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", 1232 | "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", 1233 | "dev": true, 1234 | "license": "ISC", 1235 | "bin": { 1236 | "semver": "bin/semver.js" 1237 | }, 1238 | "engines": { 1239 | "node": ">=10" 1240 | } 1241 | }, 1242 | "node_modules/shiki": { 1243 | "version": "0.14.7", 1244 | "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", 1245 | "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", 1246 | "dev": true, 1247 | "license": "MIT", 1248 | "dependencies": { 1249 | "ansi-sequence-parser": "^1.1.0", 1250 | "jsonc-parser": "^3.2.0", 1251 | "vscode-oniguruma": "^1.7.0", 1252 | "vscode-textmate": "^8.0.0" 1253 | } 1254 | }, 1255 | "node_modules/tinybench": { 1256 | "version": "2.8.0", 1257 | "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", 1258 | "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", 1259 | "dev": true, 1260 | "license": "MIT" 1261 | }, 1262 | "node_modules/tslib": { 1263 | "version": "2.6.3", 1264 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", 1265 | "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", 1266 | "dev": true, 1267 | "license": "0BSD" 1268 | }, 1269 | "node_modules/tsx": { 1270 | "version": "4.15.5", 1271 | "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.15.5.tgz", 1272 | "integrity": "sha512-iKi8jQ2VBmZ2kU/FkGkL2OSHBHsazsUzsdC/W/RwhKIEsIoZ1alCclZHP5jGfNHEaEWUJFM1GquzCf+4db3b0w==", 1273 | "dev": true, 1274 | "license": "MIT", 1275 | "dependencies": { 1276 | "esbuild": "~0.21.4", 1277 | "get-tsconfig": "^4.7.5" 1278 | }, 1279 | "bin": { 1280 | "tsx": "dist/cli.mjs" 1281 | }, 1282 | "engines": { 1283 | "node": ">=18.0.0" 1284 | }, 1285 | "optionalDependencies": { 1286 | "fsevents": "~2.3.3" 1287 | } 1288 | }, 1289 | "node_modules/typedoc": { 1290 | "version": "0.25.13", 1291 | "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.13.tgz", 1292 | "integrity": "sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ==", 1293 | "dev": true, 1294 | "license": "Apache-2.0", 1295 | "dependencies": { 1296 | "lunr": "^2.3.9", 1297 | "marked": "^4.3.0", 1298 | "minimatch": "^9.0.3", 1299 | "shiki": "^0.14.7" 1300 | }, 1301 | "bin": { 1302 | "typedoc": "bin/typedoc" 1303 | }, 1304 | "engines": { 1305 | "node": ">= 16" 1306 | }, 1307 | "peerDependencies": { 1308 | "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x" 1309 | } 1310 | }, 1311 | "node_modules/typedoc-plugin-markdown": { 1312 | "version": "4.0.3", 1313 | "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.0.3.tgz", 1314 | "integrity": "sha512-0tZbeVGGCd4+lpoIX+yHWgUfyaLZCQCgJOpuVdTtOtD3+jKaedJ4sl/tkNaYBPeWVKiyDkSHfGuHkq53jlzIFg==", 1315 | "dev": true, 1316 | "license": "MIT", 1317 | "peerDependencies": { 1318 | "typedoc": "0.25.x" 1319 | } 1320 | }, 1321 | "node_modules/typescript": { 1322 | "version": "5.4.5", 1323 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", 1324 | "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", 1325 | "dev": true, 1326 | "license": "Apache-2.0", 1327 | "bin": { 1328 | "tsc": "bin/tsc", 1329 | "tsserver": "bin/tsserver" 1330 | }, 1331 | "engines": { 1332 | "node": ">=14.17" 1333 | } 1334 | }, 1335 | "node_modules/undici-types": { 1336 | "version": "5.26.5", 1337 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 1338 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 1339 | "dev": true, 1340 | "license": "MIT" 1341 | }, 1342 | "node_modules/universalify": { 1343 | "version": "2.0.1", 1344 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", 1345 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", 1346 | "dev": true, 1347 | "license": "MIT", 1348 | "engines": { 1349 | "node": ">= 10.0.0" 1350 | } 1351 | }, 1352 | "node_modules/vscode-oniguruma": { 1353 | "version": "1.7.0", 1354 | "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", 1355 | "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", 1356 | "dev": true, 1357 | "license": "MIT" 1358 | }, 1359 | "node_modules/vscode-textmate": { 1360 | "version": "8.0.0", 1361 | "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", 1362 | "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", 1363 | "dev": true, 1364 | "license": "MIT" 1365 | } 1366 | } 1367 | } 1368 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "middleware-io", 3 | "version": "2.8.1", 4 | "description": "Modern middleware with promises and status", 5 | "license": "MIT", 6 | "author": { 7 | "name": "Vladlen (Negezor)", 8 | "email": "negezor@gmail.com" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/negezor/middleware-io.git" 13 | }, 14 | "homepage": "https://github.com/negezor/middleware-io#readme", 15 | "bugs": "https://github.com/negezor/middleware-io/issues", 16 | "keywords": [ 17 | "typescript", 18 | "middleware", 19 | "compose", 20 | "ware", 21 | "promise", 22 | "async", 23 | "await", 24 | "modern", 25 | "es2015", 26 | "es6", 27 | "es7", 28 | "cjs", 29 | "esm", 30 | "js" 31 | ], 32 | "files": [ 33 | "lib" 34 | ], 35 | "main": "./lib/index.js", 36 | "types": "./lib/index.d.ts", 37 | "exports": { 38 | ".": { 39 | "types": "./lib/index.d.ts", 40 | "import": "./lib/index.mjs", 41 | "require": "./lib/index.js" 42 | } 43 | }, 44 | "sideEffects": false, 45 | "engines": { 46 | "node": ">=12.0.0" 47 | }, 48 | "devDependencies": { 49 | "@biomejs/biome": "^1.8.1", 50 | "@types/node": "^20.14.2", 51 | "rollup": "^4.18.0", 52 | "rollup-plugin-typescript2": "^0.36.0", 53 | "tinybench": "^2.8.0", 54 | "tsx": "^4.15.5", 55 | "typedoc": "^0.25.13", 56 | "typedoc-plugin-markdown": "^4.0.3", 57 | "typescript": "^5.4.5" 58 | }, 59 | "scripts": { 60 | "prepare": "npm run rollup:build && npm run test", 61 | "build": "npm run rollup:build", 62 | "watch": "npm run rollup:watch", 63 | "clean": "rm -rf lib", 64 | "rollup:build": "NODE_ENV=production rollup --bundleConfigAsCjs -c rollup.config.js", 65 | "rollup:watch": "npm run rollup:build -- --watch", 66 | "test": "npm run test:node && npm run lint", 67 | "test:bench": "node --import tsx test/benchmark.bench.ts", 68 | "test:node": "node --import tsx --test test/*.test.ts", 69 | "lint": "npm run lint:biome", 70 | "lint:biome": "biome lint --apply ./src", 71 | "docs:generate": "typedoc --plugin typedoc-plugin-markdown --out docs/api-reference --excludeExternals --readme none src" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import typescript from 'rollup-plugin-typescript2'; 2 | 3 | import { tmpdir } from 'os'; 4 | import { builtinModules } from 'module'; 5 | import { join as pathJoin } from 'path'; 6 | 7 | import pkg from './package.json'; 8 | 9 | const cacheRoot = pathJoin(tmpdir(), '.rpt2_cache'); 10 | 11 | const CORE_MODULE_RE = /(^_|\/)/; 12 | const coreModules = builtinModules.filter(name => ( 13 | !CORE_MODULE_RE.test(name) 14 | )); 15 | 16 | const src = pathJoin(__dirname, 'src'); 17 | const lib = pathJoin(__dirname, 'lib'); 18 | 19 | export default { 20 | input: pathJoin(src, 'index.ts'), 21 | plugins: [ 22 | typescript({ 23 | cacheRoot, 24 | 25 | declarationDir: lib, 26 | 27 | tsconfigOverride: { 28 | outDir: lib, 29 | rootDir: src, 30 | include: [src] 31 | } 32 | }) 33 | ], 34 | external: [ 35 | ...Object.keys(pkg.dependencies || {}), 36 | ...Object.keys(pkg.peerDependencies || {}), 37 | ...coreModules 38 | ], 39 | output: [ 40 | { 41 | file: pathJoin(lib, 'index.js'), 42 | format: 'cjs', 43 | exports: 'named' 44 | }, 45 | { 46 | file: pathJoin(lib, 'index.mjs'), 47 | format: 'esm' 48 | } 49 | ] 50 | }; 51 | -------------------------------------------------------------------------------- /src/compose.ts: -------------------------------------------------------------------------------- 1 | import type { Middleware, MiddlewareReturn, NextMiddleware, NextMiddlewareReturn } from './types'; 2 | 3 | import { assertMiddlewares } from './helpers'; 4 | 5 | /** 6 | * Compose an array of middleware handlers into a single handler 7 | * 8 | * @param middlewares - The array of middleware 9 | * 10 | * @returns Composed middleware 11 | */ 12 | export function compose(middlewares: Middleware[]): Middleware { 13 | assertMiddlewares(middlewares); 14 | 15 | return (context: T, next?: NextMiddleware): Promise => { 16 | let lastIndex = -1; 17 | 18 | const nextDispatch = (index: number): Promise => { 19 | if (index <= lastIndex) { 20 | return Promise.reject(new Error('next() called multiple times')); 21 | } 22 | 23 | lastIndex = index; 24 | 25 | const middleware = middlewares.length !== index ? middlewares[index] : next; 26 | 27 | if (!middleware) { 28 | return Promise.resolve(); 29 | } 30 | 31 | try { 32 | return Promise.resolve( 33 | middleware(context, (): Promise => nextDispatch(index + 1)), 34 | ); 35 | } catch (error) { 36 | return Promise.reject(error); 37 | } 38 | }; 39 | 40 | return nextDispatch(0); 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /src/composer.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | BranchMiddlewareCondition, 3 | CaughtMiddlewareHandler, 4 | LazyMiddlewareFactory, 5 | Middleware, 6 | UnknownObject, 7 | } from './types'; 8 | 9 | import { compose } from './compose'; 10 | import { 11 | getAfterMiddleware, 12 | getBeforeMiddleware, 13 | getBranchMiddleware, 14 | getCaughtMiddleware, 15 | getConcurrencyMiddleware, 16 | getEnforceMiddleware, 17 | getFilterMiddleware, 18 | getForkMiddleware, 19 | getLazyMiddleware, 20 | getOptionalMiddleware, 21 | getTapMiddleware, 22 | } from './snippets'; 23 | 24 | import { assertMiddleware } from './helpers'; 25 | 26 | /** 27 | * A simple middleware compose builder 28 | */ 29 | export class Composer { 30 | protected middlewares: Middleware[] = []; 31 | 32 | /** 33 | * Invokes a new instance of the Composer class 34 | */ 35 | public static builder(): Composer { 36 | return new Composer(); 37 | } 38 | 39 | /** 40 | * The number of middleware installed in Composer 41 | */ 42 | public get length(): number { 43 | return this.middlewares.length; 44 | } 45 | 46 | /** 47 | * Clones a composer object 48 | */ 49 | public clone(): Composer { 50 | const composer = new Composer(); 51 | 52 | composer.middlewares = [...this.middlewares]; 53 | 54 | return composer; 55 | } 56 | 57 | /** 58 | * Adds middleware to the chain 59 | */ 60 | public use(middleware: Middleware): Composer { 61 | assertMiddleware(middleware); 62 | 63 | this.middlewares.push(middleware); 64 | 65 | return this; 66 | } 67 | 68 | /** 69 | * Lazily asynchronously gets middleware 70 | */ 71 | public lazy(factory: LazyMiddlewareFactory): Composer { 72 | return this.use(getLazyMiddleware(factory)); 73 | } 74 | 75 | /** 76 | * Runs the middleware and force call `next()` 77 | */ 78 | public tap(middleware: Middleware): Composer { 79 | return this.use(getTapMiddleware(middleware)); 80 | } 81 | 82 | /** 83 | * Runs the middleware at the next event loop and force call `next()` 84 | */ 85 | public fork(middleware: Middleware): Composer { 86 | return this.use(getForkMiddleware(middleware)); 87 | } 88 | 89 | /** 90 | * By condition splits the middleware 91 | */ 92 | public branch( 93 | condition: BranchMiddlewareCondition, 94 | 95 | trueMiddleware: Middleware, 96 | falseMiddleware: Middleware, 97 | ): Composer { 98 | return this.use( 99 | getBranchMiddleware( 100 | condition, 101 | 102 | trueMiddleware, 103 | falseMiddleware, 104 | ), 105 | ); 106 | } 107 | 108 | /** 109 | * Conditionally runs optional middleware or skips middleware 110 | */ 111 | public optional( 112 | condition: BranchMiddlewareCondition, 113 | optionalMiddleware: Middleware, 114 | ): Composer { 115 | return this.use(getOptionalMiddleware(condition, optionalMiddleware)); 116 | } 117 | 118 | /** 119 | * Conditionally runs middleware or stops the chain 120 | */ 121 | public filter( 122 | condition: BranchMiddlewareCondition, 123 | filterMiddleware: Middleware, 124 | ): Composer { 125 | return this.use(getFilterMiddleware(condition, filterMiddleware)); 126 | } 127 | 128 | /** 129 | * Runs the second middleware before the main 130 | */ 131 | public before( 132 | beforeMiddleware: Middleware, 133 | middleware: Middleware, 134 | ): Composer { 135 | return this.use(getBeforeMiddleware(middleware, beforeMiddleware)); 136 | } 137 | 138 | /** 139 | * Runs the second middleware after the main 140 | */ 141 | public after( 142 | middleware: Middleware, 143 | afterMiddleware: Middleware, 144 | ): Composer { 145 | return this.use(getAfterMiddleware(middleware, afterMiddleware)); 146 | } 147 | 148 | /** 149 | * Runs middleware before and after the main 150 | */ 151 | public enforce( 152 | beforeMiddleware: Middleware, 153 | middleware: Middleware, 154 | afterMiddleware: Middleware, 155 | ): Composer { 156 | return this.use(getEnforceMiddleware(middleware, beforeMiddleware, afterMiddleware)); 157 | } 158 | 159 | /** 160 | * Catches errors in the middleware chain 161 | */ 162 | public caught(errorHandler: CaughtMiddlewareHandler): Composer { 163 | return this.use(getCaughtMiddleware(errorHandler)); 164 | } 165 | 166 | /** 167 | * Concurrently launches middleware, 168 | * the chain will continue if `next()` is called in all middlewares 169 | */ 170 | public concurrency(middlewares: Middleware[]): Composer { 171 | return this.use(getConcurrencyMiddleware(middlewares)); 172 | } 173 | 174 | /** 175 | * Compose middleware handlers into a single handler 176 | */ 177 | public compose(): Middleware { 178 | return compose([...this.middlewares]); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/helpers.ts: -------------------------------------------------------------------------------- 1 | import type { Middleware, NextMiddleware } from './types'; 2 | 3 | export function assertMiddleware(middleware: unknown): asserts middleware is Middleware { 4 | if (typeof middleware !== 'function') { 5 | throw new TypeError('Middleware must be composed of function!'); 6 | } 7 | } 8 | 9 | export function assertMiddlewares(middlewares: unknown[]): asserts middlewares is Middleware[] { 10 | middlewares.forEach(assertMiddleware); 11 | } 12 | 13 | export const wrapMiddlewareNextCall = async (context: T, middleware: Middleware): Promise => { 14 | let called = false; 15 | 16 | await middleware(context, async (): Promise => { 17 | if (called) { 18 | throw new Error('next() called multiple times'); 19 | } 20 | 21 | called = true; 22 | }); 23 | 24 | return called; 25 | }; 26 | 27 | /** 28 | * Noop for call `next()` in middleware 29 | */ 30 | export const noopNext: NextMiddleware = (): Promise => Promise.resolve(); 31 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { compose } from './compose'; 2 | 3 | export * from './types'; 4 | export * from './snippets'; 5 | 6 | export { noopNext } from './helpers'; 7 | 8 | export { Composer } from './composer'; 9 | 10 | export { compose }; 11 | 12 | export default compose; 13 | -------------------------------------------------------------------------------- /src/snippets.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | BranchMiddlewareCondition, 3 | CaughtMiddlewareHandler, 4 | LazyMiddlewareFactory, 5 | Middleware, 6 | MiddlewareReturn, 7 | NextMiddleware, 8 | NextMiddlewareReturn, 9 | } from './types'; 10 | 11 | import { noopNext, wrapMiddlewareNextCall } from './helpers'; 12 | 13 | /** 14 | * Call `next()` in middleware 15 | */ 16 | export const skipMiddleware = (context: T, next: NextMiddleware): Promise => next(); 17 | 18 | /** 19 | * Does not call `next()` in middleware 20 | */ 21 | export const stopMiddleware = (context: T, next: NextMiddleware): Promise => Promise.resolve(); 22 | 23 | /** 24 | * Lazily asynchronously gets middleware 25 | * 26 | * Example: 27 | * 28 | * ```ts 29 | * getLazyMiddleware(async (context) => { 30 | * const route = await getSomeRoute(context.path) // Promise; 31 | * 32 | * return route; 33 | * }); 34 | * ``` 35 | */ 36 | export const getLazyMiddleware = (factory: LazyMiddlewareFactory): Middleware => { 37 | let middleware: Middleware | undefined; 38 | 39 | return async (context: T, next: NextMiddleware): Promise => { 40 | if (middleware === undefined) { 41 | middleware = await factory(context); 42 | } 43 | 44 | return middleware(context, next); 45 | }; 46 | }; 47 | 48 | /** 49 | * Runs the middleware and force call `next()` 50 | * 51 | * Example: 52 | * 53 | * ```ts 54 | * getTapMiddleware((context) => { 55 | * console.log('Context', context); 56 | * }); 57 | * ``` 58 | */ 59 | export const getTapMiddleware = 60 | (middleware: Middleware): Middleware => 61 | async (context: T, next: NextMiddleware): Promise => { 62 | await middleware(context, noopNext); 63 | 64 | return next(); 65 | }; 66 | 67 | /** 68 | * Runs the middleware at the next event loop and force call `next()` 69 | * 70 | * Example: 71 | * 72 | * ```ts 73 | * getForkMiddleware((context) => { 74 | * statisticsMiddlewares(context).catch(console.error); 75 | * }); 76 | * ``` 77 | */ 78 | export const getForkMiddleware = 79 | (middleware: Middleware): Middleware => 80 | (context: T, next: NextMiddleware): Promise => { 81 | setImmediate(middleware, context, noopNext); 82 | 83 | return next(); 84 | }; 85 | 86 | /** 87 | * By condition splits the middleware 88 | * 89 | * Example: 90 | * 91 | * ```ts 92 | * getBranchMiddleware( 93 | * async context => context.is('Content-Type', 'json'), 94 | * myBodyParser.json(), 95 | * myBodyParser.urlencoded() 96 | * ); 97 | * ``` 98 | * 99 | * Static condition 100 | * 101 | * ```ts 102 | * getBranchMiddleware( 103 | * process.env.NODE_ENV === 'production', 104 | * logger.loggedContextToFile(), 105 | * logger.loggedContextToConsole() 106 | * ); 107 | * ``` 108 | */ 109 | export const getBranchMiddleware = ( 110 | condition: BranchMiddlewareCondition, 111 | 112 | trueMiddleware: Middleware, 113 | falseMiddleware: Middleware, 114 | ): Middleware => { 115 | if (typeof condition !== 'function') { 116 | return condition ? trueMiddleware : falseMiddleware; 117 | } 118 | 119 | return async (context: T, next: NextMiddleware): Promise => 120 | (await condition(context)) ? trueMiddleware(context, next) : falseMiddleware(context, next); 121 | }; 122 | 123 | /** 124 | * Conditionally runs optional middleware or skips middleware 125 | * 126 | * Example: 127 | * 128 | * ```ts 129 | * getOptionalMiddleware( 130 | * context => context.user.isAdmin, 131 | * addFieldsForAdmin 132 | * ); 133 | * ``` 134 | */ 135 | export const getOptionalMiddleware = ( 136 | condition: BranchMiddlewareCondition, 137 | optionalMiddleware: Middleware, 138 | ): Middleware => getBranchMiddleware(condition, optionalMiddleware, skipMiddleware); 139 | 140 | /** 141 | * Conditionally runs middleware or stops the chain 142 | * 143 | * Example: 144 | * 145 | * ```ts 146 | * getFilterMiddleware( 147 | * context => context.authorized, 148 | * middlewareForAuthorized 149 | * ); 150 | * ``` 151 | */ 152 | export const getFilterMiddleware = ( 153 | condition: BranchMiddlewareCondition, 154 | filterMiddleware: Middleware, 155 | ): Middleware => getBranchMiddleware(condition, filterMiddleware, stopMiddleware); 156 | 157 | /** 158 | * Runs the second middleware before the main 159 | * 160 | * Example: 161 | * 162 | * ```ts 163 | * getBeforeMiddleware( 164 | * myMockMiddleware, 165 | * ouputUserData 166 | * ); 167 | * ``` 168 | */ 169 | export const getBeforeMiddleware = 170 | (beforeMiddleware: Middleware, middleware: Middleware): Middleware => 171 | async (context: T, next: NextMiddleware): Promise => { 172 | const called = await wrapMiddlewareNextCall(context, beforeMiddleware); 173 | 174 | if (called) { 175 | return middleware(context, next); 176 | } 177 | }; 178 | 179 | /** 180 | * Runs the second middleware after the main 181 | * 182 | * Example: 183 | * 184 | * ```ts 185 | * getAfterMiddleware( 186 | * sendSecureData, 187 | * clearSecurityData 188 | * ); 189 | * ``` 190 | */ 191 | export const getAfterMiddleware = 192 | (middleware: Middleware, afterMiddleware: Middleware): Middleware => 193 | async (context: T, next: NextMiddleware): Promise => { 194 | const called = await wrapMiddlewareNextCall(context, middleware); 195 | 196 | if (called) { 197 | return afterMiddleware(context, next); 198 | } 199 | }; 200 | 201 | /** 202 | * Runs middleware before and after the main 203 | * 204 | * Example: 205 | * 206 | * ```ts 207 | * getEnforceMiddleware( 208 | * prepareData, 209 | * sendData, 210 | * clearData 211 | * ); 212 | */ 213 | export const getEnforceMiddleware = 214 | (beforeMiddleware: Middleware, middleware: Middleware, afterMiddleware: Middleware): Middleware => 215 | async (context: T, next: NextMiddleware): Promise => { 216 | const beforeCalled = await wrapMiddlewareNextCall(context, beforeMiddleware); 217 | 218 | if (!beforeCalled) { 219 | return; 220 | } 221 | 222 | const middlewareCalled = await wrapMiddlewareNextCall(context, middleware); 223 | 224 | if (!middlewareCalled) { 225 | return; 226 | } 227 | 228 | return afterMiddleware(context, next); 229 | }; 230 | 231 | /** 232 | * Catches errors in the middleware chain 233 | * 234 | * Example: 235 | * ```js 236 | * getCaughtMiddleware((context, error) => { 237 | * if (error instanceof NetworkError) { 238 | * return context.send('Sorry, network issues 😔'); 239 | * } 240 | * 241 | * throw error; 242 | * }) 243 | * ``` 244 | * 245 | * Without a snippet, it would look like this: 246 | * 247 | * ```js 248 | * async (context, next) => { 249 | * try { 250 | * await next(); 251 | * } catch (error) { 252 | * if (error instanceof NetworkError) { 253 | * return context.send('Sorry, network issues 😔'); 254 | * } 255 | * 256 | * throw error; 257 | * } 258 | * }; 259 | * ``` 260 | */ 261 | export const getCaughtMiddleware = 262 | (errorHandler: CaughtMiddlewareHandler): Middleware => 263 | async (context: T, next: NextMiddleware): Promise => { 264 | try { 265 | await next(); 266 | } catch (error) { 267 | return errorHandler(context, error as Error); 268 | } 269 | }; 270 | 271 | /** 272 | * Concurrently launches middleware, 273 | * the chain will continue if `next()` is called in all middlewares 274 | * 275 | * **Warning: Error interrupts all others** 276 | * 277 | * Example: 278 | * 279 | * ```ts 280 | * getConcurrencyMiddleware( 281 | * initializeUser, 282 | * initializeSession, 283 | * initializeDatabase 284 | * ); 285 | * ``` 286 | */ 287 | export const getConcurrencyMiddleware = 288 | (middlewares: Middleware[]): Middleware => 289 | async (context: T, next: NextMiddleware): Promise => { 290 | const concurrencies = await Promise.all( 291 | middlewares.map((middleware): Promise => wrapMiddlewareNextCall(context, middleware)), 292 | ); 293 | 294 | if (concurrencies.every(Boolean)) { 295 | return next(); 296 | } 297 | }; 298 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Returns the type of response middleware 3 | */ 4 | export type NextMiddlewareReturn = unknown; 5 | 6 | /** 7 | * Call the next middleware from the chain 8 | */ 9 | export type NextMiddleware = () => Promise; 10 | 11 | /** 12 | * Returns the type of response middleware 13 | */ 14 | export type MiddlewareReturn = unknown; 15 | 16 | /** 17 | * Instead of object 18 | */ 19 | export type UnknownObject = Record; 20 | 21 | /** 22 | * Basic middleware 23 | */ 24 | export type Middleware = (context: T, next: NextMiddleware) => MiddlewareReturn; 25 | 26 | /** 27 | * Asynchronous function for branch condition 28 | */ 29 | export type BranchMiddlewareConditionFunction = (context: T) => Promise | boolean; 30 | 31 | /** 32 | * Possible types for branch condition 33 | */ 34 | export type BranchMiddlewareCondition = BranchMiddlewareConditionFunction | boolean; 35 | 36 | /** 37 | * Asynchronous factory to create middleware 38 | */ 39 | export type LazyMiddlewareFactory = (context: T) => Promise> | Middleware; 40 | 41 | /** 42 | * Handler for catching errors in middleware chains 43 | */ 44 | export type CaughtMiddlewareHandler = (context: T, error: Error) => MiddlewareReturn; 45 | -------------------------------------------------------------------------------- /test/benchmark.bench.ts: -------------------------------------------------------------------------------- 1 | import { Bench, type Fn } from 'tinybench'; 2 | 3 | import { type Middleware, compose, noopNext } from '..'; 4 | 5 | const numberFormat = (number: number) => ( 6 | new Intl.NumberFormat('en-US').format(number) 7 | ); 8 | 9 | const makeSuite = ({ name }: { name: string }) => { 10 | const suite = new Bench({ 11 | iterations: 30, 12 | }); 13 | 14 | suite.addEventListener('start', () => { 15 | process.stdout.write(`${name}\n\n`.padStart(name.length + 8)); 16 | }); 17 | 18 | suite.addEventListener('cycle', ({ task }) => { 19 | // biome-ignore lint/style/noNonNullAssertion: after cycle task.result always exist 20 | const { hz, rme } = task.result!; 21 | const text = `${task.name} » ${numberFormat(Number(hz.toFixed(hz < 100 ? 2 : 0)))} op/s ±${rme.toFixed(2)}%\n`; 22 | 23 | process.stdout.clearLine(0); 24 | process.stdout.cursorTo(0); 25 | process.stdout.write(text.padStart(text.length + 8)); 26 | }) 27 | 28 | 29 | suite.addEventListener('complete', () => { 30 | process.stdout.write('\n'); 31 | }); 32 | 33 | return { 34 | add: (testName: string, options: { fn: Fn }) => { 35 | suite.add(testName, options.fn, { 36 | ...options, 37 | 38 | beforeAll() { 39 | const text = `wait » ${testName}`; 40 | 41 | process.stdout.write(text.padStart(testName.length + 17)); 42 | }, 43 | }); 44 | }, 45 | run: suite.run.bind(suite), 46 | }; 47 | }; 48 | 49 | const composeSuite = makeSuite({ 50 | name: 'Compose', 51 | }); 52 | 53 | for (let exp = 0; exp <= 10; exp += 1) { 54 | const count = 2 ** exp; 55 | 56 | const logic = async () => true; 57 | 58 | const fn: Middleware = async (ctx, next) => { 59 | await logic(); 60 | await next(); 61 | await logic(); 62 | }; 63 | 64 | const middlewares = Array(count).fill(fn); 65 | 66 | const middleware = compose(middlewares); 67 | 68 | composeSuite.add(`(fn * ${count})`, { 69 | fn: () => ( 70 | middleware({}, noopNext) 71 | ), 72 | }); 73 | } 74 | 75 | (async () => { 76 | for (const benchmark of [composeSuite]) { 77 | await benchmark.run(); 78 | } 79 | })(); 80 | -------------------------------------------------------------------------------- /test/composer.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'node:test'; 2 | import { match, ok, deepStrictEqual, strictEqual } from 'node:assert'; 3 | 4 | import { Composer, noopNext } from '..'; 5 | 6 | /** 7 | * Delay N-ms 8 | * 9 | * @param {Number} delayed 10 | * 11 | * @return {Promise} 12 | */ 13 | const delay = (delayed: number): Promise => ( 14 | new Promise((resolve): void => { 15 | setTimeout(resolve, delayed); 16 | }) 17 | ); 18 | 19 | describe('Composer', (): void => { 20 | it('should work', async (): Promise => { 21 | const out: number[] = []; 22 | 23 | const composer = new Composer(); 24 | 25 | composer.use(async (ctx, next): Promise => { 26 | out.push(1); 27 | 28 | await delay(1); 29 | await next(); 30 | await delay(1); 31 | 32 | out.push(6); 33 | }); 34 | 35 | composer.use(async (ctx, next): Promise => { 36 | out.push(2); 37 | 38 | await delay(1); 39 | await next(); 40 | await delay(1); 41 | 42 | out.push(5); 43 | }); 44 | 45 | composer.use(async (ctx, next): Promise => { 46 | out.push(3); 47 | 48 | await delay(1); 49 | await next(); 50 | await delay(1); 51 | 52 | out.push(4); 53 | }); 54 | 55 | const middleware = composer.compose(); 56 | 57 | await middleware({}, noopNext); 58 | 59 | deepStrictEqual(out, [1, 2, 3, 4, 5, 6]); 60 | }); 61 | 62 | it('should keep the context', async (): Promise => { 63 | const context = {}; 64 | 65 | const composer = new Composer(); 66 | 67 | composer.use(async (ctx, next): Promise => { 68 | await next(); 69 | 70 | strictEqual(ctx, context); 71 | }); 72 | 73 | composer.use(async (ctx, next): Promise => { 74 | await next(); 75 | 76 | strictEqual(ctx, context); 77 | }); 78 | 79 | composer.use(async (ctx, next): Promise => { 80 | await next(); 81 | 82 | strictEqual(ctx, context); 83 | }); 84 | 85 | const middleware = composer.compose(); 86 | 87 | await middleware(context, noopNext); 88 | }); 89 | 90 | it('should work with 0 middleware', async (): Promise => { 91 | const middleware = (new Composer()).compose(); 92 | 93 | await middleware({}, noopNext); 94 | }); 95 | 96 | it('should reject on errors in middleware', async (): Promise => { 97 | const composer = new Composer>(); 98 | 99 | composer.use(async (ctx, next): Promise => { 100 | ctx.now = Date.now(); 101 | 102 | await next(); 103 | }); 104 | 105 | composer.use(async (): Promise => { 106 | throw new Error(); 107 | }); 108 | 109 | const middleware = composer.compose(); 110 | 111 | try { 112 | await middleware({}, noopNext); 113 | } catch (error) { 114 | ok(error instanceof Error); 115 | 116 | return; 117 | } 118 | 119 | throw new Error(); 120 | }); 121 | 122 | it('should only accept middleware as functions', (): void => { 123 | try { 124 | // @ts-expect-error cause test 125 | (new Composer()).use(null); 126 | 127 | throw new Error('Middleware must be composed of functions'); 128 | } catch (error) { 129 | ok(error instanceof TypeError); 130 | } 131 | }); 132 | 133 | it('composer should be cloned', async (): Promise => { 134 | type CloneContext = { 135 | baseValue?: boolean; 136 | value: 'first' | 'second' | 'default'; 137 | } 138 | 139 | const baseComposer = new Composer(); 140 | 141 | baseComposer.use((context, next) => { 142 | context.baseValue = true; 143 | 144 | return next(); 145 | }); 146 | 147 | const firstComposer = baseComposer.clone() 148 | .use((context, next) => { 149 | context.value = 'first'; 150 | 151 | return next(); 152 | }); 153 | 154 | const secondComposer = baseComposer.clone() 155 | .use((context, next) => { 156 | context.value = 'second'; 157 | 158 | return next(); 159 | }); 160 | 161 | const baseContext = { value: 'default' } as CloneContext; 162 | const firstContext = { value: 'default' } as CloneContext; 163 | const secondContext = { value: 'default' } as CloneContext; 164 | 165 | await baseComposer.compose()(baseContext, noopNext); 166 | await firstComposer.compose()(firstContext, noopNext); 167 | await secondComposer.compose()(secondContext, noopNext); 168 | 169 | deepStrictEqual(baseContext, { 170 | baseValue: true, 171 | value: 'default', 172 | }); 173 | 174 | deepStrictEqual(firstContext, { 175 | baseValue: true, 176 | value: 'first', 177 | }); 178 | 179 | deepStrictEqual(secondContext, { 180 | baseValue: true, 181 | value: 'second', 182 | }); 183 | }); 184 | 185 | it('should correctly display the number of middleware', (): void => { 186 | const composer = new Composer(); 187 | 188 | strictEqual(composer.length, 0); 189 | 190 | composer.tap(() => { }); 191 | 192 | strictEqual(composer.length, 1); 193 | 194 | composer.tap(() => { }); 195 | 196 | strictEqual(composer.length, 2); 197 | }); 198 | 199 | it('should create new instance of the Composer class', (): void => { 200 | const composer = Composer.builder<{ test: 'test' }>(); 201 | 202 | composer.use((context) => { 203 | if (context.test === 'test') { 204 | // ... 205 | } 206 | }); 207 | 208 | strictEqual(composer.length, 1); 209 | ok(composer instanceof Composer); 210 | }); 211 | 212 | it('should throw if next() is called multiple times', async (): Promise => { 213 | const composer = new Composer(); 214 | 215 | composer.use(async (ctx, next): Promise => { 216 | await next(); 217 | }); 218 | 219 | composer.use(async (ctx, next): Promise => { 220 | await next(); 221 | await next(); 222 | }); 223 | 224 | composer.use(async (ctx, next): Promise => { 225 | await next(); 226 | }); 227 | 228 | const middleware = composer.compose(); 229 | 230 | try { 231 | await middleware({}, noopNext); 232 | // @ts-expect-error cause test 233 | } catch ({ message }) { 234 | match(message, /multiple times/); 235 | 236 | return; 237 | } 238 | 239 | throw new Error('next() called multiple times'); 240 | }); 241 | }); 242 | -------------------------------------------------------------------------------- /test/middleware.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'node:test'; 2 | import { deepStrictEqual, match, ok, strictEqual } from 'node:assert'; 3 | 4 | import { compose, noopNext } from '..'; 5 | 6 | /** 7 | * Delay N-ms 8 | * 9 | * @param {Number} delayed 10 | * 11 | * @return {Promise} 12 | */ 13 | const delay = (delayed: number): Promise => ( 14 | new Promise((resolve): void => { 15 | setTimeout(resolve, delayed); 16 | }) 17 | ); 18 | 19 | describe('compose', (): void => { 20 | it('should work', async (): Promise => { 21 | const out: number[] = []; 22 | 23 | const middleware = compose([ 24 | async (ctx, next): Promise => { 25 | out.push(1); 26 | 27 | await delay(1); 28 | await next(); 29 | await delay(1); 30 | 31 | out.push(6); 32 | }, 33 | async (ctx, next): Promise => { 34 | out.push(2); 35 | 36 | await delay(1); 37 | await next(); 38 | await delay(1); 39 | 40 | out.push(5); 41 | }, 42 | async (ctx, next): Promise => { 43 | out.push(3); 44 | 45 | await delay(1); 46 | await next(); 47 | await delay(1); 48 | 49 | out.push(4); 50 | }, 51 | ]); 52 | 53 | await middleware(out, noopNext); 54 | 55 | deepStrictEqual(out, [1, 2, 3, 4, 5, 6]); 56 | }); 57 | 58 | it('should keep the context', async (): Promise => { 59 | const context = {}; 60 | 61 | const middleware = compose([ 62 | async (ctx, next): Promise => { 63 | await next(); 64 | 65 | strictEqual(ctx, context); 66 | }, 67 | async (ctx, next): Promise => { 68 | await next(); 69 | 70 | strictEqual(ctx, context); 71 | }, 72 | async (ctx, next): Promise => { 73 | await next(); 74 | 75 | strictEqual(ctx, context); 76 | }, 77 | ]); 78 | 79 | await middleware(context, noopNext); 80 | }); 81 | 82 | it('should work with 0 middleware', async (): Promise => { 83 | const middleware = compose([]); 84 | 85 | await middleware({}, noopNext); 86 | }); 87 | 88 | it('should reject on errors in middleware', async (): Promise => { 89 | const middleware = compose>([ 90 | async (ctx, next): Promise => { 91 | ctx.now = Date.now(); 92 | 93 | await next(); 94 | }, 95 | async (): Promise => { 96 | throw new Error(); 97 | }, 98 | ]); 99 | 100 | try { 101 | await middleware({}, noopNext); 102 | } catch (error) { 103 | ok(error instanceof Error); 104 | 105 | return; 106 | } 107 | 108 | throw new Error(); 109 | }); 110 | 111 | it('should only accept middleware as functions', (): void => { 112 | try { 113 | // @ts-expect-error cause test 114 | compose([null]); 115 | 116 | throw new Error('Middleware must be composed of functions'); 117 | } catch (error) { 118 | ok(error instanceof TypeError); 119 | } 120 | }); 121 | 122 | it('should throw if next() is called multiple times', async (): Promise => { 123 | const middleware = compose([ 124 | async (ctx, next): Promise => { 125 | await next(); 126 | }, 127 | async (ctx, next): Promise => { 128 | await next(); 129 | await next(); 130 | }, 131 | async (ctx, next): Promise => { 132 | await next(); 133 | }, 134 | ]); 135 | 136 | try { 137 | await middleware({}, noopNext); 138 | // @ts-expect-error cause error 139 | } catch ({ message }) { 140 | match(message, /multiple times/); 141 | 142 | return; 143 | } 144 | 145 | throw new Error('next() called multiple times'); 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /test/snippets.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, mock } from 'node:test'; 2 | import { deepStrictEqual, ok, strictEqual } from 'node:assert'; 3 | 4 | import { 5 | Middleware, 6 | NextMiddleware, 7 | 8 | noopNext, 9 | getLazyMiddleware, 10 | getTapMiddleware, 11 | getForkMiddleware, 12 | getBranchMiddleware, 13 | getOptionalMiddleware, 14 | getBeforeMiddleware, 15 | getAfterMiddleware, 16 | getEnforceMiddleware, 17 | getConcurrencyMiddleware, 18 | getFilterMiddleware, 19 | getCaughtMiddleware, 20 | } from '..'; 21 | 22 | const makeContext = (): { shouldTrue: boolean; shouldFalse: boolean } => ({ 23 | shouldTrue: true, 24 | shouldFalse: false, 25 | }); 26 | 27 | type ContextType = ReturnType; 28 | 29 | describe('Snippets', (): void => { 30 | describe('getLazyMiddleware', (): void => { 31 | it('should work with function', async (): Promise => { 32 | const lazyContext = makeContext(); 33 | 34 | const nextMock = mock.fn(noopNext); 35 | const middlewareMock = mock.fn( 36 | (factoryContext: ContextType): Middleware => { 37 | strictEqual(factoryContext, lazyContext); 38 | 39 | return async (context: ContextType, next: NextMiddleware): Promise => { 40 | strictEqual(context, lazyContext); 41 | 42 | await next(); 43 | }; 44 | }, 45 | ); 46 | 47 | const lazyMiddleware = getLazyMiddleware(middlewareMock); 48 | 49 | await lazyMiddleware(lazyContext, nextMock); 50 | 51 | strictEqual(middlewareMock.mock.callCount(), 1); 52 | strictEqual(nextMock.mock.callCount(), 1); 53 | }); 54 | 55 | it('should factory be called once', async (): Promise => { 56 | const lazyContext = makeContext(); 57 | 58 | const nextMock = mock.fn(noopNext); 59 | const middlewareMock = mock.fn( 60 | (factoryContext: ContextType): Middleware => { 61 | ok(factoryContext === lazyContext); 62 | 63 | return async (context: ContextType, next: NextMiddleware): Promise => { 64 | ok(context === lazyContext); 65 | 66 | await next(); 67 | }; 68 | }, 69 | ); 70 | 71 | const lazyMiddleware = getLazyMiddleware(middlewareMock); 72 | 73 | const CALLED_TIMES = 10; 74 | for (let i = 0; i < CALLED_TIMES; i += 1) { 75 | await lazyMiddleware(lazyContext, nextMock); 76 | } 77 | 78 | strictEqual(middlewareMock.mock.callCount(), 1); 79 | strictEqual(nextMock.mock.callCount(), CALLED_TIMES); 80 | }); 81 | }); 82 | 83 | describe('getTapMiddleware', (): void => { 84 | it('should runs with force next()', async (): Promise => { 85 | const tapContext = makeContext(); 86 | 87 | const nextMock = mock.fn(noopNext); 88 | const middlewareMock = mock.fn( 89 | async (context: ContextType): Promise => { 90 | ok(context === tapContext); 91 | }, 92 | ); 93 | 94 | const tapMiddleware = getTapMiddleware(middlewareMock); 95 | 96 | await tapMiddleware(tapContext, nextMock); 97 | 98 | strictEqual(middlewareMock.mock.callCount(), 1); 99 | strictEqual(nextMock.mock.callCount(), 1); 100 | }); 101 | }); 102 | 103 | describe('getForkMiddleware', (): void => { 104 | it('should runs with force next()', async (): Promise => { 105 | const forkContext = makeContext(); 106 | 107 | const nextMock = mock.fn(noopNext); 108 | const middlewareMock = mock.fn( 109 | async (context: ContextType, next: NextMiddleware): Promise => { 110 | ok(context === forkContext); 111 | 112 | await next(); 113 | }, 114 | ); 115 | 116 | const forkMiddleware = getForkMiddleware(middlewareMock); 117 | 118 | await forkMiddleware(forkContext, nextMock); 119 | 120 | strictEqual(middlewareMock.mock.callCount(), 0); 121 | strictEqual(nextMock.mock.callCount(), 1); 122 | 123 | await new Promise((resolve: Function): void => { 124 | setImmediate((): void => { 125 | strictEqual(middlewareMock.mock.callCount(), 1); 126 | 127 | resolve(); 128 | }); 129 | }); 130 | }); 131 | }); 132 | 133 | describe('getBranchMiddleware', (): void => { 134 | it('should runs with static condition', async (): Promise => { 135 | const branchContext = makeContext(); 136 | 137 | const nextMock = mock.fn(noopNext); 138 | 139 | const trueMiddlewareMock = mock.fn( 140 | async (context: ContextType, next: NextMiddleware): Promise => { 141 | ok(context === branchContext); 142 | 143 | await next(); 144 | }, 145 | ); 146 | 147 | const falseMiddlewareMock = mock.fn( 148 | async (context: ContextType, next: NextMiddleware): Promise => { 149 | ok(context === branchContext); 150 | 151 | await next(); 152 | }, 153 | ); 154 | 155 | const trueMiddleware = getBranchMiddleware( 156 | true, 157 | trueMiddlewareMock, 158 | falseMiddlewareMock, 159 | ); 160 | 161 | const falseMiddleware = getBranchMiddleware( 162 | false, 163 | trueMiddlewareMock, 164 | falseMiddlewareMock, 165 | ); 166 | 167 | await trueMiddleware(branchContext, nextMock); 168 | await falseMiddleware(branchContext, nextMock); 169 | 170 | strictEqual(trueMiddlewareMock.mock.callCount(), 1); 171 | strictEqual(falseMiddlewareMock.mock.callCount(), 1); 172 | strictEqual(nextMock.mock.callCount(), 2); 173 | }); 174 | 175 | it('should runs with dynamic condition', async (): Promise => { 176 | const branchContext = makeContext(); 177 | 178 | const nextMock = mock.fn(noopNext); 179 | 180 | const trueMiddlewareMock = mock.fn( 181 | async (context: ContextType, next: NextMiddleware): Promise => { 182 | ok(context === branchContext); 183 | 184 | await next(); 185 | }, 186 | ); 187 | 188 | const falseMiddlewareMock = mock.fn( 189 | async (context: ContextType, next: NextMiddleware): Promise => { 190 | ok(context === branchContext); 191 | 192 | await next(); 193 | }, 194 | ); 195 | 196 | const trueMiddleware = getBranchMiddleware( 197 | mock.fn(() => true), 198 | trueMiddlewareMock, 199 | falseMiddlewareMock, 200 | ); 201 | 202 | const falseMiddleware = getBranchMiddleware( 203 | mock.fn(() => false), 204 | trueMiddlewareMock, 205 | falseMiddlewareMock, 206 | ); 207 | 208 | await trueMiddleware(branchContext, nextMock); 209 | await falseMiddleware(branchContext, nextMock); 210 | 211 | strictEqual(trueMiddlewareMock.mock.callCount(), 1); 212 | strictEqual(falseMiddlewareMock.mock.callCount(), 1); 213 | strictEqual(nextMock.mock.callCount(), 2); 214 | }); 215 | }); 216 | 217 | describe('getOptionalMiddleware', (): void => { 218 | it('should runs with static condition', async (): Promise => { 219 | const optionalContext = makeContext(); 220 | 221 | const nextMock = mock.fn(noopNext); 222 | 223 | const middlewareMock = mock.fn( 224 | async (context: ContextType, next: NextMiddleware): Promise => { 225 | ok(context === optionalContext); 226 | 227 | await next(); 228 | }, 229 | ); 230 | 231 | const trueMiddleware = getOptionalMiddleware( 232 | true, 233 | middlewareMock, 234 | ); 235 | 236 | const falseMiddleware = getOptionalMiddleware( 237 | false, 238 | middlewareMock, 239 | ); 240 | 241 | await trueMiddleware(optionalContext, nextMock); 242 | await falseMiddleware(optionalContext, nextMock); 243 | 244 | strictEqual(middlewareMock.mock.callCount(), 1); 245 | strictEqual(nextMock.mock.callCount(), 2); 246 | }); 247 | 248 | it('should runs with dynamic condition', async (): Promise => { 249 | const optionalContext = makeContext(); 250 | 251 | const nextMock = mock.fn(noopNext); 252 | 253 | const middlewareMock = mock.fn( 254 | async (context: ContextType, next: NextMiddleware): Promise => { 255 | ok(context === optionalContext); 256 | 257 | await next(); 258 | }, 259 | ); 260 | 261 | const trueMiddleware = getOptionalMiddleware( 262 | mock.fn(() => true), 263 | middlewareMock, 264 | ); 265 | 266 | const falseMiddleware = getOptionalMiddleware( 267 | mock.fn(() => false), 268 | middlewareMock, 269 | ); 270 | 271 | await trueMiddleware(optionalContext, nextMock); 272 | await falseMiddleware(optionalContext, nextMock); 273 | 274 | strictEqual(middlewareMock.mock.callCount(), 1); 275 | strictEqual(nextMock.mock.callCount(), 2); 276 | }); 277 | }); 278 | 279 | describe('getFilterMiddleware', (): void => { 280 | it('should runs with static condition', async (): Promise => { 281 | const filterContext = makeContext(); 282 | 283 | const nextMock = mock.fn(noopNext); 284 | 285 | const middlewareMock = mock.fn( 286 | async (context: ContextType, next: NextMiddleware): Promise => { 287 | ok(context === filterContext); 288 | 289 | await next(); 290 | }, 291 | ); 292 | 293 | const trueMiddleware = getFilterMiddleware( 294 | true, 295 | middlewareMock, 296 | ); 297 | 298 | const falseMiddleware = getFilterMiddleware( 299 | false, 300 | middlewareMock, 301 | ); 302 | 303 | await trueMiddleware(filterContext, nextMock); 304 | await falseMiddleware(filterContext, nextMock); 305 | 306 | strictEqual(middlewareMock.mock.callCount(), 1); 307 | strictEqual(nextMock.mock.callCount(), 1); 308 | }); 309 | 310 | it('should runs with dynamic condition', async (): Promise => { 311 | const filterContext = makeContext(); 312 | 313 | const nextMock = mock.fn(noopNext); 314 | 315 | const middlewareMock = mock.fn( 316 | async (context: ContextType, next: NextMiddleware): Promise => { 317 | ok(context === filterContext); 318 | 319 | await next(); 320 | }, 321 | ); 322 | 323 | const trueMiddleware = getFilterMiddleware( 324 | mock.fn(() => true), 325 | middlewareMock, 326 | ); 327 | 328 | const falseMiddleware = getFilterMiddleware( 329 | mock.fn(() => false), 330 | middlewareMock, 331 | ); 332 | 333 | await trueMiddleware(filterContext, nextMock); 334 | await falseMiddleware(filterContext, nextMock); 335 | 336 | strictEqual(middlewareMock.mock.callCount(), 1); 337 | strictEqual(nextMock.mock.callCount(), 1); 338 | }); 339 | }); 340 | 341 | describe('getBeforeMiddleware', (): void => { 342 | it('should runs before middleware', async (): Promise => { 343 | const beforeContext = makeContext(); 344 | 345 | const nextMock = mock.fn(noopNext); 346 | 347 | const beforeMiddlewareMock = mock.fn( 348 | async (context: ContextType, next: NextMiddleware): Promise => { 349 | ok(context === beforeContext); 350 | 351 | strictEqual(middlewareMock.mock.callCount(), 0); 352 | 353 | await next(); 354 | }, 355 | ); 356 | 357 | const middlewareMock = mock.fn( 358 | async (context: ContextType, next: NextMiddleware): Promise => { 359 | ok(context === beforeContext); 360 | 361 | strictEqual(beforeMiddlewareMock.mock.callCount(), 1); 362 | 363 | await next(); 364 | }, 365 | ); 366 | 367 | const beforeMiddleware = getBeforeMiddleware( 368 | beforeMiddlewareMock, 369 | middlewareMock, 370 | ); 371 | 372 | await beforeMiddleware(beforeContext, nextMock); 373 | 374 | strictEqual(middlewareMock.mock.callCount(), 1); 375 | strictEqual(nextMock.mock.callCount(), 1); 376 | }); 377 | }); 378 | 379 | describe('getAfterMiddleware', (): void => { 380 | it('should runs after middleware', async (): Promise => { 381 | const afterContext = makeContext(); 382 | 383 | const nextMock = mock.fn(noopNext); 384 | 385 | const middlewareMock = mock.fn( 386 | async (context: ContextType, next: NextMiddleware): Promise => { 387 | ok(context === afterContext); 388 | strictEqual(afterMiddlewareMock.mock.callCount(), 0); 389 | 390 | await next(); 391 | }, 392 | ); 393 | 394 | const afterMiddlewareMock = mock.fn( 395 | async (context: ContextType, next: NextMiddleware): Promise => { 396 | ok(context === afterContext); 397 | strictEqual(middlewareMock.mock.callCount(), 1); 398 | 399 | await next(); 400 | }, 401 | ); 402 | 403 | const afterMiddleware = getAfterMiddleware( 404 | middlewareMock, 405 | afterMiddlewareMock, 406 | ); 407 | 408 | await afterMiddleware(afterContext, nextMock); 409 | 410 | strictEqual(middlewareMock.mock.callCount(), 1); 411 | strictEqual(nextMock.mock.callCount(), 1); 412 | }); 413 | }); 414 | 415 | describe('getEnforceMiddleware', (): void => { 416 | it('should runs enforce middleware', async (): Promise => { 417 | const enforceContext = makeContext(); 418 | 419 | const nextMock = mock.fn(noopNext); 420 | 421 | const beforeMiddlewareMock = mock.fn( 422 | async (context: ContextType, next: NextMiddleware): Promise => { 423 | ok(context === enforceContext); 424 | 425 | strictEqual(middlewareMock.mock.callCount(), 0); 426 | strictEqual(afterMiddlewareMock.mock.callCount(), 0); 427 | 428 | await next(); 429 | }, 430 | ); 431 | 432 | const middlewareMock = mock.fn( 433 | async (context: ContextType, next: NextMiddleware): Promise => { 434 | ok(context === enforceContext); 435 | 436 | strictEqual(beforeMiddlewareMock.mock.callCount(), 1); 437 | strictEqual(afterMiddlewareMock.mock.callCount(), 0); 438 | 439 | await next(); 440 | }, 441 | ); 442 | 443 | const afterMiddlewareMock = mock.fn( 444 | async (context: ContextType, next: NextMiddleware): Promise => { 445 | ok(context === enforceContext); 446 | 447 | strictEqual(middlewareMock.mock.callCount(), 1); 448 | strictEqual(beforeMiddlewareMock.mock.callCount(), 1); 449 | 450 | await next(); 451 | }, 452 | ); 453 | 454 | const enforceMiddleware = getEnforceMiddleware( 455 | beforeMiddlewareMock, 456 | middlewareMock, 457 | afterMiddlewareMock, 458 | ); 459 | 460 | await enforceMiddleware(enforceContext, nextMock); 461 | 462 | strictEqual(middlewareMock.mock.callCount(), 1); 463 | strictEqual(nextMock.mock.callCount(), 1); 464 | }); 465 | }); 466 | 467 | describe('getCaughtMiddleware', (): void => { 468 | it('should work with error', async (): Promise => { 469 | const caughtContext = makeContext(); 470 | 471 | const caughtError = new Error('Test error'); 472 | const nextMock = mock.fn(() => { 473 | throw caughtError; 474 | }); 475 | 476 | const handlerMock = mock.fn( 477 | (context: ContextType, error: Error): void => { 478 | ok(context === caughtContext); 479 | strictEqual(error, caughtError); 480 | }, 481 | ); 482 | 483 | const caughtMiddleware = getCaughtMiddleware(handlerMock); 484 | 485 | await caughtMiddleware(caughtContext, nextMock); 486 | 487 | strictEqual(handlerMock.mock.callCount(), 1); 488 | strictEqual(nextMock.mock.callCount(), 1); 489 | }); 490 | 491 | it('should work without error', async (): Promise => { 492 | const caughtContext = makeContext(); 493 | 494 | const nextMock = mock.fn(noopNext); 495 | const handlerMock = mock.fn((): void => {}); 496 | 497 | const caughtMiddleware = getCaughtMiddleware(handlerMock); 498 | 499 | await caughtMiddleware(caughtContext, nextMock); 500 | 501 | strictEqual(handlerMock.mock.callCount(), 0); 502 | strictEqual(nextMock.mock.callCount(), 1); 503 | }); 504 | }); 505 | 506 | describe('getConcurrencyMiddleware', (): void => { 507 | it('should runs concurrency middleware', async (): Promise => { 508 | const concurrencyContext = makeContext(); 509 | 510 | concurrencyContext.shouldTrue = false; 511 | concurrencyContext.shouldFalse = true; 512 | 513 | deepStrictEqual(concurrencyContext, { 514 | shouldTrue: false, 515 | shouldFalse: true, 516 | }); 517 | 518 | const nextMock = mock.fn(noopNext); 519 | 520 | const firstMiddlewareMock = mock.fn( 521 | async (context: ContextType, next: NextMiddleware): Promise => { 522 | ok(context === concurrencyContext); 523 | 524 | concurrencyContext.shouldTrue = true; 525 | 526 | await next(); 527 | }, 528 | ); 529 | 530 | const secondMiddlewareMock = mock.fn( 531 | async (context: ContextType, next: NextMiddleware): Promise => { 532 | ok(context === concurrencyContext); 533 | 534 | concurrencyContext.shouldFalse = false; 535 | 536 | await next(); 537 | }, 538 | ); 539 | 540 | const enforceMiddleware = getConcurrencyMiddleware([ 541 | firstMiddlewareMock as Middleware, 542 | secondMiddlewareMock as Middleware, 543 | ]); 544 | 545 | await enforceMiddleware(concurrencyContext, nextMock); 546 | 547 | deepStrictEqual(concurrencyContext, { 548 | shouldTrue: true, 549 | shouldFalse: false, 550 | }); 551 | 552 | strictEqual(firstMiddlewareMock.mock.callCount(), 1); 553 | strictEqual(secondMiddlewareMock.mock.callCount(), 1); 554 | strictEqual(nextMock.mock.callCount(), 1); 555 | }); 556 | }); 557 | }); 558 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "moduleResolution": "node", 6 | "declaration": true, 7 | "sourceMap": false, 8 | "strict": true 9 | } 10 | } 11 | --------------------------------------------------------------------------------