├── .github
├── dependabot.yml
└── workflows
│ ├── check-pr.yml
│ └── publish-npm-packages.yml
├── .gitignore
├── .npmignore
├── .prettierrc
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── docs
└── assets
│ ├── demo.gif
│ ├── logo-dark.svg
│ └── logo-light.svg
├── jest.config.js
├── package.json
├── pnpm-lock.yaml
├── src
├── index.ts
└── utils
│ └── error.ts
├── tests
├── errors
│ └── 0_errors.test.ts
├── middlewares
│ ├── 0_simple-middleware.test.ts
│ └── 1_chained-middleware.test.ts
├── misc
│ └── 0_no-transformer.test.ts
└── validation
│ ├── 0_body-validation.test.ts
│ ├── 1_header-validation.test.ts
│ ├── 2_params-validation.test.ts
│ ├── 3_query-validation.test.ts
│ ├── 4_combined-validation.test.ts
│ └── 5_validation_transforms.test.ts
└── tsconfig.json
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Enable version updates package.json
4 | - package-ecosystem: 'npm'
5 | directory: '/'
6 | schedule:
7 | interval: 'weekly'
8 |
--------------------------------------------------------------------------------
/.github/workflows/check-pr.yml:
--------------------------------------------------------------------------------
1 | name: '[PR] Tests pass and build is successful'
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 |
7 | jobs:
8 | check-pr:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - uses: actions/setup-node@v4
13 | with:
14 | node-version: '20.x'
15 | - run: npm install -g pnpm
16 | - run: pnpm install --frozen-lockfile
17 | - run: pnpm test
18 | - run: pnpm build
19 |
--------------------------------------------------------------------------------
/.github/workflows/publish-npm-packages.yml:
--------------------------------------------------------------------------------
1 | name: Publish Package to npmjs
2 | on:
3 | workflow_dispatch:
4 | release:
5 | types: [published]
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v4
11 | # Setup .npmrc file to publish to npm
12 | - uses: actions/setup-node@v4
13 | with:
14 | node-version: '20.x'
15 | registry-url: 'https://registry.npmjs.org'
16 | - run: npm install -g pnpm
17 | - run: pnpm install
18 | - run: pnpm test
19 | - run: pnpm build
20 | - run: pnpm publish --access public --no-git-checks
21 | env:
22 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 | .pnp
6 | .pnp.js
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 |
11 | # testing
12 | coverage/
13 |
14 | # IntelliJ
15 | .idea/
16 |
17 | # misc
18 | .DS_Store
19 | *.pem
20 |
21 | # ts
22 | *.tsbuildinfo
23 |
24 | # local env files
25 | .env
26 | .env.local
27 | .env.development.local
28 | .env.test.local
29 | .env.production.local
30 |
31 | # project
32 | dist/
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # needs to be explicity allowed as it is ignored by the
2 | # .gitignore, which is also taken into account by `npm package`
3 | !dist/
4 |
5 | # testing
6 | coverage/
7 |
8 | .vscode/
9 | .github/
10 | docs/
11 | src/
12 | examples/
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 4,
4 | "semi": false,
5 | "singleQuote": true,
6 | "printWidth": 100
7 | }
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.workingDirectories": [
3 | {
4 | "mode": "auto"
5 | }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Lightning Technologies GmbH
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 |
4 |
5 |
6 |
7 |
8 |
9 | A library for building type-safe Node.js APIs
10 |
11 |
12 | Installation •
13 | Examples •
14 | Documentation
15 |
16 |
17 |
18 |
19 | # Build type-safe APIs
20 |
21 | Catena is an lightweight library for building end-to-end type-safe APIs on top of Express. It's inspired by tRPC but unlike tRPC, you can just plug it into your existing Express codebase.
22 | The main goal is to have a unified chain of useful steps to safely handle requests with a great DX and minimal overhead.
23 |
24 |
25 |
26 |
27 |
28 | A demo of type sharing between route handler (backend) and frontend, inspired by tRPC.
29 |
30 |
31 |
32 |
33 | # Installation
34 |
35 | 1. Install Catena and its peer dependencies
36 |
37 | ```
38 | npm i @sonic-tech/catena zod express
39 | ```
40 |
41 | 2. Also make sure that you have Express' types installed, if you want to leverage the full type-safeness.
42 |
43 | ```
44 | npm i -D @types/express
45 | ```
46 |
47 | # Documentation
48 |
49 | - [Examples](#examples)
50 | - [Setting up Catena with Express](#setting-up-catena--express)
51 | - [Core Concepts](#core-concepts)
52 | - [Chaining](#chaining)
53 | - [Validators](#validators)
54 | - [Middlewares](#middlewares-1)
55 | - [Resolver](#resolver)
56 | - [Transformer](#transformer)
57 | - [Type-sharing across codebases](#type-sharing-across-codebases)
58 | - [File-based Routing](#file-based-routing)
59 |
60 | # Examples
61 |
62 | ## A simple handler
63 |
64 | The first example is as simple as it gets. Looks like a normal express handler and also does the same.
65 |
66 | ```ts
67 | // ...
68 | import { Handler } from '@sonic-tech/catena'
69 |
70 | const app = express()
71 | app.use(express.json())
72 |
73 | app.get(
74 | '/',
75 | new Handler()
76 | .resolve((req, res) => {
77 | res.status(200).send('Hello World')
78 | })
79 | // Make sure that `.express()` always is the last method in the handler chain. It converts the logical chain into an express handler.
80 | .express()
81 | )
82 | ```
83 |
84 | ## Validating requests
85 |
86 | There are many occasions where you want to validate parts of the incoming data. Here's how Catena does it.
87 |
88 | ```ts
89 | // ...
90 | import { Handler } from '@sonic-tech/catena'
91 |
92 | const app = express()
93 | app.use(express.json());
94 |
95 |
96 | app.post(
97 | '/user/:uuid',
98 | new Handler().
99 | .validate("params", {
100 | uuid: z.string().uuid()
101 | })
102 | .validate("body", {
103 | username: z.string().optional(),
104 | age: z.number().min(13).optional(),
105 | email: z.string().email(),
106 | })
107 | .resolve(async (req, res) => {
108 | // All 4 properties are strongly typed based on the zod schemas
109 | const { uuid } = req.params
110 | const { username, age, email } = req.body
111 |
112 | // ...
113 |
114 | res.status(200).send("User created!")
115 | })
116 | .express()
117 | )
118 | ```
119 |
120 | ## Transformers
121 |
122 | If you want to have a secure and unified way of returning data to the client, use transformers.
123 | Transformers let you create and send JSON DTOs based on the data that the resolver returned.
124 |
125 | This is the recommended way of returning data to the client.
126 |
127 | ```ts
128 | // ...
129 | import { Handler } from '@sonic-tech/catena'
130 |
131 | const app = express()
132 | app.use(express.json());
133 |
134 |
135 | app.get(
136 | '/user/:uuid',
137 | new Handler().
138 | .validate("params", {
139 | uuid: z.string().uuid()
140 | })
141 | .resolve(async (req, res) => {
142 | const userIncludingPassword = await UserService.getUser(req.uuid)
143 |
144 | return userIncludingPassword
145 | })
146 | .transform((data) => {
147 | return {
148 | data: {
149 | uuid: data.uuid,
150 | email: data.email
151 | }
152 | }
153 | })
154 | .express()
155 | )
156 | ```
157 |
158 | ## Middlewares
159 |
160 | Catena extends middlewares by establishing a shared context that can be passed from one middleware to another and finally to the resolver. You can write inline middlewares or just pass in a function.
161 |
162 | ```ts
163 | // ...
164 | import { Handler, HTTPError } from '@sonic-tech/catena'
165 | import { AnotherMiddleware } from "..."
166 |
167 | const app = express()
168 | app.use(express.json());
169 |
170 |
171 | app.get(
172 | '/user/:uuid',
173 | new Handler().
174 | .validate("params", {
175 | uuid: z.string().uuid()
176 | })
177 | .validate("headers", {
178 | // key in header validations must always be lower-case!
179 | authorization: z.string()
180 | })
181 | .middleware((req) => {j
182 | const requestingUser = await SecurityService.getAuthorizedUser(req.headers.authorization);
183 | if (!requestingUser) {
184 | // Throw errors when you want to stop further request processing while returning an error at the same time
185 | throw new HTTPError(400, 'This should fail')
186 | }
187 |
188 | return {
189 | requestingUser
190 | }
191 | })
192 | .middleware(AnotherMiddleware)
193 | .resolve(async (req, res, context) => {
194 | // You can access the merged type-safe context of all middlewares in the resolver
195 | const { requestingUser } = context
196 |
197 |
198 | const userIncludingPassword = await UserService.getUser(req.uuid)
199 |
200 | return userIncludingPassword
201 | })
202 | .transform((data) => {
203 | return {
204 | data: {
205 | uuid: data.uuid,
206 | email: data.email
207 | }
208 | }
209 | })
210 | .express()
211 | )
212 | ```
213 |
214 | ## Setting up Catena + Express
215 |
216 | Catena currently supports Express; work is underway to support Next.js.
217 |
218 | To setup Catena with Express make sure to do the following:
219 |
220 | - Install `express` and `@types/express` using yarn/npm/pnpm/bun
221 | - Suffix all Catena handlers with `.express()` (!). This function will transform the Catena chain into an Express request handler. Without appending this method, you're going to get a type-error and the handler will not work.
222 |
223 | Also, you have to use the `express.json()` (or body-parser) middleware in order for the validators to work with JSON content.
224 |
225 | ```ts
226 | const app = express()
227 | app.use(express.json())
228 | ```
229 |
230 | ## Core Concepts
231 |
232 | ## Chaining
233 |
234 | Catena features a handler that is assembled as a chain out of the following elements. Only the `resolve` element is required, all other elements are optional.
235 |
236 | - **`validate`**: Chain [zod](https://github.com/colinhacks/zod)-powered validators for `body`, `params`, `query` and `headers` that only allow requests that match the zod schema
237 | - **`middleware`**: Middlewares can return values into a shared "context", which is type-safe and accessible to all following chain elements. To block further request processing, e.g. because the requesting entity is not authorized, throw `HTTPError`
238 | - **`resolve`**: The resolver should be used to handle all business logic, like a normal express handler would do. It either returns data that is passed to the transformer or may use the `res` object to send a response without a transformer
239 | - **`transform`**: The transformer can be used to generate a DTO that can be send as response body by just returning it
240 |
241 | The elements in this chain are processed one after the other. So if a middleware is executed after a validator, you can be sure that the validation has been passed. If there are multiple chained middlewares, you always access the context of all previous middlewares in the following middlewares.
242 |
243 | All Catena chain elements are bundled into one actual Express handler with the `.express()` method at the end of the chain. Internally, we are not calling Express' `next()` until all chain elements have completed or there has been an uncaught error. If there is an uncaught error, that is not `HTTPError`, we are calling `next(err)`. You may then handle errors on router level or append another middleware.
244 |
245 | ## Validators
246 |
247 | Validators are virtual middlewares that validate the given request data using zod. You can create validators for `body`, `params`, `query` and `headers`. Objects validated by validators are type guarded for all following middlewares and the resolver.
248 |
249 | ### Method Signature
250 |
251 | `.validate(type: "body" | "params" | "query" | "headers", zodObject: object | z.object)`
252 |
253 | The second parameter can either be a `z.object()` or just a normal object that contains keys with zod validations as values. So both of the following usages are valid:
254 |
255 | ```ts
256 | new Handler().validate('body', {
257 | email: z.string().email(),
258 | })
259 | // .resolve ...
260 | ```
261 |
262 | ```ts
263 | new Handler().validate(
264 | 'body',
265 | z.object({
266 | email: z.string().email(),
267 | })
268 | // .resolve ...
269 | )
270 | ```
271 |
272 | Using just an object is more readable, while using `z.object` has the advantage of being able to infer the validator type and use it e.g. in services as argument type. Example:
273 |
274 | ```ts
275 | const bodyValidation = z.object({
276 | email: z.string().email(),
277 | })
278 |
279 | new Handler().validate('body', bodyValidation) //.resolve ...
280 |
281 | const myServiceMethod = (body: z.infer) => {
282 | // ...
283 | }
284 | ```
285 |
286 | ### Caveats
287 |
288 | - For `headers` validations, **always** use lower-case only keys! ~~`Authorization: z.string()`~~ --> `authorization: z.string()`. The reason for this is that Express converts all headers to lower case to comply with the RFC for HTTP requests, which states that header keys are case-insensitive.
289 |
290 | ## Middlewares
291 |
292 | Middlewares are functions that you can connect prior to the resolver in order to add custom logic such as authorization, non-trivial validation, etc. before the resolver is executed.
293 |
294 | ### Middleware method signature
295 |
296 | ```ts
297 | .middleware(req: RequestWithValidations, res: Response, next: NextFunction, context: MiddlewareContext)
298 | ```
299 |
300 | - `req` extends the default express object with the type-safe inference made by the validators on `body`, `params`, `query` and `headers`.
301 | - `res` is the default Express `Response` object
302 | - `next` is the default Express `NextFunction`
303 | - `context` is a simple object that is empty at the beginning of the first middleware in the chain. It can be filled with any values by the middlewares and passed to other middlewares and the resolver, see below
304 |
305 | ### Catena Middlewares
306 |
307 | Catena exposes a more straightforward way to write middlewares, while also supporting all existing middlewares.
308 |
309 | #### Context
310 |
311 | Instead of overwriting or extending some parts of the `req` object to pass along context, you can just return an object. This object will be merged with the existing `context` object and will be accessible to all following middlewares and the resolver (type-safe, of course).
312 |
313 | ```ts
314 | import { Handler, HTTPError } from '@sonic-tech/catena'
315 |
316 | new Handler()
317 | .validate('params', {
318 | uuid: z.string().uuid(),
319 | })
320 | .middleware(async (req) => {
321 | const user = await UserService.getUser(req.params.uuid) // -> { email: "...", uuid: "..." }
322 |
323 | return {
324 | user,
325 | }
326 | })
327 | .middleware(async (req, res, next, context) => {
328 | // email and uuid can be extracted from the context type-safely
329 | const { email, uuid } = context.user
330 |
331 | if (!email.endsWith('@mycompany.com')) {
332 | throw new HTTPError(403, 'Company not allowed')
333 | }
334 |
335 | const organization = await OrganizationService().getByUser(uuid)
336 |
337 | return {
338 | organization,
339 | }
340 | })
341 | .resolve(async (req, res, context) => {
342 | /**
343 | * The resolver has access to both user and organization
344 | * since the context objects have been merged
345 | */
346 | const { user, organization } = context
347 |
348 | // ...
349 | })
350 | .express()
351 | ```
352 |
353 | A middleware does not need to return anything. If it returns void, the context objects stays as is.
354 |
355 | Sending something to the client using `res.send` causes the chain to stop, i.e. the next chain element is not executed.
356 |
357 | #### Errors
358 |
359 | Instead of using `res.send` to send error messages, you can import `HTTPError` from Catena and use `throw new HTTPError(statusCode, errorMessage)` which will automatically resolve the request using the given status code and a standardized error message. An example can be seen in the code snippet of the last section.
360 |
361 | ### Existing Middlewares
362 |
363 | You can also use any middleware that works with express out of the box using the default `(req, res, next)` syntax.
364 |
365 | ```ts
366 | import { MySecondMiddleware } from "../middlewares"
367 | const MyExistingMiddleware = (req, res, next) => {
368 | if(!req.body.continue) {
369 | res.status(400).send("Bad Request")
370 | return
371 | }
372 |
373 | next()
374 | }
375 |
376 | new Handler()
377 | .middleware(MyExistingMiddleware)
378 | .middleware(MySecondMiddleware)
379 | .resolve(...)
380 | .transform(...)
381 | .express()
382 | ```
383 |
384 | ## Resolver
385 |
386 | The resolver may be used as the core handler of the request, just as you used the handler function before.
387 |
388 | ### Method Signature
389 |
390 | ```ts
391 | .resolve((req: RequestWithValidations, res: Response, context: MiddlewareContext) => any | Promise)
392 | ```
393 |
394 | - The `req` is the default Express request object, except that `req.body`, `req.params`, `req.query` and `req.headers` are typed by the infered zod validations from the validators
395 | - The `res` object is the default Express response object
396 | - The `context` object is the merged Context you passed along the middlewares
397 |
398 | ### Context
399 |
400 | As with middlewares, you can access the merged context of all previous middlewares (= all middlewares) through the `context` object.
401 |
402 | ### Return Values
403 |
404 | You can use `res` to send responses directly to the client without a transformer.
405 |
406 | However, it is recommended to return values instead. Those values are then passed to the [Transformer](#transformer) instead of being sent to the client directly.
407 |
408 | ```ts
409 | new Handler()
410 | .middleware(() => {
411 | return {
412 | user: {
413 | uuid: '...',
414 | },
415 | }
416 | })
417 | .resolve((req, res, context) => {
418 | const { user } = context
419 |
420 | const subscription = await UserService.getUserSubscription(user.uuid)
421 |
422 | // Just pass the data to the transformer instead of using res.send.
423 | return subscription
424 | })
425 | .transform((data) => {
426 | // data has the type of "subscription"
427 | return {
428 | userSubscriptionUuid: data.uuid,
429 | }
430 | })
431 | .express()
432 | ```
433 |
434 | ## Transformer
435 |
436 | Transformers can be used to create sanitized data transfer objects based on the resolved data. This enables your resolver to just handle the business logic, independent of what single values should or should not be returned to the client.
437 |
438 | For example, the resolver might get a user object from the database for a given query. Of course you don't want to return the user's password to the client. To keep things clean, just pass the user object from the resolver (which shouldn't have to care about sanitizing values) to the transformer, which then takes the given object and only returns values that are appropriate to be returned.
439 |
440 | Example
441 |
442 | ```ts
443 | new Handler()
444 | .validate('params', {
445 | uuid: z.string().uuid(),
446 | })
447 | .resolve(async (req) => {
448 | const { uuid } = req.params
449 |
450 | // This object contains confidential information, like a password
451 | const user = await UserService.getUser(uuid)
452 |
453 | return user
454 | })
455 | .transform((data) => {
456 | return {
457 | uuid: data.uuid,
458 | email: data.email,
459 | // leave out the password, since we don't want to send it to the client
460 | }
461 | })
462 | .express()
463 | ```
464 |
465 | You may return any value. If you choose to return an object or array, they are send with `res.json()`. All other return values are send with `res.send()`.
466 |
467 | If you want to use a different status code, set headers, cookie, etc. you can use e.g. `res.status(201)` before the return statement. We'll use this `res` object for sending the response internally
468 |
469 | ## Type-sharing across codebases
470 |
471 | Request and response types of API handlers can be inferred and exported. You can use this to share your types e.g. with the frontend, like tRPC does.
472 |
473 | Each handler exposes a `types` interface that contains `request` and `response` types.
474 |
475 | The request type contains the expected types for `body`, `query`, `params` and `headers`.
476 |
477 | The `response` type represents the type of the value that is returned by the transformer.
478 |
479 | ### Example
480 |
481 | **Backend**
482 |
483 | ```ts backend/handler.ts
484 | const myRequestHandler = new Handler()
485 | .validate("body", {
486 | email: z.string().email()
487 | })
488 | .resolve(...)
489 | .transform((data) => {
490 | return {
491 | data: {
492 | uuid: data.uuid,
493 | email: data.email,
494 | age: data.age
495 | }
496 | }
497 | })
498 | .express()
499 |
500 | app.get("/user", myRequestHandler);
501 |
502 |
503 | export type GetUserTypes = typeof myRequestHandler.types;
504 |
505 | ```
506 |
507 | **Frontend**
508 |
509 | ```ts frontend/requests.ts
510 | // It's important to only import using `import type`. This way, no business logic will be leaked to the frontend but just the type
511 | import type { GetUserTypes } from 'backend/handler'
512 |
513 | /**
514 | * Body type inferred as
515 | * {
516 | * email: string
517 | * }
518 | */
519 |
520 | const body: GetUserTypes['request']['body'] = {
521 | email: 'test@test.com',
522 | }
523 |
524 | const myRequestResponse = await fetch('/user', {
525 | body: JSON.stringify(body),
526 | })
527 |
528 | /**
529 | * Type inferred as
530 | * {
531 | * data: {
532 | * uuid: string;
533 | * email: string;
534 | * age: number;
535 | * }
536 | */
537 | const responseData: GetUserTypes['response'] = await myRequestResponse.json()
538 | ```
539 |
540 | ## File-based Routing
541 |
542 | We found [express-file-routing](https://github.com/matthiaaas/express-file-routing) to be a great addition to projects that use Catena, if you like file-based routing.
543 |
544 | An example of Catena + file-based routing:
545 |
546 | ```ts
547 | // /users/[uuid].ts
548 |
549 | export const POST = new Handler()
550 | .validate('params', {
551 | uuid: z.string().uuid(),
552 | })
553 | .validate('body', {
554 | email: z.string().email().optional(),
555 | firstName: z.string().optional(),
556 | lastName: z.string().optional(),
557 | })
558 | .resolve((req) => {
559 | const updatedUser = new UserService.updateUser(req.params.uuid)
560 |
561 | return updatedUser
562 | })
563 | .transform((user) => {
564 | return {
565 | uuid: user.uuid,
566 | email: user.email,
567 | name: user.firstName + ' ' + user.lastName,
568 | }
569 | })
570 | .express()
571 | ```
572 |
--------------------------------------------------------------------------------
/docs/assets/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sonic-technology/catena/faa824f75cd04e559e042720bfe7b47e3694466a/docs/assets/demo.gif
--------------------------------------------------------------------------------
/docs/assets/logo-dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/assets/logo-light.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('ts-jest').JestConfigWithTsJest} */
2 | export default {
3 | testEnvironment: 'node',
4 | preset: 'ts-jest/presets/default-esm',
5 | testMatch: ['/**/tests/**/*.test.ts'],
6 | moduleNameMapper: {
7 | // @/index.js -> src/index.ts
8 | // '^@/(.*)$': '/src/$1',
9 | '^(..?/.+).js?$': '$1',
10 | },
11 | extensionsToTreatAsEsm: ['.ts'],
12 | transform: {
13 | '^.+\\.[jt]s?$': [
14 | 'ts-jest',
15 | {
16 | useESM: true,
17 | tsconfig: {
18 | allowJs: true,
19 | },
20 | },
21 | ],
22 | },
23 | }
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@sonic-tech/catena",
3 | "version": "0.2.0",
4 | "type": "module",
5 | "description": "A lightweight and extensible library for building robust Node.js APIs, fast.",
6 | "main": "./dist/index.js",
7 | "types": "./dist/index.d.ts",
8 | "scripts": {
9 | "build": "rm -rf ./dist tsconfig.tsbuildinfo && tsc",
10 | "test": "NODE_OPTIONS=--experimental-vm-modules jest"
11 | },
12 | "peerDependencies": {
13 | "express": "^4.18.2",
14 | "zod": "^3.22.4"
15 | },
16 | "keywords": [],
17 | "repository": {
18 | "type": "git",
19 | "url": "https://github.com/sonic-technology/catena"
20 | },
21 | "author": "Sonic Technologies",
22 | "license": "MIT",
23 | "devDependencies": {
24 | "@types/express": "^4.17.20",
25 | "@types/jest": "^29.5.6",
26 | "@types/supertest": "^6.0.2",
27 | "jest": "^29.7.0",
28 | "supertest": "^6.3.3",
29 | "ts-jest": "^29.1.1",
30 | "typescript": "^5.2.2"
31 | },
32 | "packageManager": "pnpm@8.6.10"
33 | }
34 |
--------------------------------------------------------------------------------
/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '6.0'
2 |
3 | settings:
4 | autoInstallPeers: true
5 | excludeLinksFromLockfile: false
6 |
7 | dependencies:
8 | express:
9 | specifier: ^4.18.2
10 | version: 4.18.2
11 | zod:
12 | specifier: ^3.22.4
13 | version: 3.22.4
14 |
15 | devDependencies:
16 | '@types/express':
17 | specifier: ^4.17.20
18 | version: 4.17.21
19 | '@types/jest':
20 | specifier: ^29.5.6
21 | version: 29.5.12
22 | '@types/supertest':
23 | specifier: ^6.0.2
24 | version: 6.0.2
25 | jest:
26 | specifier: ^29.7.0
27 | version: 29.7.0
28 | supertest:
29 | specifier: ^6.3.3
30 | version: 6.3.4
31 | ts-jest:
32 | specifier: ^29.1.1
33 | version: 29.1.5(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.5.3)
34 | typescript:
35 | specifier: ^5.2.2
36 | version: 5.5.3
37 |
38 | packages:
39 |
40 | /@ampproject/remapping@2.2.1:
41 | resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==}
42 | engines: {node: '>=6.0.0'}
43 | dependencies:
44 | '@jridgewell/gen-mapping': 0.3.3
45 | '@jridgewell/trace-mapping': 0.3.22
46 | dev: true
47 |
48 | /@babel/code-frame@7.23.5:
49 | resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==}
50 | engines: {node: '>=6.9.0'}
51 | dependencies:
52 | '@babel/highlight': 7.23.4
53 | chalk: 2.4.2
54 | dev: true
55 |
56 | /@babel/compat-data@7.23.5:
57 | resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==}
58 | engines: {node: '>=6.9.0'}
59 | dev: true
60 |
61 | /@babel/core@7.23.9:
62 | resolution: {integrity: sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==}
63 | engines: {node: '>=6.9.0'}
64 | dependencies:
65 | '@ampproject/remapping': 2.2.1
66 | '@babel/code-frame': 7.23.5
67 | '@babel/generator': 7.23.6
68 | '@babel/helper-compilation-targets': 7.23.6
69 | '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.9)
70 | '@babel/helpers': 7.23.9
71 | '@babel/parser': 7.23.9
72 | '@babel/template': 7.23.9
73 | '@babel/traverse': 7.23.9
74 | '@babel/types': 7.23.9
75 | convert-source-map: 2.0.0
76 | debug: 4.3.4
77 | gensync: 1.0.0-beta.2
78 | json5: 2.2.3
79 | semver: 6.3.1
80 | transitivePeerDependencies:
81 | - supports-color
82 | dev: true
83 |
84 | /@babel/generator@7.23.6:
85 | resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==}
86 | engines: {node: '>=6.9.0'}
87 | dependencies:
88 | '@babel/types': 7.23.9
89 | '@jridgewell/gen-mapping': 0.3.3
90 | '@jridgewell/trace-mapping': 0.3.22
91 | jsesc: 2.5.2
92 | dev: true
93 |
94 | /@babel/helper-compilation-targets@7.23.6:
95 | resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==}
96 | engines: {node: '>=6.9.0'}
97 | dependencies:
98 | '@babel/compat-data': 7.23.5
99 | '@babel/helper-validator-option': 7.23.5
100 | browserslist: 4.22.3
101 | lru-cache: 5.1.1
102 | semver: 6.3.1
103 | dev: true
104 |
105 | /@babel/helper-environment-visitor@7.22.20:
106 | resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==}
107 | engines: {node: '>=6.9.0'}
108 | dev: true
109 |
110 | /@babel/helper-function-name@7.23.0:
111 | resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==}
112 | engines: {node: '>=6.9.0'}
113 | dependencies:
114 | '@babel/template': 7.23.9
115 | '@babel/types': 7.23.9
116 | dev: true
117 |
118 | /@babel/helper-hoist-variables@7.22.5:
119 | resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==}
120 | engines: {node: '>=6.9.0'}
121 | dependencies:
122 | '@babel/types': 7.23.9
123 | dev: true
124 |
125 | /@babel/helper-module-imports@7.22.15:
126 | resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==}
127 | engines: {node: '>=6.9.0'}
128 | dependencies:
129 | '@babel/types': 7.23.9
130 | dev: true
131 |
132 | /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.9):
133 | resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==}
134 | engines: {node: '>=6.9.0'}
135 | peerDependencies:
136 | '@babel/core': ^7.0.0
137 | dependencies:
138 | '@babel/core': 7.23.9
139 | '@babel/helper-environment-visitor': 7.22.20
140 | '@babel/helper-module-imports': 7.22.15
141 | '@babel/helper-simple-access': 7.22.5
142 | '@babel/helper-split-export-declaration': 7.22.6
143 | '@babel/helper-validator-identifier': 7.22.20
144 | dev: true
145 |
146 | /@babel/helper-plugin-utils@7.22.5:
147 | resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==}
148 | engines: {node: '>=6.9.0'}
149 | dev: true
150 |
151 | /@babel/helper-simple-access@7.22.5:
152 | resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==}
153 | engines: {node: '>=6.9.0'}
154 | dependencies:
155 | '@babel/types': 7.23.9
156 | dev: true
157 |
158 | /@babel/helper-split-export-declaration@7.22.6:
159 | resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
160 | engines: {node: '>=6.9.0'}
161 | dependencies:
162 | '@babel/types': 7.23.9
163 | dev: true
164 |
165 | /@babel/helper-string-parser@7.23.4:
166 | resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
167 | engines: {node: '>=6.9.0'}
168 | dev: true
169 |
170 | /@babel/helper-validator-identifier@7.22.20:
171 | resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
172 | engines: {node: '>=6.9.0'}
173 | dev: true
174 |
175 | /@babel/helper-validator-option@7.23.5:
176 | resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==}
177 | engines: {node: '>=6.9.0'}
178 | dev: true
179 |
180 | /@babel/helpers@7.23.9:
181 | resolution: {integrity: sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==}
182 | engines: {node: '>=6.9.0'}
183 | dependencies:
184 | '@babel/template': 7.23.9
185 | '@babel/traverse': 7.23.9
186 | '@babel/types': 7.23.9
187 | transitivePeerDependencies:
188 | - supports-color
189 | dev: true
190 |
191 | /@babel/highlight@7.23.4:
192 | resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==}
193 | engines: {node: '>=6.9.0'}
194 | dependencies:
195 | '@babel/helper-validator-identifier': 7.22.20
196 | chalk: 2.4.2
197 | js-tokens: 4.0.0
198 | dev: true
199 |
200 | /@babel/parser@7.23.9:
201 | resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==}
202 | engines: {node: '>=6.0.0'}
203 | hasBin: true
204 | dependencies:
205 | '@babel/types': 7.23.9
206 | dev: true
207 |
208 | /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.23.9):
209 | resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
210 | peerDependencies:
211 | '@babel/core': ^7.0.0-0
212 | dependencies:
213 | '@babel/core': 7.23.9
214 | '@babel/helper-plugin-utils': 7.22.5
215 | dev: true
216 |
217 | /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.23.9):
218 | resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==}
219 | peerDependencies:
220 | '@babel/core': ^7.0.0-0
221 | dependencies:
222 | '@babel/core': 7.23.9
223 | '@babel/helper-plugin-utils': 7.22.5
224 | dev: true
225 |
226 | /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.23.9):
227 | resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
228 | peerDependencies:
229 | '@babel/core': ^7.0.0-0
230 | dependencies:
231 | '@babel/core': 7.23.9
232 | '@babel/helper-plugin-utils': 7.22.5
233 | dev: true
234 |
235 | /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.23.9):
236 | resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==}
237 | peerDependencies:
238 | '@babel/core': ^7.0.0-0
239 | dependencies:
240 | '@babel/core': 7.23.9
241 | '@babel/helper-plugin-utils': 7.22.5
242 | dev: true
243 |
244 | /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.23.9):
245 | resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
246 | peerDependencies:
247 | '@babel/core': ^7.0.0-0
248 | dependencies:
249 | '@babel/core': 7.23.9
250 | '@babel/helper-plugin-utils': 7.22.5
251 | dev: true
252 |
253 | /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.9):
254 | resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==}
255 | engines: {node: '>=6.9.0'}
256 | peerDependencies:
257 | '@babel/core': ^7.0.0-0
258 | dependencies:
259 | '@babel/core': 7.23.9
260 | '@babel/helper-plugin-utils': 7.22.5
261 | dev: true
262 |
263 | /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.23.9):
264 | resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
265 | peerDependencies:
266 | '@babel/core': ^7.0.0-0
267 | dependencies:
268 | '@babel/core': 7.23.9
269 | '@babel/helper-plugin-utils': 7.22.5
270 | dev: true
271 |
272 | /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.23.9):
273 | resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
274 | peerDependencies:
275 | '@babel/core': ^7.0.0-0
276 | dependencies:
277 | '@babel/core': 7.23.9
278 | '@babel/helper-plugin-utils': 7.22.5
279 | dev: true
280 |
281 | /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.23.9):
282 | resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
283 | peerDependencies:
284 | '@babel/core': ^7.0.0-0
285 | dependencies:
286 | '@babel/core': 7.23.9
287 | '@babel/helper-plugin-utils': 7.22.5
288 | dev: true
289 |
290 | /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.23.9):
291 | resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
292 | peerDependencies:
293 | '@babel/core': ^7.0.0-0
294 | dependencies:
295 | '@babel/core': 7.23.9
296 | '@babel/helper-plugin-utils': 7.22.5
297 | dev: true
298 |
299 | /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.23.9):
300 | resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
301 | peerDependencies:
302 | '@babel/core': ^7.0.0-0
303 | dependencies:
304 | '@babel/core': 7.23.9
305 | '@babel/helper-plugin-utils': 7.22.5
306 | dev: true
307 |
308 | /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.23.9):
309 | resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
310 | peerDependencies:
311 | '@babel/core': ^7.0.0-0
312 | dependencies:
313 | '@babel/core': 7.23.9
314 | '@babel/helper-plugin-utils': 7.22.5
315 | dev: true
316 |
317 | /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.23.9):
318 | resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
319 | engines: {node: '>=6.9.0'}
320 | peerDependencies:
321 | '@babel/core': ^7.0.0-0
322 | dependencies:
323 | '@babel/core': 7.23.9
324 | '@babel/helper-plugin-utils': 7.22.5
325 | dev: true
326 |
327 | /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.9):
328 | resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==}
329 | engines: {node: '>=6.9.0'}
330 | peerDependencies:
331 | '@babel/core': ^7.0.0-0
332 | dependencies:
333 | '@babel/core': 7.23.9
334 | '@babel/helper-plugin-utils': 7.22.5
335 | dev: true
336 |
337 | /@babel/template@7.23.9:
338 | resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==}
339 | engines: {node: '>=6.9.0'}
340 | dependencies:
341 | '@babel/code-frame': 7.23.5
342 | '@babel/parser': 7.23.9
343 | '@babel/types': 7.23.9
344 | dev: true
345 |
346 | /@babel/traverse@7.23.9:
347 | resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==}
348 | engines: {node: '>=6.9.0'}
349 | dependencies:
350 | '@babel/code-frame': 7.23.5
351 | '@babel/generator': 7.23.6
352 | '@babel/helper-environment-visitor': 7.22.20
353 | '@babel/helper-function-name': 7.23.0
354 | '@babel/helper-hoist-variables': 7.22.5
355 | '@babel/helper-split-export-declaration': 7.22.6
356 | '@babel/parser': 7.23.9
357 | '@babel/types': 7.23.9
358 | debug: 4.3.4
359 | globals: 11.12.0
360 | transitivePeerDependencies:
361 | - supports-color
362 | dev: true
363 |
364 | /@babel/types@7.23.9:
365 | resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==}
366 | engines: {node: '>=6.9.0'}
367 | dependencies:
368 | '@babel/helper-string-parser': 7.23.4
369 | '@babel/helper-validator-identifier': 7.22.20
370 | to-fast-properties: 2.0.0
371 | dev: true
372 |
373 | /@bcoe/v8-coverage@0.2.3:
374 | resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
375 | dev: true
376 |
377 | /@istanbuljs/load-nyc-config@1.1.0:
378 | resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
379 | engines: {node: '>=8'}
380 | dependencies:
381 | camelcase: 5.3.1
382 | find-up: 4.1.0
383 | get-package-type: 0.1.0
384 | js-yaml: 3.14.1
385 | resolve-from: 5.0.0
386 | dev: true
387 |
388 | /@istanbuljs/schema@0.1.3:
389 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
390 | engines: {node: '>=8'}
391 | dev: true
392 |
393 | /@jest/console@29.7.0:
394 | resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==}
395 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
396 | dependencies:
397 | '@jest/types': 29.6.3
398 | '@types/node': 20.11.16
399 | chalk: 4.1.2
400 | jest-message-util: 29.7.0
401 | jest-util: 29.7.0
402 | slash: 3.0.0
403 | dev: true
404 |
405 | /@jest/core@29.7.0:
406 | resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==}
407 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
408 | peerDependencies:
409 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
410 | peerDependenciesMeta:
411 | node-notifier:
412 | optional: true
413 | dependencies:
414 | '@jest/console': 29.7.0
415 | '@jest/reporters': 29.7.0
416 | '@jest/test-result': 29.7.0
417 | '@jest/transform': 29.7.0
418 | '@jest/types': 29.6.3
419 | '@types/node': 20.11.16
420 | ansi-escapes: 4.3.2
421 | chalk: 4.1.2
422 | ci-info: 3.9.0
423 | exit: 0.1.2
424 | graceful-fs: 4.2.11
425 | jest-changed-files: 29.7.0
426 | jest-config: 29.7.0(@types/node@20.11.16)
427 | jest-haste-map: 29.7.0
428 | jest-message-util: 29.7.0
429 | jest-regex-util: 29.6.3
430 | jest-resolve: 29.7.0
431 | jest-resolve-dependencies: 29.7.0
432 | jest-runner: 29.7.0
433 | jest-runtime: 29.7.0
434 | jest-snapshot: 29.7.0
435 | jest-util: 29.7.0
436 | jest-validate: 29.7.0
437 | jest-watcher: 29.7.0
438 | micromatch: 4.0.5
439 | pretty-format: 29.7.0
440 | slash: 3.0.0
441 | strip-ansi: 6.0.1
442 | transitivePeerDependencies:
443 | - babel-plugin-macros
444 | - supports-color
445 | - ts-node
446 | dev: true
447 |
448 | /@jest/environment@29.7.0:
449 | resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==}
450 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
451 | dependencies:
452 | '@jest/fake-timers': 29.7.0
453 | '@jest/types': 29.6.3
454 | '@types/node': 20.11.16
455 | jest-mock: 29.7.0
456 | dev: true
457 |
458 | /@jest/expect-utils@29.7.0:
459 | resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==}
460 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
461 | dependencies:
462 | jest-get-type: 29.6.3
463 | dev: true
464 |
465 | /@jest/expect@29.7.0:
466 | resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==}
467 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
468 | dependencies:
469 | expect: 29.7.0
470 | jest-snapshot: 29.7.0
471 | transitivePeerDependencies:
472 | - supports-color
473 | dev: true
474 |
475 | /@jest/fake-timers@29.7.0:
476 | resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==}
477 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
478 | dependencies:
479 | '@jest/types': 29.6.3
480 | '@sinonjs/fake-timers': 10.3.0
481 | '@types/node': 20.11.16
482 | jest-message-util: 29.7.0
483 | jest-mock: 29.7.0
484 | jest-util: 29.7.0
485 | dev: true
486 |
487 | /@jest/globals@29.7.0:
488 | resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==}
489 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
490 | dependencies:
491 | '@jest/environment': 29.7.0
492 | '@jest/expect': 29.7.0
493 | '@jest/types': 29.6.3
494 | jest-mock: 29.7.0
495 | transitivePeerDependencies:
496 | - supports-color
497 | dev: true
498 |
499 | /@jest/reporters@29.7.0:
500 | resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==}
501 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
502 | peerDependencies:
503 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
504 | peerDependenciesMeta:
505 | node-notifier:
506 | optional: true
507 | dependencies:
508 | '@bcoe/v8-coverage': 0.2.3
509 | '@jest/console': 29.7.0
510 | '@jest/test-result': 29.7.0
511 | '@jest/transform': 29.7.0
512 | '@jest/types': 29.6.3
513 | '@jridgewell/trace-mapping': 0.3.22
514 | '@types/node': 20.11.16
515 | chalk: 4.1.2
516 | collect-v8-coverage: 1.0.2
517 | exit: 0.1.2
518 | glob: 7.2.3
519 | graceful-fs: 4.2.11
520 | istanbul-lib-coverage: 3.2.2
521 | istanbul-lib-instrument: 6.0.1
522 | istanbul-lib-report: 3.0.1
523 | istanbul-lib-source-maps: 4.0.1
524 | istanbul-reports: 3.1.6
525 | jest-message-util: 29.7.0
526 | jest-util: 29.7.0
527 | jest-worker: 29.7.0
528 | slash: 3.0.0
529 | string-length: 4.0.2
530 | strip-ansi: 6.0.1
531 | v8-to-istanbul: 9.2.0
532 | transitivePeerDependencies:
533 | - supports-color
534 | dev: true
535 |
536 | /@jest/schemas@29.6.3:
537 | resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
538 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
539 | dependencies:
540 | '@sinclair/typebox': 0.27.8
541 | dev: true
542 |
543 | /@jest/source-map@29.6.3:
544 | resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==}
545 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
546 | dependencies:
547 | '@jridgewell/trace-mapping': 0.3.22
548 | callsites: 3.1.0
549 | graceful-fs: 4.2.11
550 | dev: true
551 |
552 | /@jest/test-result@29.7.0:
553 | resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==}
554 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
555 | dependencies:
556 | '@jest/console': 29.7.0
557 | '@jest/types': 29.6.3
558 | '@types/istanbul-lib-coverage': 2.0.6
559 | collect-v8-coverage: 1.0.2
560 | dev: true
561 |
562 | /@jest/test-sequencer@29.7.0:
563 | resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==}
564 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
565 | dependencies:
566 | '@jest/test-result': 29.7.0
567 | graceful-fs: 4.2.11
568 | jest-haste-map: 29.7.0
569 | slash: 3.0.0
570 | dev: true
571 |
572 | /@jest/transform@29.7.0:
573 | resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
574 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
575 | dependencies:
576 | '@babel/core': 7.23.9
577 | '@jest/types': 29.6.3
578 | '@jridgewell/trace-mapping': 0.3.22
579 | babel-plugin-istanbul: 6.1.1
580 | chalk: 4.1.2
581 | convert-source-map: 2.0.0
582 | fast-json-stable-stringify: 2.1.0
583 | graceful-fs: 4.2.11
584 | jest-haste-map: 29.7.0
585 | jest-regex-util: 29.6.3
586 | jest-util: 29.7.0
587 | micromatch: 4.0.5
588 | pirates: 4.0.6
589 | slash: 3.0.0
590 | write-file-atomic: 4.0.2
591 | transitivePeerDependencies:
592 | - supports-color
593 | dev: true
594 |
595 | /@jest/types@29.6.3:
596 | resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
597 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
598 | dependencies:
599 | '@jest/schemas': 29.6.3
600 | '@types/istanbul-lib-coverage': 2.0.6
601 | '@types/istanbul-reports': 3.0.4
602 | '@types/node': 20.11.16
603 | '@types/yargs': 17.0.32
604 | chalk: 4.1.2
605 | dev: true
606 |
607 | /@jridgewell/gen-mapping@0.3.3:
608 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
609 | engines: {node: '>=6.0.0'}
610 | dependencies:
611 | '@jridgewell/set-array': 1.1.2
612 | '@jridgewell/sourcemap-codec': 1.4.15
613 | '@jridgewell/trace-mapping': 0.3.22
614 | dev: true
615 |
616 | /@jridgewell/resolve-uri@3.1.1:
617 | resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==}
618 | engines: {node: '>=6.0.0'}
619 | dev: true
620 |
621 | /@jridgewell/set-array@1.1.2:
622 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
623 | engines: {node: '>=6.0.0'}
624 | dev: true
625 |
626 | /@jridgewell/sourcemap-codec@1.4.15:
627 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
628 | dev: true
629 |
630 | /@jridgewell/trace-mapping@0.3.22:
631 | resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==}
632 | dependencies:
633 | '@jridgewell/resolve-uri': 3.1.1
634 | '@jridgewell/sourcemap-codec': 1.4.15
635 | dev: true
636 |
637 | /@sinclair/typebox@0.27.8:
638 | resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
639 | dev: true
640 |
641 | /@sinonjs/commons@3.0.1:
642 | resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==}
643 | dependencies:
644 | type-detect: 4.0.8
645 | dev: true
646 |
647 | /@sinonjs/fake-timers@10.3.0:
648 | resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
649 | dependencies:
650 | '@sinonjs/commons': 3.0.1
651 | dev: true
652 |
653 | /@types/babel__core@7.20.5:
654 | resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
655 | dependencies:
656 | '@babel/parser': 7.23.9
657 | '@babel/types': 7.23.9
658 | '@types/babel__generator': 7.6.8
659 | '@types/babel__template': 7.4.4
660 | '@types/babel__traverse': 7.20.5
661 | dev: true
662 |
663 | /@types/babel__generator@7.6.8:
664 | resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==}
665 | dependencies:
666 | '@babel/types': 7.23.9
667 | dev: true
668 |
669 | /@types/babel__template@7.4.4:
670 | resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
671 | dependencies:
672 | '@babel/parser': 7.23.9
673 | '@babel/types': 7.23.9
674 | dev: true
675 |
676 | /@types/babel__traverse@7.20.5:
677 | resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==}
678 | dependencies:
679 | '@babel/types': 7.23.9
680 | dev: true
681 |
682 | /@types/body-parser@1.19.5:
683 | resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==}
684 | dependencies:
685 | '@types/connect': 3.4.38
686 | '@types/node': 20.11.16
687 | dev: true
688 |
689 | /@types/connect@3.4.38:
690 | resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
691 | dependencies:
692 | '@types/node': 20.11.16
693 | dev: true
694 |
695 | /@types/cookiejar@2.1.5:
696 | resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==}
697 | dev: true
698 |
699 | /@types/express-serve-static-core@4.17.43:
700 | resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==}
701 | dependencies:
702 | '@types/node': 20.11.16
703 | '@types/qs': 6.9.11
704 | '@types/range-parser': 1.2.7
705 | '@types/send': 0.17.4
706 | dev: true
707 |
708 | /@types/express@4.17.21:
709 | resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==}
710 | dependencies:
711 | '@types/body-parser': 1.19.5
712 | '@types/express-serve-static-core': 4.17.43
713 | '@types/qs': 6.9.11
714 | '@types/serve-static': 1.15.5
715 | dev: true
716 |
717 | /@types/graceful-fs@4.1.9:
718 | resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==}
719 | dependencies:
720 | '@types/node': 20.11.16
721 | dev: true
722 |
723 | /@types/http-errors@2.0.4:
724 | resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
725 | dev: true
726 |
727 | /@types/istanbul-lib-coverage@2.0.6:
728 | resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
729 | dev: true
730 |
731 | /@types/istanbul-lib-report@3.0.3:
732 | resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==}
733 | dependencies:
734 | '@types/istanbul-lib-coverage': 2.0.6
735 | dev: true
736 |
737 | /@types/istanbul-reports@3.0.4:
738 | resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==}
739 | dependencies:
740 | '@types/istanbul-lib-report': 3.0.3
741 | dev: true
742 |
743 | /@types/jest@29.5.12:
744 | resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==}
745 | dependencies:
746 | expect: 29.7.0
747 | pretty-format: 29.7.0
748 | dev: true
749 |
750 | /@types/methods@1.1.4:
751 | resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==}
752 | dev: true
753 |
754 | /@types/mime@1.3.5:
755 | resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==}
756 | dev: true
757 |
758 | /@types/mime@3.0.4:
759 | resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==}
760 | dev: true
761 |
762 | /@types/node@20.11.16:
763 | resolution: {integrity: sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==}
764 | dependencies:
765 | undici-types: 5.26.5
766 | dev: true
767 |
768 | /@types/qs@6.9.11:
769 | resolution: {integrity: sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==}
770 | dev: true
771 |
772 | /@types/range-parser@1.2.7:
773 | resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
774 | dev: true
775 |
776 | /@types/send@0.17.4:
777 | resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==}
778 | dependencies:
779 | '@types/mime': 1.3.5
780 | '@types/node': 20.11.16
781 | dev: true
782 |
783 | /@types/serve-static@1.15.5:
784 | resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==}
785 | dependencies:
786 | '@types/http-errors': 2.0.4
787 | '@types/mime': 3.0.4
788 | '@types/node': 20.11.16
789 | dev: true
790 |
791 | /@types/stack-utils@2.0.3:
792 | resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==}
793 | dev: true
794 |
795 | /@types/superagent@8.1.3:
796 | resolution: {integrity: sha512-R/CfN6w2XsixLb1Ii8INfn+BT9sGPvw74OavfkW4SwY+jeUcAwLZv2+bXLJkndnimxjEBm0RPHgcjW9pLCa8cw==}
797 | dependencies:
798 | '@types/cookiejar': 2.1.5
799 | '@types/methods': 1.1.4
800 | '@types/node': 20.11.16
801 | dev: true
802 |
803 | /@types/supertest@6.0.2:
804 | resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==}
805 | dependencies:
806 | '@types/methods': 1.1.4
807 | '@types/superagent': 8.1.3
808 | dev: true
809 |
810 | /@types/yargs-parser@21.0.3:
811 | resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
812 | dev: true
813 |
814 | /@types/yargs@17.0.32:
815 | resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==}
816 | dependencies:
817 | '@types/yargs-parser': 21.0.3
818 | dev: true
819 |
820 | /accepts@1.3.8:
821 | resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
822 | engines: {node: '>= 0.6'}
823 | dependencies:
824 | mime-types: 2.1.35
825 | negotiator: 0.6.3
826 | dev: false
827 |
828 | /ansi-escapes@4.3.2:
829 | resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
830 | engines: {node: '>=8'}
831 | dependencies:
832 | type-fest: 0.21.3
833 | dev: true
834 |
835 | /ansi-regex@5.0.1:
836 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
837 | engines: {node: '>=8'}
838 | dev: true
839 |
840 | /ansi-styles@3.2.1:
841 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
842 | engines: {node: '>=4'}
843 | dependencies:
844 | color-convert: 1.9.3
845 | dev: true
846 |
847 | /ansi-styles@4.3.0:
848 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
849 | engines: {node: '>=8'}
850 | dependencies:
851 | color-convert: 2.0.1
852 | dev: true
853 |
854 | /ansi-styles@5.2.0:
855 | resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
856 | engines: {node: '>=10'}
857 | dev: true
858 |
859 | /anymatch@3.1.3:
860 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
861 | engines: {node: '>= 8'}
862 | dependencies:
863 | normalize-path: 3.0.0
864 | picomatch: 2.3.1
865 | dev: true
866 |
867 | /argparse@1.0.10:
868 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
869 | dependencies:
870 | sprintf-js: 1.0.3
871 | dev: true
872 |
873 | /array-flatten@1.1.1:
874 | resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==}
875 | dev: false
876 |
877 | /asap@2.0.6:
878 | resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
879 | dev: true
880 |
881 | /asynckit@0.4.0:
882 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
883 | dev: true
884 |
885 | /babel-jest@29.7.0(@babel/core@7.23.9):
886 | resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==}
887 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
888 | peerDependencies:
889 | '@babel/core': ^7.8.0
890 | dependencies:
891 | '@babel/core': 7.23.9
892 | '@jest/transform': 29.7.0
893 | '@types/babel__core': 7.20.5
894 | babel-plugin-istanbul: 6.1.1
895 | babel-preset-jest: 29.6.3(@babel/core@7.23.9)
896 | chalk: 4.1.2
897 | graceful-fs: 4.2.11
898 | slash: 3.0.0
899 | transitivePeerDependencies:
900 | - supports-color
901 | dev: true
902 |
903 | /babel-plugin-istanbul@6.1.1:
904 | resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
905 | engines: {node: '>=8'}
906 | dependencies:
907 | '@babel/helper-plugin-utils': 7.22.5
908 | '@istanbuljs/load-nyc-config': 1.1.0
909 | '@istanbuljs/schema': 0.1.3
910 | istanbul-lib-instrument: 5.2.1
911 | test-exclude: 6.0.0
912 | transitivePeerDependencies:
913 | - supports-color
914 | dev: true
915 |
916 | /babel-plugin-jest-hoist@29.6.3:
917 | resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==}
918 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
919 | dependencies:
920 | '@babel/template': 7.23.9
921 | '@babel/types': 7.23.9
922 | '@types/babel__core': 7.20.5
923 | '@types/babel__traverse': 7.20.5
924 | dev: true
925 |
926 | /babel-preset-current-node-syntax@1.0.1(@babel/core@7.23.9):
927 | resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==}
928 | peerDependencies:
929 | '@babel/core': ^7.0.0
930 | dependencies:
931 | '@babel/core': 7.23.9
932 | '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.23.9)
933 | '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.23.9)
934 | '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.23.9)
935 | '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.23.9)
936 | '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.23.9)
937 | '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.23.9)
938 | '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.23.9)
939 | '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.23.9)
940 | '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.23.9)
941 | '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.23.9)
942 | '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.23.9)
943 | '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.23.9)
944 | dev: true
945 |
946 | /babel-preset-jest@29.6.3(@babel/core@7.23.9):
947 | resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==}
948 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
949 | peerDependencies:
950 | '@babel/core': ^7.0.0
951 | dependencies:
952 | '@babel/core': 7.23.9
953 | babel-plugin-jest-hoist: 29.6.3
954 | babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.9)
955 | dev: true
956 |
957 | /balanced-match@1.0.2:
958 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
959 | dev: true
960 |
961 | /body-parser@1.20.1:
962 | resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==}
963 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
964 | dependencies:
965 | bytes: 3.1.2
966 | content-type: 1.0.5
967 | debug: 2.6.9
968 | depd: 2.0.0
969 | destroy: 1.2.0
970 | http-errors: 2.0.0
971 | iconv-lite: 0.4.24
972 | on-finished: 2.4.1
973 | qs: 6.11.0
974 | raw-body: 2.5.1
975 | type-is: 1.6.18
976 | unpipe: 1.0.0
977 | transitivePeerDependencies:
978 | - supports-color
979 | dev: false
980 |
981 | /brace-expansion@1.1.11:
982 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
983 | dependencies:
984 | balanced-match: 1.0.2
985 | concat-map: 0.0.1
986 | dev: true
987 |
988 | /braces@3.0.2:
989 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
990 | engines: {node: '>=8'}
991 | dependencies:
992 | fill-range: 7.0.1
993 | dev: true
994 |
995 | /browserslist@4.22.3:
996 | resolution: {integrity: sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==}
997 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
998 | hasBin: true
999 | dependencies:
1000 | caniuse-lite: 1.0.30001583
1001 | electron-to-chromium: 1.4.656
1002 | node-releases: 2.0.14
1003 | update-browserslist-db: 1.0.13(browserslist@4.22.3)
1004 | dev: true
1005 |
1006 | /bs-logger@0.2.6:
1007 | resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
1008 | engines: {node: '>= 6'}
1009 | dependencies:
1010 | fast-json-stable-stringify: 2.1.0
1011 | dev: true
1012 |
1013 | /bser@2.1.1:
1014 | resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
1015 | dependencies:
1016 | node-int64: 0.4.0
1017 | dev: true
1018 |
1019 | /buffer-from@1.1.2:
1020 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
1021 | dev: true
1022 |
1023 | /bytes@3.1.2:
1024 | resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
1025 | engines: {node: '>= 0.8'}
1026 | dev: false
1027 |
1028 | /call-bind@1.0.5:
1029 | resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==}
1030 | dependencies:
1031 | function-bind: 1.1.2
1032 | get-intrinsic: 1.2.2
1033 | set-function-length: 1.2.0
1034 |
1035 | /callsites@3.1.0:
1036 | resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
1037 | engines: {node: '>=6'}
1038 | dev: true
1039 |
1040 | /camelcase@5.3.1:
1041 | resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
1042 | engines: {node: '>=6'}
1043 | dev: true
1044 |
1045 | /camelcase@6.3.0:
1046 | resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
1047 | engines: {node: '>=10'}
1048 | dev: true
1049 |
1050 | /caniuse-lite@1.0.30001583:
1051 | resolution: {integrity: sha512-acWTYaha8xfhA/Du/z4sNZjHUWjkiuoAi2LM+T/aL+kemKQgPT1xBb/YKjlQ0Qo8gvbHsGNplrEJ+9G3gL7i4Q==}
1052 | dev: true
1053 |
1054 | /chalk@2.4.2:
1055 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
1056 | engines: {node: '>=4'}
1057 | dependencies:
1058 | ansi-styles: 3.2.1
1059 | escape-string-regexp: 1.0.5
1060 | supports-color: 5.5.0
1061 | dev: true
1062 |
1063 | /chalk@4.1.2:
1064 | resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
1065 | engines: {node: '>=10'}
1066 | dependencies:
1067 | ansi-styles: 4.3.0
1068 | supports-color: 7.2.0
1069 | dev: true
1070 |
1071 | /char-regex@1.0.2:
1072 | resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
1073 | engines: {node: '>=10'}
1074 | dev: true
1075 |
1076 | /ci-info@3.9.0:
1077 | resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
1078 | engines: {node: '>=8'}
1079 | dev: true
1080 |
1081 | /cjs-module-lexer@1.2.3:
1082 | resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==}
1083 | dev: true
1084 |
1085 | /cliui@8.0.1:
1086 | resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
1087 | engines: {node: '>=12'}
1088 | dependencies:
1089 | string-width: 4.2.3
1090 | strip-ansi: 6.0.1
1091 | wrap-ansi: 7.0.0
1092 | dev: true
1093 |
1094 | /co@4.6.0:
1095 | resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
1096 | engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
1097 | dev: true
1098 |
1099 | /collect-v8-coverage@1.0.2:
1100 | resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==}
1101 | dev: true
1102 |
1103 | /color-convert@1.9.3:
1104 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
1105 | dependencies:
1106 | color-name: 1.1.3
1107 | dev: true
1108 |
1109 | /color-convert@2.0.1:
1110 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
1111 | engines: {node: '>=7.0.0'}
1112 | dependencies:
1113 | color-name: 1.1.4
1114 | dev: true
1115 |
1116 | /color-name@1.1.3:
1117 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
1118 | dev: true
1119 |
1120 | /color-name@1.1.4:
1121 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
1122 | dev: true
1123 |
1124 | /combined-stream@1.0.8:
1125 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
1126 | engines: {node: '>= 0.8'}
1127 | dependencies:
1128 | delayed-stream: 1.0.0
1129 | dev: true
1130 |
1131 | /component-emitter@1.3.1:
1132 | resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==}
1133 | dev: true
1134 |
1135 | /concat-map@0.0.1:
1136 | resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
1137 | dev: true
1138 |
1139 | /content-disposition@0.5.4:
1140 | resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
1141 | engines: {node: '>= 0.6'}
1142 | dependencies:
1143 | safe-buffer: 5.2.1
1144 | dev: false
1145 |
1146 | /content-type@1.0.5:
1147 | resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
1148 | engines: {node: '>= 0.6'}
1149 | dev: false
1150 |
1151 | /convert-source-map@2.0.0:
1152 | resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
1153 | dev: true
1154 |
1155 | /cookie-signature@1.0.6:
1156 | resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==}
1157 | dev: false
1158 |
1159 | /cookie@0.5.0:
1160 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
1161 | engines: {node: '>= 0.6'}
1162 | dev: false
1163 |
1164 | /cookiejar@2.1.4:
1165 | resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==}
1166 | dev: true
1167 |
1168 | /create-jest@29.7.0:
1169 | resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==}
1170 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1171 | hasBin: true
1172 | dependencies:
1173 | '@jest/types': 29.6.3
1174 | chalk: 4.1.2
1175 | exit: 0.1.2
1176 | graceful-fs: 4.2.11
1177 | jest-config: 29.7.0(@types/node@20.11.16)
1178 | jest-util: 29.7.0
1179 | prompts: 2.4.2
1180 | transitivePeerDependencies:
1181 | - '@types/node'
1182 | - babel-plugin-macros
1183 | - supports-color
1184 | - ts-node
1185 | dev: true
1186 |
1187 | /cross-spawn@7.0.3:
1188 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
1189 | engines: {node: '>= 8'}
1190 | dependencies:
1191 | path-key: 3.1.1
1192 | shebang-command: 2.0.0
1193 | which: 2.0.2
1194 | dev: true
1195 |
1196 | /debug@2.6.9:
1197 | resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
1198 | peerDependencies:
1199 | supports-color: '*'
1200 | peerDependenciesMeta:
1201 | supports-color:
1202 | optional: true
1203 | dependencies:
1204 | ms: 2.0.0
1205 | dev: false
1206 |
1207 | /debug@4.3.4:
1208 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
1209 | engines: {node: '>=6.0'}
1210 | peerDependencies:
1211 | supports-color: '*'
1212 | peerDependenciesMeta:
1213 | supports-color:
1214 | optional: true
1215 | dependencies:
1216 | ms: 2.1.2
1217 | dev: true
1218 |
1219 | /dedent@1.5.1:
1220 | resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==}
1221 | peerDependencies:
1222 | babel-plugin-macros: ^3.1.0
1223 | peerDependenciesMeta:
1224 | babel-plugin-macros:
1225 | optional: true
1226 | dev: true
1227 |
1228 | /deepmerge@4.3.1:
1229 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
1230 | engines: {node: '>=0.10.0'}
1231 | dev: true
1232 |
1233 | /define-data-property@1.1.1:
1234 | resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==}
1235 | engines: {node: '>= 0.4'}
1236 | dependencies:
1237 | get-intrinsic: 1.2.2
1238 | gopd: 1.0.1
1239 | has-property-descriptors: 1.0.1
1240 |
1241 | /delayed-stream@1.0.0:
1242 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
1243 | engines: {node: '>=0.4.0'}
1244 | dev: true
1245 |
1246 | /depd@2.0.0:
1247 | resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
1248 | engines: {node: '>= 0.8'}
1249 | dev: false
1250 |
1251 | /destroy@1.2.0:
1252 | resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==}
1253 | engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16}
1254 | dev: false
1255 |
1256 | /detect-newline@3.1.0:
1257 | resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
1258 | engines: {node: '>=8'}
1259 | dev: true
1260 |
1261 | /dezalgo@1.0.4:
1262 | resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==}
1263 | dependencies:
1264 | asap: 2.0.6
1265 | wrappy: 1.0.2
1266 | dev: true
1267 |
1268 | /diff-sequences@29.6.3:
1269 | resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==}
1270 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1271 | dev: true
1272 |
1273 | /ee-first@1.1.1:
1274 | resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
1275 | dev: false
1276 |
1277 | /electron-to-chromium@1.4.656:
1278 | resolution: {integrity: sha512-9AQB5eFTHyR3Gvt2t/NwR0le2jBSUNwCnMbUCejFWHD+so4tH40/dRLgoE+jxlPeWS43XJewyvCv+I8LPMl49Q==}
1279 | dev: true
1280 |
1281 | /emittery@0.13.1:
1282 | resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==}
1283 | engines: {node: '>=12'}
1284 | dev: true
1285 |
1286 | /emoji-regex@8.0.0:
1287 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
1288 | dev: true
1289 |
1290 | /encodeurl@1.0.2:
1291 | resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==}
1292 | engines: {node: '>= 0.8'}
1293 | dev: false
1294 |
1295 | /error-ex@1.3.2:
1296 | resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
1297 | dependencies:
1298 | is-arrayish: 0.2.1
1299 | dev: true
1300 |
1301 | /escalade@3.1.1:
1302 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
1303 | engines: {node: '>=6'}
1304 | dev: true
1305 |
1306 | /escape-html@1.0.3:
1307 | resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
1308 | dev: false
1309 |
1310 | /escape-string-regexp@1.0.5:
1311 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
1312 | engines: {node: '>=0.8.0'}
1313 | dev: true
1314 |
1315 | /escape-string-regexp@2.0.0:
1316 | resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==}
1317 | engines: {node: '>=8'}
1318 | dev: true
1319 |
1320 | /esprima@4.0.1:
1321 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
1322 | engines: {node: '>=4'}
1323 | hasBin: true
1324 | dev: true
1325 |
1326 | /etag@1.8.1:
1327 | resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
1328 | engines: {node: '>= 0.6'}
1329 | dev: false
1330 |
1331 | /execa@5.1.1:
1332 | resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
1333 | engines: {node: '>=10'}
1334 | dependencies:
1335 | cross-spawn: 7.0.3
1336 | get-stream: 6.0.1
1337 | human-signals: 2.1.0
1338 | is-stream: 2.0.1
1339 | merge-stream: 2.0.0
1340 | npm-run-path: 4.0.1
1341 | onetime: 5.1.2
1342 | signal-exit: 3.0.7
1343 | strip-final-newline: 2.0.0
1344 | dev: true
1345 |
1346 | /exit@0.1.2:
1347 | resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==}
1348 | engines: {node: '>= 0.8.0'}
1349 | dev: true
1350 |
1351 | /expect@29.7.0:
1352 | resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
1353 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1354 | dependencies:
1355 | '@jest/expect-utils': 29.7.0
1356 | jest-get-type: 29.6.3
1357 | jest-matcher-utils: 29.7.0
1358 | jest-message-util: 29.7.0
1359 | jest-util: 29.7.0
1360 | dev: true
1361 |
1362 | /express@4.18.2:
1363 | resolution: {integrity: sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==}
1364 | engines: {node: '>= 0.10.0'}
1365 | dependencies:
1366 | accepts: 1.3.8
1367 | array-flatten: 1.1.1
1368 | body-parser: 1.20.1
1369 | content-disposition: 0.5.4
1370 | content-type: 1.0.5
1371 | cookie: 0.5.0
1372 | cookie-signature: 1.0.6
1373 | debug: 2.6.9
1374 | depd: 2.0.0
1375 | encodeurl: 1.0.2
1376 | escape-html: 1.0.3
1377 | etag: 1.8.1
1378 | finalhandler: 1.2.0
1379 | fresh: 0.5.2
1380 | http-errors: 2.0.0
1381 | merge-descriptors: 1.0.1
1382 | methods: 1.1.2
1383 | on-finished: 2.4.1
1384 | parseurl: 1.3.3
1385 | path-to-regexp: 0.1.7
1386 | proxy-addr: 2.0.7
1387 | qs: 6.11.0
1388 | range-parser: 1.2.1
1389 | safe-buffer: 5.2.1
1390 | send: 0.18.0
1391 | serve-static: 1.15.0
1392 | setprototypeof: 1.2.0
1393 | statuses: 2.0.1
1394 | type-is: 1.6.18
1395 | utils-merge: 1.0.1
1396 | vary: 1.1.2
1397 | transitivePeerDependencies:
1398 | - supports-color
1399 | dev: false
1400 |
1401 | /fast-json-stable-stringify@2.1.0:
1402 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
1403 | dev: true
1404 |
1405 | /fast-safe-stringify@2.1.1:
1406 | resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
1407 | dev: true
1408 |
1409 | /fb-watchman@2.0.2:
1410 | resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
1411 | dependencies:
1412 | bser: 2.1.1
1413 | dev: true
1414 |
1415 | /fill-range@7.0.1:
1416 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
1417 | engines: {node: '>=8'}
1418 | dependencies:
1419 | to-regex-range: 5.0.1
1420 | dev: true
1421 |
1422 | /finalhandler@1.2.0:
1423 | resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==}
1424 | engines: {node: '>= 0.8'}
1425 | dependencies:
1426 | debug: 2.6.9
1427 | encodeurl: 1.0.2
1428 | escape-html: 1.0.3
1429 | on-finished: 2.4.1
1430 | parseurl: 1.3.3
1431 | statuses: 2.0.1
1432 | unpipe: 1.0.0
1433 | transitivePeerDependencies:
1434 | - supports-color
1435 | dev: false
1436 |
1437 | /find-up@4.1.0:
1438 | resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
1439 | engines: {node: '>=8'}
1440 | dependencies:
1441 | locate-path: 5.0.0
1442 | path-exists: 4.0.0
1443 | dev: true
1444 |
1445 | /form-data@4.0.0:
1446 | resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
1447 | engines: {node: '>= 6'}
1448 | dependencies:
1449 | asynckit: 0.4.0
1450 | combined-stream: 1.0.8
1451 | mime-types: 2.1.35
1452 | dev: true
1453 |
1454 | /formidable@2.1.2:
1455 | resolution: {integrity: sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==}
1456 | dependencies:
1457 | dezalgo: 1.0.4
1458 | hexoid: 1.0.0
1459 | once: 1.4.0
1460 | qs: 6.11.2
1461 | dev: true
1462 |
1463 | /forwarded@0.2.0:
1464 | resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
1465 | engines: {node: '>= 0.6'}
1466 | dev: false
1467 |
1468 | /fresh@0.5.2:
1469 | resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==}
1470 | engines: {node: '>= 0.6'}
1471 | dev: false
1472 |
1473 | /fs.realpath@1.0.0:
1474 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
1475 | dev: true
1476 |
1477 | /fsevents@2.3.3:
1478 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
1479 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
1480 | os: [darwin]
1481 | requiresBuild: true
1482 | dev: true
1483 | optional: true
1484 |
1485 | /function-bind@1.1.2:
1486 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
1487 |
1488 | /gensync@1.0.0-beta.2:
1489 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
1490 | engines: {node: '>=6.9.0'}
1491 | dev: true
1492 |
1493 | /get-caller-file@2.0.5:
1494 | resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
1495 | engines: {node: 6.* || 8.* || >= 10.*}
1496 | dev: true
1497 |
1498 | /get-intrinsic@1.2.2:
1499 | resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==}
1500 | dependencies:
1501 | function-bind: 1.1.2
1502 | has-proto: 1.0.1
1503 | has-symbols: 1.0.3
1504 | hasown: 2.0.0
1505 |
1506 | /get-package-type@0.1.0:
1507 | resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
1508 | engines: {node: '>=8.0.0'}
1509 | dev: true
1510 |
1511 | /get-stream@6.0.1:
1512 | resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
1513 | engines: {node: '>=10'}
1514 | dev: true
1515 |
1516 | /glob@7.2.3:
1517 | resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
1518 | dependencies:
1519 | fs.realpath: 1.0.0
1520 | inflight: 1.0.6
1521 | inherits: 2.0.4
1522 | minimatch: 3.1.2
1523 | once: 1.4.0
1524 | path-is-absolute: 1.0.1
1525 | dev: true
1526 |
1527 | /globals@11.12.0:
1528 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
1529 | engines: {node: '>=4'}
1530 | dev: true
1531 |
1532 | /gopd@1.0.1:
1533 | resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
1534 | dependencies:
1535 | get-intrinsic: 1.2.2
1536 |
1537 | /graceful-fs@4.2.11:
1538 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
1539 | dev: true
1540 |
1541 | /has-flag@3.0.0:
1542 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
1543 | engines: {node: '>=4'}
1544 | dev: true
1545 |
1546 | /has-flag@4.0.0:
1547 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
1548 | engines: {node: '>=8'}
1549 | dev: true
1550 |
1551 | /has-property-descriptors@1.0.1:
1552 | resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==}
1553 | dependencies:
1554 | get-intrinsic: 1.2.2
1555 |
1556 | /has-proto@1.0.1:
1557 | resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==}
1558 | engines: {node: '>= 0.4'}
1559 |
1560 | /has-symbols@1.0.3:
1561 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
1562 | engines: {node: '>= 0.4'}
1563 |
1564 | /hasown@2.0.0:
1565 | resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==}
1566 | engines: {node: '>= 0.4'}
1567 | dependencies:
1568 | function-bind: 1.1.2
1569 |
1570 | /hexoid@1.0.0:
1571 | resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==}
1572 | engines: {node: '>=8'}
1573 | dev: true
1574 |
1575 | /html-escaper@2.0.2:
1576 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
1577 | dev: true
1578 |
1579 | /http-errors@2.0.0:
1580 | resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
1581 | engines: {node: '>= 0.8'}
1582 | dependencies:
1583 | depd: 2.0.0
1584 | inherits: 2.0.4
1585 | setprototypeof: 1.2.0
1586 | statuses: 2.0.1
1587 | toidentifier: 1.0.1
1588 | dev: false
1589 |
1590 | /human-signals@2.1.0:
1591 | resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
1592 | engines: {node: '>=10.17.0'}
1593 | dev: true
1594 |
1595 | /iconv-lite@0.4.24:
1596 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
1597 | engines: {node: '>=0.10.0'}
1598 | dependencies:
1599 | safer-buffer: 2.1.2
1600 | dev: false
1601 |
1602 | /import-local@3.1.0:
1603 | resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==}
1604 | engines: {node: '>=8'}
1605 | hasBin: true
1606 | dependencies:
1607 | pkg-dir: 4.2.0
1608 | resolve-cwd: 3.0.0
1609 | dev: true
1610 |
1611 | /imurmurhash@0.1.4:
1612 | resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
1613 | engines: {node: '>=0.8.19'}
1614 | dev: true
1615 |
1616 | /inflight@1.0.6:
1617 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
1618 | dependencies:
1619 | once: 1.4.0
1620 | wrappy: 1.0.2
1621 | dev: true
1622 |
1623 | /inherits@2.0.4:
1624 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
1625 |
1626 | /ipaddr.js@1.9.1:
1627 | resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
1628 | engines: {node: '>= 0.10'}
1629 | dev: false
1630 |
1631 | /is-arrayish@0.2.1:
1632 | resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
1633 | dev: true
1634 |
1635 | /is-core-module@2.13.1:
1636 | resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==}
1637 | dependencies:
1638 | hasown: 2.0.0
1639 | dev: true
1640 |
1641 | /is-fullwidth-code-point@3.0.0:
1642 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
1643 | engines: {node: '>=8'}
1644 | dev: true
1645 |
1646 | /is-generator-fn@2.1.0:
1647 | resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
1648 | engines: {node: '>=6'}
1649 | dev: true
1650 |
1651 | /is-number@7.0.0:
1652 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
1653 | engines: {node: '>=0.12.0'}
1654 | dev: true
1655 |
1656 | /is-stream@2.0.1:
1657 | resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
1658 | engines: {node: '>=8'}
1659 | dev: true
1660 |
1661 | /isexe@2.0.0:
1662 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
1663 | dev: true
1664 |
1665 | /istanbul-lib-coverage@3.2.2:
1666 | resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==}
1667 | engines: {node: '>=8'}
1668 | dev: true
1669 |
1670 | /istanbul-lib-instrument@5.2.1:
1671 | resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==}
1672 | engines: {node: '>=8'}
1673 | dependencies:
1674 | '@babel/core': 7.23.9
1675 | '@babel/parser': 7.23.9
1676 | '@istanbuljs/schema': 0.1.3
1677 | istanbul-lib-coverage: 3.2.2
1678 | semver: 6.3.1
1679 | transitivePeerDependencies:
1680 | - supports-color
1681 | dev: true
1682 |
1683 | /istanbul-lib-instrument@6.0.1:
1684 | resolution: {integrity: sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==}
1685 | engines: {node: '>=10'}
1686 | dependencies:
1687 | '@babel/core': 7.23.9
1688 | '@babel/parser': 7.23.9
1689 | '@istanbuljs/schema': 0.1.3
1690 | istanbul-lib-coverage: 3.2.2
1691 | semver: 7.5.4
1692 | transitivePeerDependencies:
1693 | - supports-color
1694 | dev: true
1695 |
1696 | /istanbul-lib-report@3.0.1:
1697 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==}
1698 | engines: {node: '>=10'}
1699 | dependencies:
1700 | istanbul-lib-coverage: 3.2.2
1701 | make-dir: 4.0.0
1702 | supports-color: 7.2.0
1703 | dev: true
1704 |
1705 | /istanbul-lib-source-maps@4.0.1:
1706 | resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
1707 | engines: {node: '>=10'}
1708 | dependencies:
1709 | debug: 4.3.4
1710 | istanbul-lib-coverage: 3.2.2
1711 | source-map: 0.6.1
1712 | transitivePeerDependencies:
1713 | - supports-color
1714 | dev: true
1715 |
1716 | /istanbul-reports@3.1.6:
1717 | resolution: {integrity: sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==}
1718 | engines: {node: '>=8'}
1719 | dependencies:
1720 | html-escaper: 2.0.2
1721 | istanbul-lib-report: 3.0.1
1722 | dev: true
1723 |
1724 | /jest-changed-files@29.7.0:
1725 | resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
1726 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1727 | dependencies:
1728 | execa: 5.1.1
1729 | jest-util: 29.7.0
1730 | p-limit: 3.1.0
1731 | dev: true
1732 |
1733 | /jest-circus@29.7.0:
1734 | resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==}
1735 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1736 | dependencies:
1737 | '@jest/environment': 29.7.0
1738 | '@jest/expect': 29.7.0
1739 | '@jest/test-result': 29.7.0
1740 | '@jest/types': 29.6.3
1741 | '@types/node': 20.11.16
1742 | chalk: 4.1.2
1743 | co: 4.6.0
1744 | dedent: 1.5.1
1745 | is-generator-fn: 2.1.0
1746 | jest-each: 29.7.0
1747 | jest-matcher-utils: 29.7.0
1748 | jest-message-util: 29.7.0
1749 | jest-runtime: 29.7.0
1750 | jest-snapshot: 29.7.0
1751 | jest-util: 29.7.0
1752 | p-limit: 3.1.0
1753 | pretty-format: 29.7.0
1754 | pure-rand: 6.0.4
1755 | slash: 3.0.0
1756 | stack-utils: 2.0.6
1757 | transitivePeerDependencies:
1758 | - babel-plugin-macros
1759 | - supports-color
1760 | dev: true
1761 |
1762 | /jest-cli@29.7.0:
1763 | resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==}
1764 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1765 | hasBin: true
1766 | peerDependencies:
1767 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
1768 | peerDependenciesMeta:
1769 | node-notifier:
1770 | optional: true
1771 | dependencies:
1772 | '@jest/core': 29.7.0
1773 | '@jest/test-result': 29.7.0
1774 | '@jest/types': 29.6.3
1775 | chalk: 4.1.2
1776 | create-jest: 29.7.0
1777 | exit: 0.1.2
1778 | import-local: 3.1.0
1779 | jest-config: 29.7.0(@types/node@20.11.16)
1780 | jest-util: 29.7.0
1781 | jest-validate: 29.7.0
1782 | yargs: 17.7.2
1783 | transitivePeerDependencies:
1784 | - '@types/node'
1785 | - babel-plugin-macros
1786 | - supports-color
1787 | - ts-node
1788 | dev: true
1789 |
1790 | /jest-config@29.7.0(@types/node@20.11.16):
1791 | resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==}
1792 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1793 | peerDependencies:
1794 | '@types/node': '*'
1795 | ts-node: '>=9.0.0'
1796 | peerDependenciesMeta:
1797 | '@types/node':
1798 | optional: true
1799 | ts-node:
1800 | optional: true
1801 | dependencies:
1802 | '@babel/core': 7.23.9
1803 | '@jest/test-sequencer': 29.7.0
1804 | '@jest/types': 29.6.3
1805 | '@types/node': 20.11.16
1806 | babel-jest: 29.7.0(@babel/core@7.23.9)
1807 | chalk: 4.1.2
1808 | ci-info: 3.9.0
1809 | deepmerge: 4.3.1
1810 | glob: 7.2.3
1811 | graceful-fs: 4.2.11
1812 | jest-circus: 29.7.0
1813 | jest-environment-node: 29.7.0
1814 | jest-get-type: 29.6.3
1815 | jest-regex-util: 29.6.3
1816 | jest-resolve: 29.7.0
1817 | jest-runner: 29.7.0
1818 | jest-util: 29.7.0
1819 | jest-validate: 29.7.0
1820 | micromatch: 4.0.5
1821 | parse-json: 5.2.0
1822 | pretty-format: 29.7.0
1823 | slash: 3.0.0
1824 | strip-json-comments: 3.1.1
1825 | transitivePeerDependencies:
1826 | - babel-plugin-macros
1827 | - supports-color
1828 | dev: true
1829 |
1830 | /jest-diff@29.7.0:
1831 | resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==}
1832 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1833 | dependencies:
1834 | chalk: 4.1.2
1835 | diff-sequences: 29.6.3
1836 | jest-get-type: 29.6.3
1837 | pretty-format: 29.7.0
1838 | dev: true
1839 |
1840 | /jest-docblock@29.7.0:
1841 | resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==}
1842 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1843 | dependencies:
1844 | detect-newline: 3.1.0
1845 | dev: true
1846 |
1847 | /jest-each@29.7.0:
1848 | resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==}
1849 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1850 | dependencies:
1851 | '@jest/types': 29.6.3
1852 | chalk: 4.1.2
1853 | jest-get-type: 29.6.3
1854 | jest-util: 29.7.0
1855 | pretty-format: 29.7.0
1856 | dev: true
1857 |
1858 | /jest-environment-node@29.7.0:
1859 | resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==}
1860 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1861 | dependencies:
1862 | '@jest/environment': 29.7.0
1863 | '@jest/fake-timers': 29.7.0
1864 | '@jest/types': 29.6.3
1865 | '@types/node': 20.11.16
1866 | jest-mock: 29.7.0
1867 | jest-util: 29.7.0
1868 | dev: true
1869 |
1870 | /jest-get-type@29.6.3:
1871 | resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==}
1872 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1873 | dev: true
1874 |
1875 | /jest-haste-map@29.7.0:
1876 | resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==}
1877 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1878 | dependencies:
1879 | '@jest/types': 29.6.3
1880 | '@types/graceful-fs': 4.1.9
1881 | '@types/node': 20.11.16
1882 | anymatch: 3.1.3
1883 | fb-watchman: 2.0.2
1884 | graceful-fs: 4.2.11
1885 | jest-regex-util: 29.6.3
1886 | jest-util: 29.7.0
1887 | jest-worker: 29.7.0
1888 | micromatch: 4.0.5
1889 | walker: 1.0.8
1890 | optionalDependencies:
1891 | fsevents: 2.3.3
1892 | dev: true
1893 |
1894 | /jest-leak-detector@29.7.0:
1895 | resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==}
1896 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1897 | dependencies:
1898 | jest-get-type: 29.6.3
1899 | pretty-format: 29.7.0
1900 | dev: true
1901 |
1902 | /jest-matcher-utils@29.7.0:
1903 | resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==}
1904 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1905 | dependencies:
1906 | chalk: 4.1.2
1907 | jest-diff: 29.7.0
1908 | jest-get-type: 29.6.3
1909 | pretty-format: 29.7.0
1910 | dev: true
1911 |
1912 | /jest-message-util@29.7.0:
1913 | resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==}
1914 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1915 | dependencies:
1916 | '@babel/code-frame': 7.23.5
1917 | '@jest/types': 29.6.3
1918 | '@types/stack-utils': 2.0.3
1919 | chalk: 4.1.2
1920 | graceful-fs: 4.2.11
1921 | micromatch: 4.0.5
1922 | pretty-format: 29.7.0
1923 | slash: 3.0.0
1924 | stack-utils: 2.0.6
1925 | dev: true
1926 |
1927 | /jest-mock@29.7.0:
1928 | resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==}
1929 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1930 | dependencies:
1931 | '@jest/types': 29.6.3
1932 | '@types/node': 20.11.16
1933 | jest-util: 29.7.0
1934 | dev: true
1935 |
1936 | /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0):
1937 | resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==}
1938 | engines: {node: '>=6'}
1939 | peerDependencies:
1940 | jest-resolve: '*'
1941 | peerDependenciesMeta:
1942 | jest-resolve:
1943 | optional: true
1944 | dependencies:
1945 | jest-resolve: 29.7.0
1946 | dev: true
1947 |
1948 | /jest-regex-util@29.6.3:
1949 | resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==}
1950 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1951 | dev: true
1952 |
1953 | /jest-resolve-dependencies@29.7.0:
1954 | resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==}
1955 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1956 | dependencies:
1957 | jest-regex-util: 29.6.3
1958 | jest-snapshot: 29.7.0
1959 | transitivePeerDependencies:
1960 | - supports-color
1961 | dev: true
1962 |
1963 | /jest-resolve@29.7.0:
1964 | resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==}
1965 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1966 | dependencies:
1967 | chalk: 4.1.2
1968 | graceful-fs: 4.2.11
1969 | jest-haste-map: 29.7.0
1970 | jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0)
1971 | jest-util: 29.7.0
1972 | jest-validate: 29.7.0
1973 | resolve: 1.22.8
1974 | resolve.exports: 2.0.2
1975 | slash: 3.0.0
1976 | dev: true
1977 |
1978 | /jest-runner@29.7.0:
1979 | resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==}
1980 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
1981 | dependencies:
1982 | '@jest/console': 29.7.0
1983 | '@jest/environment': 29.7.0
1984 | '@jest/test-result': 29.7.0
1985 | '@jest/transform': 29.7.0
1986 | '@jest/types': 29.6.3
1987 | '@types/node': 20.11.16
1988 | chalk: 4.1.2
1989 | emittery: 0.13.1
1990 | graceful-fs: 4.2.11
1991 | jest-docblock: 29.7.0
1992 | jest-environment-node: 29.7.0
1993 | jest-haste-map: 29.7.0
1994 | jest-leak-detector: 29.7.0
1995 | jest-message-util: 29.7.0
1996 | jest-resolve: 29.7.0
1997 | jest-runtime: 29.7.0
1998 | jest-util: 29.7.0
1999 | jest-watcher: 29.7.0
2000 | jest-worker: 29.7.0
2001 | p-limit: 3.1.0
2002 | source-map-support: 0.5.13
2003 | transitivePeerDependencies:
2004 | - supports-color
2005 | dev: true
2006 |
2007 | /jest-runtime@29.7.0:
2008 | resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==}
2009 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2010 | dependencies:
2011 | '@jest/environment': 29.7.0
2012 | '@jest/fake-timers': 29.7.0
2013 | '@jest/globals': 29.7.0
2014 | '@jest/source-map': 29.6.3
2015 | '@jest/test-result': 29.7.0
2016 | '@jest/transform': 29.7.0
2017 | '@jest/types': 29.6.3
2018 | '@types/node': 20.11.16
2019 | chalk: 4.1.2
2020 | cjs-module-lexer: 1.2.3
2021 | collect-v8-coverage: 1.0.2
2022 | glob: 7.2.3
2023 | graceful-fs: 4.2.11
2024 | jest-haste-map: 29.7.0
2025 | jest-message-util: 29.7.0
2026 | jest-mock: 29.7.0
2027 | jest-regex-util: 29.6.3
2028 | jest-resolve: 29.7.0
2029 | jest-snapshot: 29.7.0
2030 | jest-util: 29.7.0
2031 | slash: 3.0.0
2032 | strip-bom: 4.0.0
2033 | transitivePeerDependencies:
2034 | - supports-color
2035 | dev: true
2036 |
2037 | /jest-snapshot@29.7.0:
2038 | resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
2039 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2040 | dependencies:
2041 | '@babel/core': 7.23.9
2042 | '@babel/generator': 7.23.6
2043 | '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.9)
2044 | '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.9)
2045 | '@babel/types': 7.23.9
2046 | '@jest/expect-utils': 29.7.0
2047 | '@jest/transform': 29.7.0
2048 | '@jest/types': 29.6.3
2049 | babel-preset-current-node-syntax: 1.0.1(@babel/core@7.23.9)
2050 | chalk: 4.1.2
2051 | expect: 29.7.0
2052 | graceful-fs: 4.2.11
2053 | jest-diff: 29.7.0
2054 | jest-get-type: 29.6.3
2055 | jest-matcher-utils: 29.7.0
2056 | jest-message-util: 29.7.0
2057 | jest-util: 29.7.0
2058 | natural-compare: 1.4.0
2059 | pretty-format: 29.7.0
2060 | semver: 7.5.4
2061 | transitivePeerDependencies:
2062 | - supports-color
2063 | dev: true
2064 |
2065 | /jest-util@29.7.0:
2066 | resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
2067 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2068 | dependencies:
2069 | '@jest/types': 29.6.3
2070 | '@types/node': 20.11.16
2071 | chalk: 4.1.2
2072 | ci-info: 3.9.0
2073 | graceful-fs: 4.2.11
2074 | picomatch: 2.3.1
2075 | dev: true
2076 |
2077 | /jest-validate@29.7.0:
2078 | resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==}
2079 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2080 | dependencies:
2081 | '@jest/types': 29.6.3
2082 | camelcase: 6.3.0
2083 | chalk: 4.1.2
2084 | jest-get-type: 29.6.3
2085 | leven: 3.1.0
2086 | pretty-format: 29.7.0
2087 | dev: true
2088 |
2089 | /jest-watcher@29.7.0:
2090 | resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==}
2091 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2092 | dependencies:
2093 | '@jest/test-result': 29.7.0
2094 | '@jest/types': 29.6.3
2095 | '@types/node': 20.11.16
2096 | ansi-escapes: 4.3.2
2097 | chalk: 4.1.2
2098 | emittery: 0.13.1
2099 | jest-util: 29.7.0
2100 | string-length: 4.0.2
2101 | dev: true
2102 |
2103 | /jest-worker@29.7.0:
2104 | resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==}
2105 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2106 | dependencies:
2107 | '@types/node': 20.11.16
2108 | jest-util: 29.7.0
2109 | merge-stream: 2.0.0
2110 | supports-color: 8.1.1
2111 | dev: true
2112 |
2113 | /jest@29.7.0:
2114 | resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==}
2115 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2116 | hasBin: true
2117 | peerDependencies:
2118 | node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0
2119 | peerDependenciesMeta:
2120 | node-notifier:
2121 | optional: true
2122 | dependencies:
2123 | '@jest/core': 29.7.0
2124 | '@jest/types': 29.6.3
2125 | import-local: 3.1.0
2126 | jest-cli: 29.7.0
2127 | transitivePeerDependencies:
2128 | - '@types/node'
2129 | - babel-plugin-macros
2130 | - supports-color
2131 | - ts-node
2132 | dev: true
2133 |
2134 | /js-tokens@4.0.0:
2135 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
2136 | dev: true
2137 |
2138 | /js-yaml@3.14.1:
2139 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
2140 | hasBin: true
2141 | dependencies:
2142 | argparse: 1.0.10
2143 | esprima: 4.0.1
2144 | dev: true
2145 |
2146 | /jsesc@2.5.2:
2147 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
2148 | engines: {node: '>=4'}
2149 | hasBin: true
2150 | dev: true
2151 |
2152 | /json-parse-even-better-errors@2.3.1:
2153 | resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
2154 | dev: true
2155 |
2156 | /json5@2.2.3:
2157 | resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
2158 | engines: {node: '>=6'}
2159 | hasBin: true
2160 | dev: true
2161 |
2162 | /kleur@3.0.3:
2163 | resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
2164 | engines: {node: '>=6'}
2165 | dev: true
2166 |
2167 | /leven@3.1.0:
2168 | resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==}
2169 | engines: {node: '>=6'}
2170 | dev: true
2171 |
2172 | /lines-and-columns@1.2.4:
2173 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
2174 | dev: true
2175 |
2176 | /locate-path@5.0.0:
2177 | resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
2178 | engines: {node: '>=8'}
2179 | dependencies:
2180 | p-locate: 4.1.0
2181 | dev: true
2182 |
2183 | /lodash.memoize@4.1.2:
2184 | resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
2185 | dev: true
2186 |
2187 | /lru-cache@5.1.1:
2188 | resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
2189 | dependencies:
2190 | yallist: 3.1.1
2191 | dev: true
2192 |
2193 | /lru-cache@6.0.0:
2194 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
2195 | engines: {node: '>=10'}
2196 | dependencies:
2197 | yallist: 4.0.0
2198 | dev: true
2199 |
2200 | /make-dir@4.0.0:
2201 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
2202 | engines: {node: '>=10'}
2203 | dependencies:
2204 | semver: 7.5.4
2205 | dev: true
2206 |
2207 | /make-error@1.3.6:
2208 | resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
2209 | dev: true
2210 |
2211 | /makeerror@1.0.12:
2212 | resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
2213 | dependencies:
2214 | tmpl: 1.0.5
2215 | dev: true
2216 |
2217 | /media-typer@0.3.0:
2218 | resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
2219 | engines: {node: '>= 0.6'}
2220 | dev: false
2221 |
2222 | /merge-descriptors@1.0.1:
2223 | resolution: {integrity: sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==}
2224 | dev: false
2225 |
2226 | /merge-stream@2.0.0:
2227 | resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
2228 | dev: true
2229 |
2230 | /methods@1.1.2:
2231 | resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==}
2232 | engines: {node: '>= 0.6'}
2233 |
2234 | /micromatch@4.0.5:
2235 | resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
2236 | engines: {node: '>=8.6'}
2237 | dependencies:
2238 | braces: 3.0.2
2239 | picomatch: 2.3.1
2240 | dev: true
2241 |
2242 | /mime-db@1.52.0:
2243 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
2244 | engines: {node: '>= 0.6'}
2245 |
2246 | /mime-types@2.1.35:
2247 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
2248 | engines: {node: '>= 0.6'}
2249 | dependencies:
2250 | mime-db: 1.52.0
2251 |
2252 | /mime@1.6.0:
2253 | resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
2254 | engines: {node: '>=4'}
2255 | hasBin: true
2256 | dev: false
2257 |
2258 | /mime@2.6.0:
2259 | resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
2260 | engines: {node: '>=4.0.0'}
2261 | hasBin: true
2262 | dev: true
2263 |
2264 | /mimic-fn@2.1.0:
2265 | resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
2266 | engines: {node: '>=6'}
2267 | dev: true
2268 |
2269 | /minimatch@3.1.2:
2270 | resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
2271 | dependencies:
2272 | brace-expansion: 1.1.11
2273 | dev: true
2274 |
2275 | /ms@2.0.0:
2276 | resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
2277 | dev: false
2278 |
2279 | /ms@2.1.2:
2280 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
2281 | dev: true
2282 |
2283 | /ms@2.1.3:
2284 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
2285 | dev: false
2286 |
2287 | /natural-compare@1.4.0:
2288 | resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
2289 | dev: true
2290 |
2291 | /negotiator@0.6.3:
2292 | resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
2293 | engines: {node: '>= 0.6'}
2294 | dev: false
2295 |
2296 | /node-int64@0.4.0:
2297 | resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==}
2298 | dev: true
2299 |
2300 | /node-releases@2.0.14:
2301 | resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
2302 | dev: true
2303 |
2304 | /normalize-path@3.0.0:
2305 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
2306 | engines: {node: '>=0.10.0'}
2307 | dev: true
2308 |
2309 | /npm-run-path@4.0.1:
2310 | resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
2311 | engines: {node: '>=8'}
2312 | dependencies:
2313 | path-key: 3.1.1
2314 | dev: true
2315 |
2316 | /object-inspect@1.13.1:
2317 | resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
2318 |
2319 | /on-finished@2.4.1:
2320 | resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
2321 | engines: {node: '>= 0.8'}
2322 | dependencies:
2323 | ee-first: 1.1.1
2324 | dev: false
2325 |
2326 | /once@1.4.0:
2327 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
2328 | dependencies:
2329 | wrappy: 1.0.2
2330 | dev: true
2331 |
2332 | /onetime@5.1.2:
2333 | resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
2334 | engines: {node: '>=6'}
2335 | dependencies:
2336 | mimic-fn: 2.1.0
2337 | dev: true
2338 |
2339 | /p-limit@2.3.0:
2340 | resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
2341 | engines: {node: '>=6'}
2342 | dependencies:
2343 | p-try: 2.2.0
2344 | dev: true
2345 |
2346 | /p-limit@3.1.0:
2347 | resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
2348 | engines: {node: '>=10'}
2349 | dependencies:
2350 | yocto-queue: 0.1.0
2351 | dev: true
2352 |
2353 | /p-locate@4.1.0:
2354 | resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
2355 | engines: {node: '>=8'}
2356 | dependencies:
2357 | p-limit: 2.3.0
2358 | dev: true
2359 |
2360 | /p-try@2.2.0:
2361 | resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
2362 | engines: {node: '>=6'}
2363 | dev: true
2364 |
2365 | /parse-json@5.2.0:
2366 | resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
2367 | engines: {node: '>=8'}
2368 | dependencies:
2369 | '@babel/code-frame': 7.23.5
2370 | error-ex: 1.3.2
2371 | json-parse-even-better-errors: 2.3.1
2372 | lines-and-columns: 1.2.4
2373 | dev: true
2374 |
2375 | /parseurl@1.3.3:
2376 | resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
2377 | engines: {node: '>= 0.8'}
2378 | dev: false
2379 |
2380 | /path-exists@4.0.0:
2381 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
2382 | engines: {node: '>=8'}
2383 | dev: true
2384 |
2385 | /path-is-absolute@1.0.1:
2386 | resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
2387 | engines: {node: '>=0.10.0'}
2388 | dev: true
2389 |
2390 | /path-key@3.1.1:
2391 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
2392 | engines: {node: '>=8'}
2393 | dev: true
2394 |
2395 | /path-parse@1.0.7:
2396 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
2397 | dev: true
2398 |
2399 | /path-to-regexp@0.1.7:
2400 | resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
2401 | dev: false
2402 |
2403 | /picocolors@1.0.0:
2404 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
2405 | dev: true
2406 |
2407 | /picomatch@2.3.1:
2408 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
2409 | engines: {node: '>=8.6'}
2410 | dev: true
2411 |
2412 | /pirates@4.0.6:
2413 | resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
2414 | engines: {node: '>= 6'}
2415 | dev: true
2416 |
2417 | /pkg-dir@4.2.0:
2418 | resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
2419 | engines: {node: '>=8'}
2420 | dependencies:
2421 | find-up: 4.1.0
2422 | dev: true
2423 |
2424 | /pretty-format@29.7.0:
2425 | resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
2426 | engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
2427 | dependencies:
2428 | '@jest/schemas': 29.6.3
2429 | ansi-styles: 5.2.0
2430 | react-is: 18.2.0
2431 | dev: true
2432 |
2433 | /prompts@2.4.2:
2434 | resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
2435 | engines: {node: '>= 6'}
2436 | dependencies:
2437 | kleur: 3.0.3
2438 | sisteransi: 1.0.5
2439 | dev: true
2440 |
2441 | /proxy-addr@2.0.7:
2442 | resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
2443 | engines: {node: '>= 0.10'}
2444 | dependencies:
2445 | forwarded: 0.2.0
2446 | ipaddr.js: 1.9.1
2447 | dev: false
2448 |
2449 | /pure-rand@6.0.4:
2450 | resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==}
2451 | dev: true
2452 |
2453 | /qs@6.11.0:
2454 | resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==}
2455 | engines: {node: '>=0.6'}
2456 | dependencies:
2457 | side-channel: 1.0.4
2458 | dev: false
2459 |
2460 | /qs@6.11.2:
2461 | resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==}
2462 | engines: {node: '>=0.6'}
2463 | dependencies:
2464 | side-channel: 1.0.4
2465 | dev: true
2466 |
2467 | /range-parser@1.2.1:
2468 | resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
2469 | engines: {node: '>= 0.6'}
2470 | dev: false
2471 |
2472 | /raw-body@2.5.1:
2473 | resolution: {integrity: sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==}
2474 | engines: {node: '>= 0.8'}
2475 | dependencies:
2476 | bytes: 3.1.2
2477 | http-errors: 2.0.0
2478 | iconv-lite: 0.4.24
2479 | unpipe: 1.0.0
2480 | dev: false
2481 |
2482 | /react-is@18.2.0:
2483 | resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==}
2484 | dev: true
2485 |
2486 | /require-directory@2.1.1:
2487 | resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
2488 | engines: {node: '>=0.10.0'}
2489 | dev: true
2490 |
2491 | /resolve-cwd@3.0.0:
2492 | resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
2493 | engines: {node: '>=8'}
2494 | dependencies:
2495 | resolve-from: 5.0.0
2496 | dev: true
2497 |
2498 | /resolve-from@5.0.0:
2499 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
2500 | engines: {node: '>=8'}
2501 | dev: true
2502 |
2503 | /resolve.exports@2.0.2:
2504 | resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==}
2505 | engines: {node: '>=10'}
2506 | dev: true
2507 |
2508 | /resolve@1.22.8:
2509 | resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
2510 | hasBin: true
2511 | dependencies:
2512 | is-core-module: 2.13.1
2513 | path-parse: 1.0.7
2514 | supports-preserve-symlinks-flag: 1.0.0
2515 | dev: true
2516 |
2517 | /safe-buffer@5.2.1:
2518 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
2519 | dev: false
2520 |
2521 | /safer-buffer@2.1.2:
2522 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
2523 | dev: false
2524 |
2525 | /semver@6.3.1:
2526 | resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
2527 | hasBin: true
2528 | dev: true
2529 |
2530 | /semver@7.5.4:
2531 | resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
2532 | engines: {node: '>=10'}
2533 | hasBin: true
2534 | dependencies:
2535 | lru-cache: 6.0.0
2536 | dev: true
2537 |
2538 | /send@0.18.0:
2539 | resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==}
2540 | engines: {node: '>= 0.8.0'}
2541 | dependencies:
2542 | debug: 2.6.9
2543 | depd: 2.0.0
2544 | destroy: 1.2.0
2545 | encodeurl: 1.0.2
2546 | escape-html: 1.0.3
2547 | etag: 1.8.1
2548 | fresh: 0.5.2
2549 | http-errors: 2.0.0
2550 | mime: 1.6.0
2551 | ms: 2.1.3
2552 | on-finished: 2.4.1
2553 | range-parser: 1.2.1
2554 | statuses: 2.0.1
2555 | transitivePeerDependencies:
2556 | - supports-color
2557 | dev: false
2558 |
2559 | /serve-static@1.15.0:
2560 | resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==}
2561 | engines: {node: '>= 0.8.0'}
2562 | dependencies:
2563 | encodeurl: 1.0.2
2564 | escape-html: 1.0.3
2565 | parseurl: 1.3.3
2566 | send: 0.18.0
2567 | transitivePeerDependencies:
2568 | - supports-color
2569 | dev: false
2570 |
2571 | /set-function-length@1.2.0:
2572 | resolution: {integrity: sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==}
2573 | engines: {node: '>= 0.4'}
2574 | dependencies:
2575 | define-data-property: 1.1.1
2576 | function-bind: 1.1.2
2577 | get-intrinsic: 1.2.2
2578 | gopd: 1.0.1
2579 | has-property-descriptors: 1.0.1
2580 |
2581 | /setprototypeof@1.2.0:
2582 | resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
2583 | dev: false
2584 |
2585 | /shebang-command@2.0.0:
2586 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
2587 | engines: {node: '>=8'}
2588 | dependencies:
2589 | shebang-regex: 3.0.0
2590 | dev: true
2591 |
2592 | /shebang-regex@3.0.0:
2593 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
2594 | engines: {node: '>=8'}
2595 | dev: true
2596 |
2597 | /side-channel@1.0.4:
2598 | resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
2599 | dependencies:
2600 | call-bind: 1.0.5
2601 | get-intrinsic: 1.2.2
2602 | object-inspect: 1.13.1
2603 |
2604 | /signal-exit@3.0.7:
2605 | resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
2606 | dev: true
2607 |
2608 | /sisteransi@1.0.5:
2609 | resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
2610 | dev: true
2611 |
2612 | /slash@3.0.0:
2613 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
2614 | engines: {node: '>=8'}
2615 | dev: true
2616 |
2617 | /source-map-support@0.5.13:
2618 | resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==}
2619 | dependencies:
2620 | buffer-from: 1.1.2
2621 | source-map: 0.6.1
2622 | dev: true
2623 |
2624 | /source-map@0.6.1:
2625 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
2626 | engines: {node: '>=0.10.0'}
2627 | dev: true
2628 |
2629 | /sprintf-js@1.0.3:
2630 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
2631 | dev: true
2632 |
2633 | /stack-utils@2.0.6:
2634 | resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
2635 | engines: {node: '>=10'}
2636 | dependencies:
2637 | escape-string-regexp: 2.0.0
2638 | dev: true
2639 |
2640 | /statuses@2.0.1:
2641 | resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
2642 | engines: {node: '>= 0.8'}
2643 | dev: false
2644 |
2645 | /string-length@4.0.2:
2646 | resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
2647 | engines: {node: '>=10'}
2648 | dependencies:
2649 | char-regex: 1.0.2
2650 | strip-ansi: 6.0.1
2651 | dev: true
2652 |
2653 | /string-width@4.2.3:
2654 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
2655 | engines: {node: '>=8'}
2656 | dependencies:
2657 | emoji-regex: 8.0.0
2658 | is-fullwidth-code-point: 3.0.0
2659 | strip-ansi: 6.0.1
2660 | dev: true
2661 |
2662 | /strip-ansi@6.0.1:
2663 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
2664 | engines: {node: '>=8'}
2665 | dependencies:
2666 | ansi-regex: 5.0.1
2667 | dev: true
2668 |
2669 | /strip-bom@4.0.0:
2670 | resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
2671 | engines: {node: '>=8'}
2672 | dev: true
2673 |
2674 | /strip-final-newline@2.0.0:
2675 | resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
2676 | engines: {node: '>=6'}
2677 | dev: true
2678 |
2679 | /strip-json-comments@3.1.1:
2680 | resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
2681 | engines: {node: '>=8'}
2682 | dev: true
2683 |
2684 | /superagent@8.1.2:
2685 | resolution: {integrity: sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==}
2686 | engines: {node: '>=6.4.0 <13 || >=14'}
2687 | dependencies:
2688 | component-emitter: 1.3.1
2689 | cookiejar: 2.1.4
2690 | debug: 4.3.4
2691 | fast-safe-stringify: 2.1.1
2692 | form-data: 4.0.0
2693 | formidable: 2.1.2
2694 | methods: 1.1.2
2695 | mime: 2.6.0
2696 | qs: 6.11.2
2697 | semver: 7.5.4
2698 | transitivePeerDependencies:
2699 | - supports-color
2700 | dev: true
2701 |
2702 | /supertest@6.3.4:
2703 | resolution: {integrity: sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==}
2704 | engines: {node: '>=6.4.0'}
2705 | dependencies:
2706 | methods: 1.1.2
2707 | superagent: 8.1.2
2708 | transitivePeerDependencies:
2709 | - supports-color
2710 | dev: true
2711 |
2712 | /supports-color@5.5.0:
2713 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
2714 | engines: {node: '>=4'}
2715 | dependencies:
2716 | has-flag: 3.0.0
2717 | dev: true
2718 |
2719 | /supports-color@7.2.0:
2720 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
2721 | engines: {node: '>=8'}
2722 | dependencies:
2723 | has-flag: 4.0.0
2724 | dev: true
2725 |
2726 | /supports-color@8.1.1:
2727 | resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
2728 | engines: {node: '>=10'}
2729 | dependencies:
2730 | has-flag: 4.0.0
2731 | dev: true
2732 |
2733 | /supports-preserve-symlinks-flag@1.0.0:
2734 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
2735 | engines: {node: '>= 0.4'}
2736 | dev: true
2737 |
2738 | /test-exclude@6.0.0:
2739 | resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
2740 | engines: {node: '>=8'}
2741 | dependencies:
2742 | '@istanbuljs/schema': 0.1.3
2743 | glob: 7.2.3
2744 | minimatch: 3.1.2
2745 | dev: true
2746 |
2747 | /tmpl@1.0.5:
2748 | resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
2749 | dev: true
2750 |
2751 | /to-fast-properties@2.0.0:
2752 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
2753 | engines: {node: '>=4'}
2754 | dev: true
2755 |
2756 | /to-regex-range@5.0.1:
2757 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
2758 | engines: {node: '>=8.0'}
2759 | dependencies:
2760 | is-number: 7.0.0
2761 | dev: true
2762 |
2763 | /toidentifier@1.0.1:
2764 | resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
2765 | engines: {node: '>=0.6'}
2766 | dev: false
2767 |
2768 | /ts-jest@29.1.5(@babel/core@7.23.9)(jest@29.7.0)(typescript@5.5.3):
2769 | resolution: {integrity: sha512-UuClSYxM7byvvYfyWdFI+/2UxMmwNyJb0NPkZPQE2hew3RurV7l7zURgOHAd/1I1ZdPpe3GUsXNXAcN8TFKSIg==}
2770 | engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0}
2771 | hasBin: true
2772 | peerDependencies:
2773 | '@babel/core': '>=7.0.0-beta.0 <8'
2774 | '@jest/transform': ^29.0.0
2775 | '@jest/types': ^29.0.0
2776 | babel-jest: ^29.0.0
2777 | esbuild: '*'
2778 | jest: ^29.0.0
2779 | typescript: '>=4.3 <6'
2780 | peerDependenciesMeta:
2781 | '@babel/core':
2782 | optional: true
2783 | '@jest/transform':
2784 | optional: true
2785 | '@jest/types':
2786 | optional: true
2787 | babel-jest:
2788 | optional: true
2789 | esbuild:
2790 | optional: true
2791 | dependencies:
2792 | '@babel/core': 7.23.9
2793 | bs-logger: 0.2.6
2794 | fast-json-stable-stringify: 2.1.0
2795 | jest: 29.7.0
2796 | jest-util: 29.7.0
2797 | json5: 2.2.3
2798 | lodash.memoize: 4.1.2
2799 | make-error: 1.3.6
2800 | semver: 7.5.4
2801 | typescript: 5.5.3
2802 | yargs-parser: 21.1.1
2803 | dev: true
2804 |
2805 | /type-detect@4.0.8:
2806 | resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==}
2807 | engines: {node: '>=4'}
2808 | dev: true
2809 |
2810 | /type-fest@0.21.3:
2811 | resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
2812 | engines: {node: '>=10'}
2813 | dev: true
2814 |
2815 | /type-is@1.6.18:
2816 | resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
2817 | engines: {node: '>= 0.6'}
2818 | dependencies:
2819 | media-typer: 0.3.0
2820 | mime-types: 2.1.35
2821 | dev: false
2822 |
2823 | /typescript@5.5.3:
2824 | resolution: {integrity: sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==}
2825 | engines: {node: '>=14.17'}
2826 | hasBin: true
2827 | dev: true
2828 |
2829 | /undici-types@5.26.5:
2830 | resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
2831 | dev: true
2832 |
2833 | /unpipe@1.0.0:
2834 | resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
2835 | engines: {node: '>= 0.8'}
2836 | dev: false
2837 |
2838 | /update-browserslist-db@1.0.13(browserslist@4.22.3):
2839 | resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
2840 | hasBin: true
2841 | peerDependencies:
2842 | browserslist: '>= 4.21.0'
2843 | dependencies:
2844 | browserslist: 4.22.3
2845 | escalade: 3.1.1
2846 | picocolors: 1.0.0
2847 | dev: true
2848 |
2849 | /utils-merge@1.0.1:
2850 | resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
2851 | engines: {node: '>= 0.4.0'}
2852 | dev: false
2853 |
2854 | /v8-to-istanbul@9.2.0:
2855 | resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==}
2856 | engines: {node: '>=10.12.0'}
2857 | dependencies:
2858 | '@jridgewell/trace-mapping': 0.3.22
2859 | '@types/istanbul-lib-coverage': 2.0.6
2860 | convert-source-map: 2.0.0
2861 | dev: true
2862 |
2863 | /vary@1.1.2:
2864 | resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
2865 | engines: {node: '>= 0.8'}
2866 | dev: false
2867 |
2868 | /walker@1.0.8:
2869 | resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
2870 | dependencies:
2871 | makeerror: 1.0.12
2872 | dev: true
2873 |
2874 | /which@2.0.2:
2875 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
2876 | engines: {node: '>= 8'}
2877 | hasBin: true
2878 | dependencies:
2879 | isexe: 2.0.0
2880 | dev: true
2881 |
2882 | /wrap-ansi@7.0.0:
2883 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
2884 | engines: {node: '>=10'}
2885 | dependencies:
2886 | ansi-styles: 4.3.0
2887 | string-width: 4.2.3
2888 | strip-ansi: 6.0.1
2889 | dev: true
2890 |
2891 | /wrappy@1.0.2:
2892 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
2893 | dev: true
2894 |
2895 | /write-file-atomic@4.0.2:
2896 | resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
2897 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
2898 | dependencies:
2899 | imurmurhash: 0.1.4
2900 | signal-exit: 3.0.7
2901 | dev: true
2902 |
2903 | /y18n@5.0.8:
2904 | resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
2905 | engines: {node: '>=10'}
2906 | dev: true
2907 |
2908 | /yallist@3.1.1:
2909 | resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
2910 | dev: true
2911 |
2912 | /yallist@4.0.0:
2913 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
2914 | dev: true
2915 |
2916 | /yargs-parser@21.1.1:
2917 | resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
2918 | engines: {node: '>=12'}
2919 | dev: true
2920 |
2921 | /yargs@17.7.2:
2922 | resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
2923 | engines: {node: '>=12'}
2924 | dependencies:
2925 | cliui: 8.0.1
2926 | escalade: 3.1.1
2927 | get-caller-file: 2.0.5
2928 | require-directory: 2.1.1
2929 | string-width: 4.2.3
2930 | y18n: 5.0.8
2931 | yargs-parser: 21.1.1
2932 | dev: true
2933 |
2934 | /yocto-queue@0.1.0:
2935 | resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
2936 | engines: {node: '>=10'}
2937 | dev: true
2938 |
2939 | /zod@3.22.4:
2940 | resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
2941 | dev: false
2942 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import express from 'express'
2 | import type { Request as ExpressDefaultRequest, Response, NextFunction } from 'express'
3 | import {
4 | baseObjectInputType,
5 | baseObjectOutputType,
6 | objectUtil,
7 | z,
8 | ZodError,
9 | ZodObject,
10 | ZodRawShape,
11 | ZodTypeAny,
12 | } from 'zod'
13 | import { ErrorReturnType, HTTPError, HTTPStatus, HTTPStatusText } from './utils/error.js'
14 | export { HTTPError, HTTPStatus, HTTPStatusText } from './utils/error.js'
15 |
16 | export type CustomRequest<
17 | RequestType,
18 | ReqBody = any,
19 | ReqQuery = any,
20 | ReqHeaders = any,
21 | ReqParams = any
22 | > = Omit & {
23 | body: ReqBody
24 | query: ReqQuery
25 | headers: ReqHeaders
26 | params: ReqParams
27 | }
28 |
29 | type Middleware<
30 | ReqType = ExpressDefaultRequest,
31 | ReqBody = any,
32 | ReqQuery = any,
33 | ReqHeaders = any,
34 | ReqParams = any,
35 | PrevContext = {},
36 | NewContext = {}
37 | > = (
38 | req: CustomRequest,
39 | res: Response,
40 | next: NextFunction,
41 | prevContext: PrevContext
42 | ) => NonNullable | Promise> | void | Promise
43 |
44 | class ValidationError extends Error {
45 | public statusCode: number
46 | public errors: ErrorReturnType['errors']
47 | public location: ErrorReturnType['location']
48 |
49 | constructor(zodError: ZodError, location: string) {
50 | super('Validation failed')
51 |
52 | // HTTP status code for validation errors
53 | this.statusCode = 400
54 |
55 | // Extract relevant error details from ZodError
56 | this.errors = JSON.parse(zodError.message).map((el: any) => ({
57 | message: el.message,
58 | path: el.path,
59 | }))
60 |
61 | this.location = location as ErrorReturnType['location']
62 | }
63 | }
64 |
65 | export type HandlerReturnType<
66 | TransformedData,
67 | ReqBody,
68 | ReqQuery,
69 | ReqHeaders,
70 | ReqParams,
71 | ResolvedData
72 | > = express.RequestHandler & {
73 | types: {
74 | response: TransformedData
75 | request: {
76 | body: ReqBody
77 | query: ReqQuery
78 | headers: ReqHeaders
79 | params: ReqParams
80 | }
81 | }
82 | /**
83 | * @deprecated Use response instead
84 | * */
85 | transformedData: TransformedData
86 | }
87 |
88 | export class Handler<
89 | /**
90 | * Set this to the type of the data that will be returned by the transformer function.
91 | */
92 | GlobalOutputData extends {},
93 | RequestType = ExpressDefaultRequest,
94 | ReqBody = any,
95 | ReqQuery = any,
96 | ReqHeaders = any,
97 | ReqParams = any,
98 | ResolvedData = any,
99 | Context = {}
100 | > {
101 | private _resolver?: (
102 | req: CustomRequest,
103 | res: Response,
104 | context: Context
105 | ) => any
106 | private _transformer?: (
107 | data: ResolvedData,
108 | res: Response
109 | ) => GlobalOutputData | Promise
110 |
111 | private _chain: ((
112 | req: CustomRequest,
113 | res: Response,
114 | next: NextFunction,
115 | context: Partial
116 | ) => Partial | Promise>)[] = []
117 |
118 | /**
119 | * Function to add a single middleware to the chain
120 | * @param mw The middleware to add
121 | */
122 | middleware(
123 | mw: Middleware
124 | ): Handler<
125 | GlobalOutputData,
126 | RequestType,
127 | ReqBody,
128 | ReqQuery,
129 | ReqHeaders,
130 | ReqParams,
131 | ResolvedData,
132 | // existing context merged with new context. If new context has a key that already exists in existing context, the new context key will be used as type
133 | Omit & NewContext
134 | > {
135 | this._chain.push(async (req, res, next, context) => {
136 | const contextData = (await mw(req, res, next, context as Context)) as Partial
137 |
138 | if (contextData === undefined || contextData === null) {
139 | // return old context if new context is undefined or null
140 | return context
141 | }
142 | return contextData
143 | })
144 | return this as any
145 | }
146 |
147 | /**
148 | *
149 | * @param type the location of the data to validate. Can be "body", "query", "headers", or "params"
150 | * @param schema the schema to validate against. Can be a zod object or a raw object containing zod types
151 | */
152 | validate<
153 | T extends 'body' | 'query' | 'headers' | 'params',
154 | K extends ZodRawShape,
155 | // copied from zod/lib/types.d.ts objectType. Adjusted to K instead of T
156 | U extends ZodObject<
157 | K,
158 | 'strip',
159 | ZodTypeAny,
160 | {
161 | [k_1 in keyof objectUtil.addQuestionMarks<
162 | baseObjectOutputType,
163 | {
164 | [k in keyof baseObjectOutputType]: undefined extends baseObjectOutputType[k]
165 | ? never
166 | : k
167 | }[keyof K]
168 | >]: objectUtil.addQuestionMarks<
169 | baseObjectOutputType,
170 | {
171 | [k in keyof baseObjectOutputType]: undefined extends baseObjectOutputType[k]
172 | ? never
173 | : k
174 | }[keyof K]
175 | >[k_1]
176 | },
177 | {
178 | [k_2 in keyof baseObjectInputType]: baseObjectInputType[k_2]
179 | }
180 | >
181 | >(
182 | type: T,
183 | schema: K | U
184 | ): Handler<
185 | GlobalOutputData,
186 | RequestType,
187 | T extends 'body' ? z.infer : ReqBody,
188 | T extends 'query' ? z.infer : ReqQuery,
189 | T extends 'headers' ? z.infer : ReqHeaders,
190 | T extends 'params' ? z.infer : ReqParams
191 | > {
192 | // validation logic here
193 | const validationMiddleware = async (
194 | req: CustomRequest,
195 | res: Response,
196 | next: NextFunction
197 | ) => {
198 | try {
199 | // if the request body is not an object, don't validate it
200 | if (typeof req[type] !== 'object') {
201 | throw new HTTPError(400, 'Invalid request body (not an object)')
202 | }
203 |
204 | const value = req[type]
205 |
206 | function isZodObject(object: K | U): object is U {
207 | return '_def' in object
208 | }
209 |
210 | // if it's already an zod object, just use it. Else, make it a zod object first
211 | if (isZodObject(schema)) {
212 | // Overwrite the object inside request with the validated object to allow for transformations and refinements through zod
213 | // @ts-ignore
214 | req[type] = await schema.parseAsync(value)
215 | next()
216 | } else {
217 | // Have to ignore the following because of an unresolved type issue. Still works as expected
218 | // @ts-ignore
219 | const combinedSchema: U = z.object(schema)
220 |
221 | // Overwrite the object inside request with the validated object to allow for transformations and refinements through zod
222 | // @ts-ignore
223 | req[type] = await combinedSchema.parseAsync(value)
224 | }
225 | } catch (err) {
226 | if (err instanceof ZodError) {
227 | throw new ValidationError(err, type)
228 | }
229 | throw err
230 | }
231 |
232 | return {}
233 | }
234 |
235 | this._chain.push(validationMiddleware)
236 | return this as any
237 | }
238 |
239 | /**
240 | * Define the resolver function for the handler. The resolver returns data that needs to be picked up by the transformer function
241 | * @param fn The function to run after all validations and middlewares have been processed
242 | */
243 | resolve(
244 | fn: (
245 | req: CustomRequest,
246 | res: Response,
247 | context: Context
248 | ) => Data | Promise
249 | ): Handler<
250 | GlobalOutputData,
251 | RequestType,
252 | ReqBody,
253 | ReqQuery,
254 | ReqHeaders,
255 | ReqParams,
256 | Data,
257 | Context
258 | > {
259 | this._resolver = fn
260 | return this as any
261 | }
262 | /**
263 | * Define the transformer function for the handler. The transformer function receives the data returned by the resolver and is responsible for sending the response. Useful for creating DTOs
264 | * @param fn The function to run after the resolver has been run. This function is responsible for sending the response
265 | * @returns
266 | */
267 | transform(
268 | fn: (data: ResolvedData, res: Response) => T | Promise
269 | ): Handler {
270 | this._transformer = fn
271 |
272 | // @ts-ignore
273 | return this
274 | }
275 |
276 | getOutputTypes(): GlobalOutputData {
277 | return {} as GlobalOutputData
278 | }
279 |
280 | express(): HandlerReturnType<
281 | GlobalOutputData,
282 | ReqBody,
283 | ReqQuery,
284 | ReqHeaders,
285 | ReqParams,
286 | ResolvedData
287 | > {
288 | const runner = async (
289 | req: CustomRequest,
290 | res: Response,
291 | next: NextFunction
292 | ) => {
293 | let index = 0
294 |
295 | let context: Context = {} as Context
296 |
297 | const runNextChainItem = async () => {
298 | // If there are no more middlewares to run, run the resolver
299 | if (index >= this._chain.length) {
300 | // All middlewares and validations have been processed
301 | try {
302 | const result = await this._resolver!(req, res, context)
303 | if (this._transformer) {
304 | const transformerValue = await this._transformer(result, res)
305 | if (transformerValue !== undefined) {
306 | if (
307 | typeof transformerValue === 'object' &&
308 | transformerValue !== null
309 | ) {
310 | res.json(transformerValue)
311 | } else {
312 | res.send(transformerValue)
313 | }
314 | }
315 | return
316 | } else {
317 | return
318 | }
319 | } catch (err) {
320 | if (err instanceof HTTPError) {
321 | return res.status(err.status).json({
322 | errors: [{ message: err.message }],
323 | type: HTTPStatusText[err.status as HTTPStatus],
324 | } satisfies ErrorReturnType)
325 | } else {
326 | next(err)
327 | return
328 | }
329 | }
330 | }
331 |
332 | // Otherwise, run the next middleware
333 | const currentMiddleware = this._chain[index++]
334 | try {
335 | const returnedContextValue = await currentMiddleware?.(
336 | req,
337 | res,
338 | (err) => {
339 | if (err instanceof Error) {
340 | throw err
341 | }
342 | },
343 | context
344 | )
345 |
346 | // only append object values to context
347 | if (
348 | returnedContextValue !== undefined &&
349 | returnedContextValue !== null &&
350 | typeof returnedContextValue === 'object' &&
351 | !Array.isArray(returnedContextValue)
352 | ) {
353 | context = { ...context, ...returnedContextValue }
354 | }
355 |
356 | // If a middleware has already sent a response, don't run the next middleware
357 | if (res.headersSent) return
358 |
359 | await runNextChainItem()
360 | } catch (err) {
361 | if (err instanceof ValidationError) {
362 | return res.status(err.statusCode).json({
363 | errors: err.errors,
364 | location: err.location,
365 | type: HTTPStatusText[err.statusCode as HTTPStatus],
366 | } satisfies ErrorReturnType)
367 | } else if (err instanceof HTTPError) {
368 | return res.status(err.status).json({
369 | errors: [{ message: err.message }],
370 | type: HTTPStatusText[err.status as HTTPStatus],
371 | } satisfies ErrorReturnType)
372 | } else {
373 | // call the native next express error handler
374 | next(err)
375 | return
376 | }
377 | }
378 | }
379 |
380 | await runNextChainItem()
381 | }
382 |
383 | return runner as unknown as HandlerReturnType<
384 | GlobalOutputData,
385 | ReqBody,
386 | ReqQuery,
387 | ReqHeaders,
388 | ReqParams,
389 | ResolvedData
390 | >
391 | }
392 | }
393 |
--------------------------------------------------------------------------------
/src/utils/error.ts:
--------------------------------------------------------------------------------
1 | export enum HTTPStatus {
2 | OK = 200,
3 | CREATED = 201,
4 | ACCEPTED = 202,
5 | NON_AUTHORITATIVE_INFORMATION = 203,
6 | NO_CONTENT = 204,
7 | RESET_CONTENT = 205,
8 | PARTIAL_CONTENT = 206,
9 | MULTI_STATUS = 207,
10 | ALREADY_REPORTED = 208,
11 | IM_USED = 226,
12 |
13 | MULTIPLE_CHOICES = 300,
14 | MOVED_PERMANENTLY = 301,
15 | FOUND = 302,
16 | SEE_OTHER = 303,
17 | NOT_MODIFIED = 304,
18 | USE_PROXY = 305,
19 | SWITCH_PROXY = 306,
20 | TEMPORARY_REDIRECT = 307,
21 | PERMANENT_REDIRECT = 308,
22 |
23 | BAD_REQUEST = 400,
24 | UNAUTHORIZED = 401,
25 | PAYMENT_REQUIRED = 402,
26 | FORBIDDEN = 403,
27 | NOT_FOUND = 404,
28 | METHOD_NOT_ALLOWED = 405,
29 | NOT_ACCEPTABLE = 406,
30 | PROXY_AUTHENTICATION_REQUIRED = 407,
31 | REQUEST_TIMEOUT = 408,
32 | CONFLICT = 409,
33 | GONE = 410,
34 | LENGTH_REQUIRED = 411,
35 | PRECONDITION_FAILED = 412,
36 | PAYLOAD_TOO_LARGE = 413,
37 | URI_TOO_LONG = 414,
38 | UNSUPPORTED_MEDIA_TYPE = 415,
39 | RANGE_NOT_SATISFIABLE = 416,
40 | EXPECTATION_FAILED = 417,
41 | I_AM_A_TEAPOT = 418,
42 | MISDIRECTED_REQUEST = 421,
43 | UNPROCESSABLE_ENTITY = 422,
44 | LOCKED = 423,
45 | FAILED_DEPENDENCY = 424,
46 | TOO_EARLY = 425,
47 | UPGRADE_REQUIRED = 426,
48 | PRECONDITION_REQUIRED = 428,
49 | TOO_MANY_REQUESTS = 429,
50 | REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
51 | UNAVAILABLE_FOR_LEGAL_REASONS = 451,
52 |
53 | INTERNAL_SERVER_ERROR = 500,
54 | NOT_IMPLEMENTED = 501,
55 | BAD_GATEWAY = 502,
56 | SERVICE_UNAVAILABLE = 503,
57 | GATEWAY_TIMEOUT = 504,
58 | HTTP_VERSION_NOT_SUPPORTED = 505,
59 | VARIANT_ALSO_NEGOTIATES = 506,
60 | INSUFFICIENT_STORAGE = 507,
61 | LOOP_DETECTED = 508,
62 | NOT_EXTENDED = 510,
63 | NETWORK_AUTHENTICATION_REQUIRED = 511,
64 | }
65 |
66 | export const HTTPStatusText: Record = {
67 | [HTTPStatus.OK]: 'OK',
68 | [HTTPStatus.CREATED]: 'Created',
69 | [HTTPStatus.ACCEPTED]: 'Accepted',
70 | [HTTPStatus.NON_AUTHORITATIVE_INFORMATION]: 'Non-Authoritative Information',
71 | [HTTPStatus.NO_CONTENT]: 'No Content',
72 | [HTTPStatus.RESET_CONTENT]: 'Reset Content',
73 | [HTTPStatus.PARTIAL_CONTENT]: 'Partial Content',
74 | [HTTPStatus.MULTI_STATUS]: 'Multi-Status',
75 | [HTTPStatus.ALREADY_REPORTED]: 'Already Reported',
76 | [HTTPStatus.IM_USED]: 'IM Used',
77 |
78 | [HTTPStatus.MULTIPLE_CHOICES]: 'Multiple Choices',
79 | [HTTPStatus.MOVED_PERMANENTLY]: 'Moved Permanently',
80 | [HTTPStatus.FOUND]: 'Found',
81 | [HTTPStatus.SEE_OTHER]: 'See Other',
82 | [HTTPStatus.NOT_MODIFIED]: 'Not Modified',
83 | [HTTPStatus.USE_PROXY]: 'Use Proxy',
84 | [HTTPStatus.SWITCH_PROXY]: 'Switch Proxy',
85 | [HTTPStatus.TEMPORARY_REDIRECT]: 'Temporary Redirect',
86 | [HTTPStatus.PERMANENT_REDIRECT]: 'Permanent Redirect',
87 |
88 | [HTTPStatus.BAD_REQUEST]: 'Bad Request',
89 | [HTTPStatus.UNAUTHORIZED]: 'Unauthorized',
90 | [HTTPStatus.PAYMENT_REQUIRED]: 'Payment Required',
91 | [HTTPStatus.FORBIDDEN]: 'Forbidden',
92 | [HTTPStatus.NOT_FOUND]: 'Not Found',
93 | [HTTPStatus.METHOD_NOT_ALLOWED]: 'Method Not Allowed',
94 | [HTTPStatus.NOT_ACCEPTABLE]: 'Not Acceptable',
95 | [HTTPStatus.PROXY_AUTHENTICATION_REQUIRED]: 'Proxy Authentication Required',
96 | [HTTPStatus.REQUEST_TIMEOUT]: 'Request Timeout',
97 | [HTTPStatus.CONFLICT]: 'Conflict',
98 | [HTTPStatus.GONE]: 'Gone',
99 | [HTTPStatus.LENGTH_REQUIRED]: 'Length Required',
100 | [HTTPStatus.PRECONDITION_FAILED]: 'Precondition Failed',
101 | [HTTPStatus.PAYLOAD_TOO_LARGE]: 'Payload Too Large',
102 | [HTTPStatus.URI_TOO_LONG]: 'URI Too Long',
103 | [HTTPStatus.UNSUPPORTED_MEDIA_TYPE]: 'Unsupported Media Type',
104 | [HTTPStatus.RANGE_NOT_SATISFIABLE]: 'Range Not Satisfiable',
105 | [HTTPStatus.EXPECTATION_FAILED]: 'Expectation Failed',
106 | [HTTPStatus.I_AM_A_TEAPOT]: "I'm a teapot",
107 | [HTTPStatus.MISDIRECTED_REQUEST]: 'Misdirected Request',
108 | [HTTPStatus.UNPROCESSABLE_ENTITY]: 'Unprocessable Entity',
109 | [HTTPStatus.LOCKED]: 'Locked',
110 | [HTTPStatus.FAILED_DEPENDENCY]: 'Failed Dependency',
111 | [HTTPStatus.TOO_EARLY]: 'Too Early',
112 | [HTTPStatus.UPGRADE_REQUIRED]: 'Upgrade Required',
113 | [HTTPStatus.PRECONDITION_REQUIRED]: 'Precondition Required',
114 | [HTTPStatus.TOO_MANY_REQUESTS]: 'Too Many Requests',
115 | [HTTPStatus.REQUEST_HEADER_FIELDS_TOO_LARGE]: 'Request Header Fields Too Large',
116 | [HTTPStatus.UNAVAILABLE_FOR_LEGAL_REASONS]: 'Unavailable For Legal Reasons',
117 |
118 | [HTTPStatus.INTERNAL_SERVER_ERROR]: 'Internal Server Error',
119 | [HTTPStatus.NOT_IMPLEMENTED]: 'Not Implemented',
120 | [HTTPStatus.BAD_GATEWAY]: 'Bad Gateway',
121 | [HTTPStatus.SERVICE_UNAVAILABLE]: 'Service Unavailable',
122 | [HTTPStatus.GATEWAY_TIMEOUT]: 'Gateway Timeout',
123 | [HTTPStatus.HTTP_VERSION_NOT_SUPPORTED]: 'HTTP Version Not Supported',
124 | [HTTPStatus.VARIANT_ALSO_NEGOTIATES]: 'Variant Also Negotiates',
125 | [HTTPStatus.INSUFFICIENT_STORAGE]: 'Insufficient Storage',
126 | [HTTPStatus.LOOP_DETECTED]: 'Loop Detected',
127 | [HTTPStatus.NOT_EXTENDED]: 'Not Extended',
128 | [HTTPStatus.NETWORK_AUTHENTICATION_REQUIRED]: 'Network Authentication Required',
129 | }
130 |
131 | export class HTTPError extends Error {
132 | constructor(public readonly status: number, message: string) {
133 | super(message)
134 | }
135 | }
136 |
137 | export type ErrorReturnType = {
138 | errors: {
139 | message: string
140 | path?: (string | number)[]
141 | }[]
142 | location?: 'query' | 'params' | 'body' | 'headers'
143 | type: string
144 | }
145 |
--------------------------------------------------------------------------------
/tests/errors/0_errors.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError, HTTPStatus } from '../../src/utils/error.js'
7 |
8 | const app = express()
9 |
10 | const resolverErrorHandler = new Handler()
11 | .validate('params', { userId: z.string() })
12 | .resolve(async (req, res, context) => {
13 | throw new HTTPError(HTTPStatus.BAD_REQUEST, 'This should fail in resolver')
14 | })
15 | .transform((data) => {
16 | return {
17 | data: {
18 | name: 'Hello World',
19 | },
20 | meta: {},
21 | }
22 | })
23 | .express()
24 |
25 | const transformerErrorHandler = new Handler()
26 | .validate('params', { userId: z.string() })
27 | .resolve(async (req, res, context) => {
28 | return 'ok'
29 | })
30 | .transform((data) => {
31 | throw new HTTPError(HTTPStatus.BAD_REQUEST, 'This should fail in transformer')
32 | return {
33 | data: {
34 | name: 'Hello World',
35 | },
36 | meta: {},
37 | }
38 | })
39 | .express()
40 |
41 | app.get('/resolver/:userId', resolverErrorHandler)
42 | app.get('/transformer/:userId', transformerErrorHandler)
43 |
44 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
45 | app.use((err: any, req: any, res: any, next: any) => {
46 | res.status(500).send('Something broke!')
47 | })
48 |
49 | // TESTS
50 |
51 | describe('Error Handling', () => {
52 | it('should return error as expected for Resolver', (done) => {
53 | request(app)
54 | .get('/resolver/1')
55 | .expect(400)
56 | .then((res) => {
57 | expect(res.body).toEqual({
58 | errors: [
59 | {
60 | message: 'This should fail in resolver',
61 | },
62 | ],
63 | type: 'Bad Request',
64 | })
65 |
66 | done()
67 | })
68 | .catch(done)
69 | })
70 |
71 | it('should return error as expected for Transformer', (done) => {
72 | request(app)
73 | .get('/transformer/1')
74 | .expect(400)
75 | .then((res) => {
76 | expect(res.body).toEqual({
77 | errors: [
78 | {
79 | message: 'This should fail in transformer',
80 | },
81 | ],
82 | type: 'Bad Request',
83 | })
84 |
85 | done()
86 | })
87 | .catch(done)
88 | })
89 | })
90 |
--------------------------------------------------------------------------------
/tests/middlewares/0_simple-middleware.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const app = express()
9 |
10 | const simpleMiddlewareHandler = new Handler()
11 | .validate('params', { userId: z.string() })
12 | .validate('query', { fail: z.string() })
13 | .middleware(async (req) => {
14 | if (req.query.fail === 'yes') {
15 | throw new HTTPError(400, 'This should fail')
16 | }
17 |
18 | if (req.query.fail === 'unknown') {
19 | throw new Error('This should fail')
20 | }
21 |
22 | return {
23 | name: 'John Doe',
24 | }
25 | })
26 | .resolve(async (req, res, context) => {
27 | return { name: context.name }
28 | })
29 | .transform((data) => {
30 | return {
31 | data: {
32 | name: data.name,
33 | },
34 | meta: {},
35 | }
36 | })
37 | .express()
38 |
39 | app.get('/user/:userId', simpleMiddlewareHandler)
40 |
41 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
42 | app.use((err: any, req: any, res: any, next: any) => {
43 | if (err instanceof HTTPError) {
44 | return res.status(err.status).send(err.message)
45 | }
46 |
47 | res.status(500).send('Something broke!')
48 | })
49 |
50 | // TESTS
51 |
52 | describe('Middleware Tests', () => {
53 | describe('Single Middleware', () => {
54 | it('should return 200 on success', (done) => {
55 | request(app)
56 | .get('/user/1?fail=no')
57 | .expect(200)
58 | .then((res) => {
59 | expect(res.body).toEqual({
60 | data: {
61 | name: 'John Doe',
62 | },
63 | meta: {},
64 | })
65 |
66 | done()
67 | })
68 | .catch(done)
69 | })
70 |
71 | it('should return 400 on fail', (done) => {
72 | request(app).get('/user/1?fail=yes').expect(400).end(done)
73 | })
74 |
75 | it('should return 500 on non-HttpError fail', (done) => {
76 | request(app).get('/user/1?fail=unknown').expect(500).end(done)
77 | })
78 | })
79 | })
80 |
--------------------------------------------------------------------------------
/tests/middlewares/1_chained-middleware.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express, { Request } from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const app = express()
9 |
10 | const mergedMiddlewareHandler = new Handler()
11 | .validate('params', { userId: z.string() })
12 | .validate('query', {
13 | failInMiddlewareOne: z.string().optional(),
14 | failInMiddlewareTwo: z.string().optional(),
15 | })
16 | .middleware(async (req) => {
17 | if (req.query.failInMiddlewareOne === 'yes') {
18 | throw new HTTPError(400, 'This should fail')
19 | }
20 |
21 | return {
22 | name: 'John Doe',
23 | age: 12,
24 | }
25 | })
26 | .middleware((req) => {
27 | // no return value
28 | })
29 | .middleware(async (req, res, next, context) => {
30 | if (req.query.failInMiddlewareTwo === 'yes') {
31 | throw new HTTPError(401, 'This should fail in middleware two')
32 | }
33 |
34 | if (context.name !== 'John Doe') {
35 | throw new Error('Middleware two should have the previous context applied')
36 | }
37 |
38 | return {
39 | age: 20,
40 | }
41 | })
42 | .resolve(async (req, res, context) => {
43 | return { name: context.name, age: context.age }
44 | })
45 | .transform((data) => {
46 | return {
47 | data: {
48 | name: data.name,
49 | age: data.age,
50 | },
51 | meta: {},
52 | }
53 | })
54 | .express()
55 |
56 | app.get('/user/:userId', mergedMiddlewareHandler)
57 |
58 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
59 | app.use((err: any, req: any, res: any, next: any) => {
60 | if (err instanceof HTTPError) {
61 | return res.status(err.status).send(err.message)
62 | }
63 |
64 | res.status(500).send('Something broke!')
65 | })
66 |
67 | // TESTS
68 |
69 | describe('Chained Middlewares', () => {
70 | it('should return 200 on success', (done) => {
71 | request(app)
72 | .get('/user/1')
73 | .expect(200)
74 | .then((res) => {
75 | expect(res.body).toEqual({
76 | data: {
77 | name: 'John Doe',
78 | age: 20,
79 | },
80 | meta: {},
81 | })
82 | done()
83 | })
84 | .catch(done)
85 | })
86 |
87 | it('should return 400 on fail in first middleware', (done) => {
88 | request(app).get('/user/1?failInMiddlewareOne=yes').expect(400).end(done)
89 | })
90 |
91 | it('should return 400 on fail in second middleware and not execute second middleware', (done) => {
92 | request(app)
93 | .get('/user/1?failInMiddlewareOne=yes&failInMiddlewareTwo=yes')
94 | .expect(400)
95 | .end(done)
96 | })
97 |
98 | it('should return 401 on fail in second middleware', (done) => {
99 | request(app).get('/user/1?failInMiddlewareTwo=yes').expect(401).end(done)
100 | })
101 | })
102 |
--------------------------------------------------------------------------------
/tests/misc/0_no-transformer.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from "zod"
2 |
3 | import request from "supertest"
4 | import express from "express"
5 | import { Handler } from "../../src/index.js"
6 | import { HTTPError } from "../../src/utils/error.js"
7 |
8 | const app = express()
9 | // JSON parser middleware is required for body validation!
10 | app.use(express.json())
11 |
12 | const miscBaseTest = new Handler()
13 | .resolve(async (req, res) => {
14 | res.status(204).send()
15 | })
16 | .express()
17 |
18 | const redirectBaseTest = new Handler()
19 | .resolve(async (req, res) => {
20 | res.redirect(301, "/")
21 | })
22 | .express()
23 |
24 | app.post("/misc/1", miscBaseTest)
25 | app.post("/misc/2", redirectBaseTest)
26 |
27 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
28 | app.use((err: any, req: any, res: any, next: any) => {
29 | if (err instanceof HTTPError) {
30 | return res.status(err.status).send(err.message)
31 | }
32 |
33 | res.status(500).send("Something broke!")
34 | })
35 |
36 | // TESTS
37 | describe("Misc Tests", () => {
38 | it("should return a custom status code without transformer", (done) => {
39 | request(app).post(`/misc/1`).expect(204).end(done)
40 | })
41 |
42 | it("should redirect with correct code", (done) => {
43 | request(app).post(`/misc/2`).expect(301).expect("Location", "/").end(done)
44 | })
45 | })
46 |
--------------------------------------------------------------------------------
/tests/validation/0_body-validation.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const app = express()
9 | // JSON parser middleware is required for body validation!
10 | app.use(express.json())
11 |
12 | const bodyValidationBaseTest = new Handler()
13 | .validate('body', {
14 | user: z.object({
15 | username: z.string(),
16 | password: z.string(),
17 | }),
18 | })
19 | .resolve(async (req) => {
20 | return { name: req.body.user.username, password: req.body.user.password }
21 | })
22 | .transform((data) => {
23 | return {
24 | data: {
25 | name: data.name,
26 | password: data.password,
27 | },
28 | meta: {},
29 | }
30 | })
31 | .express()
32 |
33 | const validateBody = z.object({
34 | user: z.object({
35 | username: z.string(),
36 | password: z.string(),
37 | }),
38 | })
39 |
40 | const bodyValidationExternalValidatorTest = new Handler()
41 | .validate('body', validateBody)
42 | .resolve(async (req) => {
43 | return { name: req.body.user.username, password: req.body.user.password }
44 | })
45 | .transform((data) => {
46 | return {
47 | data: {
48 | name: data.name,
49 | password: data.password,
50 | },
51 | meta: {},
52 | }
53 | })
54 | .express()
55 |
56 | app.post('/validation/1', bodyValidationBaseTest)
57 | app.post('/validation/2', bodyValidationExternalValidatorTest)
58 |
59 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
60 | app.use((err: any, req: any, res: any, next: any) => {
61 | if (err instanceof HTTPError) {
62 | return res.status(err.status).send(err.message)
63 | }
64 |
65 | res.status(500).send('Something broke!')
66 | })
67 |
68 | // TESTS
69 | describe('Validation Tests', () => {
70 | describe('Basic Body Validaton', () => {
71 | it('should return 200 on success', (done) => {
72 | const user = {
73 | username: 'test1',
74 | password: 'test2',
75 | }
76 | request(app)
77 | .post('/validation/1')
78 | .send({
79 | user,
80 | })
81 | .set('Content-Type', 'application/json')
82 | .set('Accept', 'application/json')
83 | .expect(200)
84 | .then((res) => {
85 | expect(res.body).toEqual({
86 | data: {
87 | name: user.username,
88 | password: user.password,
89 | },
90 | meta: {},
91 | })
92 |
93 | done()
94 | })
95 | .catch(done)
96 | })
97 |
98 | it('should return 400 on no body passed', (done) => {
99 | request(app).post('/validation/1').expect(400).end(done)
100 | })
101 |
102 | it('should return 400 on missing username', (done) => {
103 | const user = {
104 | password: 'test2',
105 | }
106 | request(app)
107 | .post('/validation/1')
108 | .send({
109 | user,
110 | })
111 | .set('Content-Type', 'application/json')
112 | .set('Accept', 'application/json')
113 | .expect(400)
114 | .end(done)
115 | })
116 |
117 | it('should return 400 on wrongly formatted data', (done) => {
118 | request(app)
119 | .post('/validation/1')
120 | .send('string')
121 | .set('Content-Type', 'text/plain')
122 | .expect(400)
123 | .end(done)
124 |
125 | request(app)
126 | .post('/validation/1')
127 | .send(undefined)
128 | .set('Content-Type', 'unset')
129 | .expect(400)
130 | .end(done)
131 | })
132 | })
133 |
134 | describe('External Validator Object Body Validaton', () => {
135 | it('should return 200 on success', (done) => {
136 | const user = {
137 | username: 'test1',
138 | password: 'test2',
139 | }
140 | request(app)
141 | .post('/validation/2')
142 | .send({
143 | user,
144 | })
145 | .set('Content-Type', 'application/json')
146 | .set('Accept', 'application/json')
147 | .expect(200)
148 | .then((res) => {
149 | expect(res.body).toEqual({
150 | data: {
151 | name: user.username,
152 | password: user.password,
153 | },
154 | meta: {},
155 | })
156 |
157 | done()
158 | })
159 | .catch(done)
160 | })
161 |
162 | it('should return 400 on no body passed', (done) => {
163 | request(app).post('/validation/2').expect(400).end(done)
164 | })
165 |
166 | it('should return 400 on missing username', (done) => {
167 | const user = {
168 | password: 'test2',
169 | }
170 | request(app)
171 | .post('/validation/2')
172 | .send({
173 | user,
174 | })
175 | .set('Content-Type', 'application/json')
176 | .set('Accept', 'application/json')
177 | .expect(400)
178 | .end(done)
179 | })
180 |
181 | it('should return 400 on wrongly formatted data', (done) => {
182 | request(app)
183 | .post('/validation/2')
184 | .send('string')
185 | .set('Content-Type', 'text/plain')
186 | .expect(400)
187 | .end(done)
188 |
189 | request(app)
190 | .post('/validation/2')
191 | .send(undefined)
192 | .set('Content-Type', 'unset')
193 | .expect(400)
194 | .end(done)
195 | })
196 | })
197 | })
198 |
--------------------------------------------------------------------------------
/tests/validation/1_header-validation.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const app = express()
9 | // JSON parser middleware is required for body validation!
10 | app.use(express.json())
11 |
12 | const headersValidationBaseTest = new Handler()
13 | .validate('headers', {
14 | // MUST be lowercase
15 | authorization: z.string(),
16 | })
17 | .resolve(async (req) => {
18 | return { auth: req.headers.authorization }
19 | })
20 | .transform((data) => {
21 | return {
22 | data: {
23 | auth: data.auth,
24 | },
25 | meta: {},
26 | }
27 | })
28 | .express()
29 |
30 | app.post('/validation/1', headersValidationBaseTest)
31 |
32 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
33 | app.use((err: any, req: any, res: any, next: any) => {
34 | if (err instanceof HTTPError) {
35 | return res.status(err.status).send(err.message)
36 | }
37 |
38 | res.status(500).send('Something broke!')
39 | })
40 |
41 | // TESTS
42 | describe('Validation Tests', () => {
43 | describe('Basic Headers Validaton', () => {
44 | it('should return 200 on success', (done) => {
45 | const auth = 'test1'
46 | request(app)
47 | .post('/validation/1')
48 | .set({ Authorization: auth })
49 | .expect(200)
50 | .then((res) => {
51 | expect(res.body).toEqual({
52 | data: {
53 | auth,
54 | },
55 | meta: {},
56 | })
57 |
58 | done()
59 | })
60 | .catch(done)
61 | })
62 |
63 | it('should return 400 on no headers passed', (done) => {
64 | request(app).post('/validation/1').expect(400).end(done)
65 | })
66 |
67 | it('should return 400 on wrong headers passed', (done) => {
68 | request(app).post('/validation/1').set({ OtherHeader: '1' }).expect(400).end(done)
69 | })
70 | })
71 | })
72 |
--------------------------------------------------------------------------------
/tests/validation/2_params-validation.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const app = express()
9 | // JSON parser middleware is required for body validation!
10 | app.use(express.json())
11 |
12 | const globalData = {
13 | username: 'test1',
14 | }
15 |
16 | const paramsValidationBaseTest = new Handler()
17 | .validate('params', {
18 | Username: z.enum([globalData.username]),
19 | organization: z.string(),
20 | })
21 | .resolve(async (req) => {
22 | return { username: req.params.Username, organization: req.params.organization }
23 | })
24 | .transform((data) => {
25 | return {
26 | data: {
27 | username: data.username,
28 | organization: data.organization,
29 | },
30 | meta: {},
31 | }
32 | })
33 | .express()
34 |
35 | app.post('/validation/:organization/:Username', paramsValidationBaseTest)
36 |
37 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
38 | app.use((err: any, req: any, res: any, next: any) => {
39 | if (err instanceof HTTPError) {
40 | return res.status(err.status).send(err.message)
41 | }
42 |
43 | res.status(500).send('Something broke!')
44 | })
45 |
46 | // TESTS
47 | describe('Validation Tests', () => {
48 | describe('Params Base Validaton', () => {
49 | it('should return 200 on success', (done) => {
50 | const params = {
51 | Username: globalData.username,
52 | organization: 'test2',
53 | }
54 | request(app)
55 | .post(`/validation/${params.organization}/${params.Username}`)
56 | .expect(200)
57 | .then((res) => {
58 | expect(res.body).toEqual({
59 | data: {
60 | username: params.Username,
61 | organization: params.organization,
62 | },
63 | meta: {},
64 | })
65 |
66 | done()
67 | })
68 | .catch(done)
69 | })
70 |
71 | it('should return 400 on wrong params passed', (done) => {
72 | const wrongParams = {
73 | Username: 1,
74 | organization: 2,
75 | }
76 |
77 | request(app)
78 | .post(`/validation/${wrongParams.organization}/${wrongParams.Username}`)
79 | .expect(400)
80 | .end(done)
81 | })
82 | })
83 | })
84 |
--------------------------------------------------------------------------------
/tests/validation/3_query-validation.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const app = express()
9 | // JSON parser middleware is required for body validation!
10 | app.use(express.json())
11 |
12 | const globalData = {
13 | username: 'test1',
14 | }
15 |
16 | const paramsValidationBaseTest = new Handler()
17 | .validate('query', {
18 | Username: z.enum([globalData.username]),
19 | organization: z.string(),
20 | })
21 | .resolve(async (req) => {
22 | return { username: req.query.Username, organization: req.query.organization }
23 | })
24 | .transform((data) => {
25 | return {
26 | data: {
27 | username: data.username,
28 | organization: data.organization,
29 | },
30 | meta: {},
31 | }
32 | })
33 | .express()
34 |
35 | app.post('/validation/1', paramsValidationBaseTest)
36 |
37 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
38 | app.use((err: any, req: any, res: any, next: any) => {
39 | if (err instanceof HTTPError) {
40 | return res.status(err.status).send(err.message)
41 | }
42 |
43 | res.status(500).send('Something broke!')
44 | })
45 |
46 | // TESTS
47 | describe('Validation Tests', () => {
48 | describe('Query Base Validaton', () => {
49 | it('should return 200 on success', (done) => {
50 | const queryParams = {
51 | Username: globalData.username,
52 | organization: 'test2',
53 | }
54 | request(app)
55 | .post(
56 | `/validation/1?organization=${queryParams.organization}&Username=${queryParams.Username}`
57 | )
58 | .expect(200)
59 | .then((res) => {
60 | expect(res.body).toEqual({
61 | data: {
62 | username: queryParams.Username,
63 | organization: queryParams.organization,
64 | },
65 | meta: {},
66 | })
67 |
68 | done()
69 | })
70 | .catch(done)
71 | })
72 |
73 | it('should return 400 on wrong params passed', (done) => {
74 | const wrongParams = {
75 | Username: 1,
76 | organization: 2,
77 | }
78 |
79 | request(app)
80 | .post(
81 | `/validation/1?organization=${wrongParams.organization}&Username=${wrongParams.Username}`
82 | )
83 | .expect(400)
84 | .end(done)
85 | })
86 |
87 | it('should return 400 on missing params passed', (done) => {
88 | request(app).post(`/validation/1`).expect(400).end(done)
89 | })
90 | })
91 | })
92 |
--------------------------------------------------------------------------------
/tests/validation/4_combined-validation.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const globalData = {
9 | username: 'test1',
10 | password: 'test2',
11 | organization: 'test3',
12 | filters: 'test4',
13 | authorization: 'test5',
14 | }
15 |
16 | const app = express()
17 | // JSON parser middleware is required for body validation!
18 | app.use(express.json())
19 |
20 | const bodyValidationBaseTest = new Handler()
21 | .validate('body', {
22 | user: z.object({
23 | username: z.string(),
24 | password: z.string(),
25 | }),
26 | })
27 | .validate('params', {
28 | organization: z.enum([globalData.organization]),
29 | })
30 | .validate('query', {
31 | filters: z.string(),
32 | })
33 | .validate('headers', {
34 | authorization: z.string(),
35 | })
36 | .middleware(async (req, res, next) => {
37 | if (req.body.user.username === 'FAIL') {
38 | throw new HTTPError(401, 'Username cannot be FAIL')
39 | }
40 |
41 | next()
42 | })
43 | .resolve(async (req) => {
44 | return {
45 | name: req.body.user.username,
46 | password: req.body.user.password,
47 | organization: req.params.organization,
48 | filters: req.query.filters,
49 | authorization: req.headers.authorization,
50 | }
51 | })
52 | .transform((data) => {
53 | return {
54 | data: {
55 | name: data.name,
56 | password: data.password,
57 | organization: data.organization,
58 | filters: data.filters,
59 | authorization: data.authorization,
60 | },
61 | meta: {},
62 | }
63 | })
64 | .express()
65 |
66 | const validateBody = z.object({
67 | user: z.object({
68 | username: z.string(),
69 | password: z.string(),
70 | }),
71 | })
72 |
73 | app.post('/validation/:organization', bodyValidationBaseTest)
74 |
75 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
76 | app.use((err: any, req: any, res: any, next: any) => {
77 | if (err instanceof HTTPError) {
78 | return res.status(err.status).send(err.message)
79 | }
80 |
81 | res.status(500).send('Something broke!')
82 | })
83 |
84 | // TESTS
85 | describe('Validation Tests', () => {
86 | describe('Combined Validations', () => {
87 | it('should return 200 on success', (done) => {
88 | request(app)
89 | .post('/validation/' + globalData.organization + '?filters=' + globalData.filters)
90 | .send({
91 | user: {
92 | username: globalData.username,
93 | password: globalData.password,
94 | },
95 | })
96 | .set('Content-Type', 'application/json')
97 | .set('Accept', 'application/json')
98 | .set({ Authorization: globalData.authorization })
99 | .expect(200)
100 | .then((res) => {
101 | expect(res.body).toEqual({
102 | data: {
103 | name: globalData.username,
104 | password: globalData.password,
105 | organization: globalData.organization,
106 | filters: globalData.filters,
107 | authorization: globalData.authorization,
108 | },
109 | meta: {},
110 | })
111 |
112 | done()
113 | })
114 | .catch(done)
115 | })
116 |
117 | it('should return 400 on invalid body', (done) => {
118 | request(app)
119 | .post('/validation/' + globalData.organization)
120 | .expect(400)
121 | .end(done)
122 | })
123 |
124 | it('should return 400 on invalid params', (done) => {
125 | request(app)
126 | .post('/validation/WRONGVALUE' + '?filters=' + globalData.filters)
127 | .send({
128 | user: {
129 | username: globalData.username,
130 | password: globalData.password,
131 | },
132 | })
133 | .set('Content-Type', 'application/json')
134 | .set('Accept', 'application/json')
135 | .set({ Authorization: globalData.authorization })
136 | .expect(400)
137 | .end(done)
138 | })
139 |
140 | it('should return 400 on invalid query', (done) => {
141 | request(app)
142 | .post('/validation/' + globalData.organization + '?otherQueryThanFilters=FAIL')
143 | .send({
144 | user: {
145 | username: globalData.username,
146 | password: globalData.password,
147 | },
148 | })
149 | .set('Content-Type', 'application/json')
150 | .set('Accept', 'application/json')
151 | .set({ Authorization: globalData.authorization })
152 | .expect(400)
153 | .end(done)
154 | })
155 |
156 | it('should return 400 on invalid headers', (done) => {
157 | request(app)
158 | .post('/validation/' + globalData.organization + '?filters=' + globalData.filters)
159 | .send({
160 | user: {
161 | username: globalData.username,
162 | password: globalData.password,
163 | },
164 | })
165 | .set('Content-Type', 'application/json')
166 | .set('Accept', 'application/json')
167 | .set({ NotProvided: 'FAIL' })
168 | .expect(400)
169 | .end(done)
170 | })
171 |
172 | it('should return 400 on middleware validation fail', (done) => {
173 | request(app)
174 | .post('/validation/' + globalData.organization + '?filters=' + globalData.filters)
175 | .send({
176 | user: {
177 | username: 'FAIL',
178 | password: globalData.password,
179 | },
180 | })
181 | .set('Content-Type', 'application/json')
182 | .set('Accept', 'application/json')
183 | .set({ Authorization: globalData.authorization })
184 | .expect(401)
185 | .end(done)
186 | })
187 | })
188 | })
189 |
--------------------------------------------------------------------------------
/tests/validation/5_validation_transforms.test.ts:
--------------------------------------------------------------------------------
1 | import { z } from 'zod'
2 |
3 | import request from 'supertest'
4 | import express from 'express'
5 | import { Handler } from '../../src/index.js'
6 | import { HTTPError } from '../../src/utils/error.js'
7 |
8 | const globalData = {
9 | username: 'test1',
10 | password: 'test2',
11 | organization: 'test3',
12 | filters: 'test4',
13 | authorization: 'test5',
14 | }
15 |
16 | const app = express()
17 | // JSON parser middleware is required for body validation!
18 | app.use(express.json())
19 |
20 | const bodyValidationBaseTest = new Handler()
21 | .validate('body', {
22 | user: z
23 | .object({
24 | username: z.string(),
25 | password: z.string(),
26 | })
27 | .transform((data) => {
28 | return {
29 | // flip it
30 | username: data.password,
31 | password: data.username,
32 | }
33 | }),
34 | })
35 | .validate('params', {
36 | organization: z.enum([globalData.organization]),
37 | test: z.string().refine((data) => data === 'test', {
38 | message: 'Test must be test',
39 | }),
40 | })
41 | .validate('query', {
42 | filters: z.string().transform(async (data) => {
43 | // wait for 1 second
44 | await new Promise((resolve) => setTimeout(resolve, 1000))
45 |
46 | return data.toUpperCase()
47 | }),
48 | })
49 | .validate('headers', {
50 | authorization: z.string().transform((data) => {
51 | return data.toLowerCase()
52 | }),
53 | })
54 | .middleware(async (req, res, next) => {
55 | if (req.body.user.username === 'FAIL') {
56 | throw new HTTPError(401, 'Username cannot be FAIL')
57 | }
58 |
59 | next()
60 | })
61 | .resolve(async (req) => {
62 | const oldPassword = req.body.user.password
63 | const oldUsername = req.body.user.username
64 |
65 | req.body.user.username = oldPassword
66 | req.body.user.password = oldUsername
67 |
68 | return {
69 | name: req.body.user.username,
70 | password: req.body.user.password,
71 | organization: req.params.organization,
72 | filters: req.query.filters,
73 | authorization: req.headers.authorization,
74 | }
75 | })
76 | .transform((data) => {
77 | return {
78 | data: {
79 | name: data.name,
80 | password: data.password,
81 | organization: data.organization,
82 | filters: data.filters,
83 | authorization: data.authorization,
84 | },
85 | meta: {},
86 | }
87 | })
88 | .express()
89 |
90 | const validateBody = z.object({
91 | user: z.object({
92 | username: z.string(),
93 | password: z.string(),
94 | }),
95 | })
96 |
97 | app.post('/validation/:organization/:test', bodyValidationBaseTest)
98 |
99 | // ALWAYS APPEND ERROR HANDLER AFTER ROUTES
100 | app.use((err: any, req: any, res: any, next: any) => {
101 | if (err instanceof HTTPError) {
102 | return res.status(err.status).send(err.message)
103 | }
104 |
105 | res.status(500).send('Something broke!')
106 | })
107 |
108 | // TESTS
109 | describe('Validation Tests', () => {
110 | describe('Transform validations', () => {
111 | it('should return 200 on success', (done) => {
112 | request(app)
113 | .post(
114 | '/validation/' +
115 | globalData.organization +
116 | '/test' +
117 | '?filters=' +
118 | globalData.filters
119 | )
120 | .send({
121 | user: {
122 | username: globalData.username,
123 | password: globalData.password,
124 | },
125 | })
126 | .set('Content-Type', 'application/json')
127 | .set('Accept', 'application/json')
128 | .set({ Authorization: globalData.authorization })
129 | .expect(200)
130 | .then((res) => {
131 | expect(res.body).toEqual({
132 | data: {
133 | name: globalData.username,
134 | password: globalData.password,
135 | organization: globalData.organization,
136 | filters: globalData.filters.toUpperCase(),
137 | authorization: globalData.authorization,
138 | },
139 | meta: {},
140 | })
141 |
142 | done()
143 | })
144 | .catch(done)
145 | })
146 |
147 | it('should return 400 on invalid body', (done) => {
148 | request(app)
149 | .post(
150 | '/validation/' +
151 | globalData.organization +
152 | '/test' +
153 | '?filters=' +
154 | globalData.filters
155 | )
156 | .expect(400)
157 | .end(done)
158 | })
159 |
160 | it('should return 400 on invalid params (refined)', (done) => {
161 | request(app)
162 | .post(
163 | '/validation/' +
164 | globalData.organization +
165 | '/not-test' +
166 | '?filters=' +
167 | globalData.filters
168 | )
169 | .send({
170 | user: {
171 | username: globalData.username,
172 | password: globalData.password,
173 | },
174 | })
175 | .set('Content-Type', 'application/json')
176 | .set('Accept', 'application/json')
177 | .set({ Authorization: globalData.authorization })
178 | .expect(400)
179 | .end(done)
180 | })
181 |
182 | it('should return 400 on invalid params', (done) => {
183 | request(app)
184 | .post('/validation/WRONGVALUE/test' + '?filters=' + globalData.filters)
185 | .send({
186 | user: {
187 | username: globalData.username,
188 | password: globalData.password,
189 | },
190 | })
191 | .set('Content-Type', 'application/json')
192 | .set('Accept', 'application/json')
193 | .set({ Authorization: globalData.authorization })
194 | .expect(400)
195 | .end(done)
196 | })
197 |
198 | it('should return 400 on invalid query', (done) => {
199 | request(app)
200 | .post('/validation/' + globalData.organization + '/test?otherQueryThanFilters=FAIL')
201 | .send({
202 | user: {
203 | username: globalData.username,
204 | password: globalData.password,
205 | },
206 | })
207 | .set('Content-Type', 'application/json')
208 | .set('Accept', 'application/json')
209 | .set({ Authorization: globalData.authorization })
210 | .expect(400)
211 | .end(done)
212 | })
213 |
214 | it('should return 400 on invalid headers', (done) => {
215 | request(app)
216 | .post(
217 | '/validation/' + globalData.organization + '/test?filters=' + globalData.filters
218 | )
219 | .send({
220 | user: {
221 | username: globalData.username,
222 | password: globalData.password,
223 | },
224 | })
225 | .set('Content-Type', 'application/json')
226 | .set('Accept', 'application/json')
227 | .set({ NotProvided: 'FAIL' })
228 | .expect(400)
229 | .end(done)
230 | })
231 |
232 | it('should return 400 on middleware validation fail', (done) => {
233 | request(app)
234 | .post(
235 | '/validation/' + globalData.organization + '/test?filters=' + globalData.filters
236 | )
237 | .send({
238 | user: {
239 | username: globalData.password,
240 | password: 'FAIL',
241 | },
242 | })
243 | .set('Content-Type', 'application/json')
244 | .set('Accept', 'application/json')
245 | .set({ Authorization: globalData.authorization })
246 | .expect(401)
247 | .end(done)
248 | })
249 | })
250 | })
251 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "esModuleInterop": true,
4 | "skipLibCheck": true,
5 | "target": "es2022",
6 | "allowJs": true,
7 | "resolveJsonModule": true,
8 | "moduleDetection": "force",
9 | "experimentalDecorators": true,
10 | "strict": true,
11 | "noUncheckedIndexedAccess": true,
12 | "moduleResolution": "NodeNext",
13 | "module": "NodeNext",
14 |
15 | "outDir": "dist",
16 | "sourceMap": true,
17 |
18 | "lib": ["es2022"],
19 | "composite": true,
20 | "declarationMap": true,
21 | "declaration": true,
22 | "rootDir": "src",
23 | },
24 | "include": ["src/**/*"],
25 | }
26 |
--------------------------------------------------------------------------------