├── .release-please-manifest.json ├── .husky └── pre-commit ├── pnpm-workspace.yaml ├── .gitignore ├── release-please-config.json ├── src ├── index.ts ├── normalizeResponse.ts ├── statusCodes.ts ├── openApi.ts ├── types.ts ├── createOpenApiDocument.ts ├── normalizeResponse.test.ts ├── createOpenApiDocument.test.ts └── openApi.test.ts ├── .vscode └── settings.json ├── vitest.config.ts ├── tsconfig.json ├── deno.json ├── .github └── workflows │ ├── test-report.yml │ ├── test.yml │ └── release-please.yml ├── biome.json ├── LICENSE ├── package.json ├── CHANGELOG.md ├── README.md └── pnpm-lock.yaml /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | ".": "1.0.1" 3 | } 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | pnpm biome check --write --staged --no-errors-on-unmatched 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | minimumReleaseAge: 10800 2 | onlyBuiltDependencies: 3 | - '@biomejs/biome' 4 | - esbuild 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | .pnpm-debug.log* 5 | 6 | node_modules 7 | dist 8 | 9 | .idea 10 | coverage/ 11 | test-results/ 12 | .DS_Store 13 | .npmrc 14 | 15 | # temporarily 16 | examples -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/release-please@16.12.0/schemas/config.json", 3 | "pull-request-title-pattern": "chore: release ${version}", 4 | "extra-files": ["deno.json"], 5 | "include-component-in-tag": false, 6 | "packages": { 7 | ".": {} 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { createOpenApiDocument } from './createOpenApiDocument.ts'; 2 | export { 3 | createOpenApiMiddleware, 4 | defineOpenApiOperation, 5 | openApi, 6 | } from './openApi.ts'; 7 | export type { 8 | HonoOpenApiDocument, 9 | HonoOpenApiResponseObject, 10 | HonoOpenApiOperation, 11 | HonoOpenApiRequestSchemas, 12 | } from './types.ts'; 13 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "typescript.preferences.preferTypeOnlyAutoImports": true, 4 | "editor.codeActionsOnSave": { 5 | "quickfix.biome": "explicit", 6 | "source.organizeImports.biome": "explicit" 7 | }, 8 | "[typescript]": { 9 | "editor.defaultFormatter": "biomejs.biome" 10 | }, 11 | "typescript.preferences.importModuleSpecifierEnding": "js" 12 | } 13 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitest/config'; 2 | 3 | export default defineConfig({ 4 | test: { 5 | coverage: { 6 | enabled: true, 7 | provider: 'v8', 8 | reporter: process.env.CI 9 | ? ['text', 'json-summary', 'json'] 10 | : ['text', 'html'], 11 | }, 12 | reporters: process.env.CI 13 | ? ['default', 'junit', 'github-actions'] 14 | : ['default'], 15 | outputFile: { 16 | junit: 'test-results/junit.xml', 17 | }, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "skipLibCheck": true, 5 | "target": "es2022", 6 | "allowJs": true, 7 | "allowImportingTsExtensions": true, 8 | "resolveJsonModule": true, 9 | "moduleDetection": "force", 10 | "isolatedModules": true, 11 | "strict": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "verbatimModuleSyntax": true, 14 | "lib": ["es2022", "DOM", "DOM.Iterable"], 15 | "module": "preserve", 16 | "noEmit": true 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@paolostyle/hono-zod-openapi", 3 | "version": "1.0.1", 4 | "exports": "./src/index.ts", 5 | "publish": { 6 | "include": [ 7 | "src/**/*.ts", 8 | "package.json", 9 | "LICENSE", 10 | "README.md", 11 | "CHANGELOG.md" 12 | ], 13 | "exclude": [ 14 | "src/**/*.test.ts" 15 | ] 16 | }, 17 | "imports": { 18 | "@hono/zod-validator": "npm:@hono/zod-validator@^0.7.3", 19 | "hono": "npm:hono@^4.8.0", 20 | "zod": "npm:zod@^4.0.0", 21 | "zod-openapi": "npm:zod-openapi@^5.4.2" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/test-report.yml: -------------------------------------------------------------------------------- 1 | name: Test Report 2 | 3 | on: 4 | workflow_run: 5 | workflows: 6 | - Test 7 | types: 8 | - completed 9 | 10 | permissions: 11 | contents: read 12 | actions: read 13 | checks: write 14 | pull-requests: write 15 | 16 | jobs: 17 | report: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - uses: actions/download-artifact@v4 23 | with: 24 | name: test-results-20 25 | github-token: ${{ secrets.GITHUB_TOKEN }} 26 | run-id: ${{ github.event.workflow_run.id }} 27 | 28 | - name: Test report 29 | uses: dorny/test-reporter@v1 30 | with: 31 | name: Test results 32 | path: test-results/junit.xml 33 | reporter: jest-junit 34 | 35 | - name: Report Coverage 36 | uses: davelosert/vitest-coverage-report-action@v2 37 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | test: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | version: [20, 22, 24] 19 | steps: 20 | - uses: actions/checkout@v4 21 | 22 | - name: Setup pnpm 23 | uses: pnpm/action-setup@v4 24 | 25 | - name: Install Node.js 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: ${{ matrix.version }} 29 | 30 | - name: Install dependencies 31 | run: pnpm install 32 | 33 | - name: Lint 34 | run: pnpm lint 35 | 36 | - name: Check types 37 | run: pnpm typecheck 38 | 39 | - name: Test 40 | run: pnpm test 41 | 42 | - uses: actions/upload-artifact@v4 43 | if: success() || failure() 44 | with: 45 | name: test-results-${{ matrix.version }} 46 | path: | 47 | coverage/ 48 | test-results/junit.xml 49 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.9.3/schema.json", 3 | "vcs": { 4 | "enabled": true, 5 | "clientKind": "git", 6 | "useIgnoreFile": true 7 | }, 8 | "files": { 9 | "ignoreUnknown": false, 10 | "ignore": [] 11 | }, 12 | "formatter": { 13 | "enabled": true, 14 | "formatWithErrors": false, 15 | "indentStyle": "space" 16 | }, 17 | "organizeImports": { 18 | "enabled": true 19 | }, 20 | "linter": { 21 | "enabled": true, 22 | "rules": { 23 | "recommended": true, 24 | "correctness": { 25 | "useImportExtensions": "error" 26 | } 27 | } 28 | }, 29 | "javascript": { 30 | "formatter": { 31 | "quoteStyle": "single" 32 | } 33 | }, 34 | "overrides": [ 35 | { 36 | "include": ["src/**/*.test.ts"], 37 | "linter": { 38 | "rules": { 39 | "suspicious": { 40 | "noExplicitAny": "off" 41 | } 42 | } 43 | } 44 | }, 45 | { 46 | "include": ["package.json", "deno.json"], 47 | "formatter": { 48 | "lineWidth": 1 49 | } 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ### MIT License 2 | 3 | Copyright (c) 2024 Paweł Dąbrowski 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 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | release-please: 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: write 13 | pull-requests: write 14 | steps: 15 | - uses: googleapis/release-please-action@v4 16 | id: release 17 | with: 18 | token: ${{ secrets.RELEASE_PLEASE_TOKEN }} 19 | outputs: 20 | release_created: ${{ steps.release.outputs.release_created }} 21 | 22 | npm-publish: 23 | needs: release-please 24 | if: ${{ needs.release-please.outputs.release_created }} 25 | runs-on: ubuntu-latest 26 | permissions: 27 | id-token: write 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - name: Setup pnpm 32 | uses: pnpm/action-setup@v4 33 | 34 | - name: Setup Node.js 35 | uses: actions/setup-node@v4 36 | with: 37 | node-version: 22 38 | registry-url: 'https://registry.npmjs.org' 39 | 40 | - name: Install dependencies 41 | run: pnpm install 42 | 43 | - name: Publish to NPM 44 | run: pnpm publish 45 | env: 46 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 47 | NPM_CONFIG_PROVENANCE: true 48 | 49 | jsr-publish: 50 | needs: release-please 51 | if: ${{ needs.release-please.outputs.release_created }} 52 | permissions: 53 | contents: read 54 | id-token: write 55 | runs-on: ubuntu-latest 56 | steps: 57 | - uses: actions/checkout@v4 58 | 59 | - uses: denoland/setup-deno@v2 60 | with: 61 | deno-version: v2.x 62 | 63 | - name: Install dependencies 64 | run: deno install 65 | 66 | - name: Publish to JSR 67 | run: deno publish --allow-dirty 68 | -------------------------------------------------------------------------------- /src/normalizeResponse.ts: -------------------------------------------------------------------------------- 1 | import * as z from 'zod'; 2 | import type { ZodOpenApiResponseObject } from 'zod-openapi'; 3 | import { statusCodes } from './statusCodes.ts'; 4 | import type { 5 | HonoOpenApiResponseObject, 6 | ReferenceObject, 7 | StatusCodeWithWildcards, 8 | } from './types.ts'; 9 | 10 | export const normalizeResponse = ( 11 | res: HonoOpenApiResponseObject, 12 | status: StatusCodeWithWildcards, 13 | path: string, 14 | ): ZodOpenApiResponseObject | ReferenceObject => { 15 | if (res instanceof z.ZodType) { 16 | const contentType = 17 | res instanceof z.ZodString ? 'text/plain' : 'application/json'; 18 | 19 | if (!(res instanceof z.ZodObject) && !(res instanceof z.ZodArray)) { 20 | console.warn( 21 | `Your schema for ${path} is not an object or array, it's recommended to provide an explicit mediaType.`, 22 | ); 23 | } 24 | 25 | return { 26 | description: statusCodes[status], 27 | content: { 28 | [contentType]: { 29 | schema: res, 30 | }, 31 | }, 32 | }; 33 | } 34 | 35 | if ('schema' in res) { 36 | const { schema, description, mediaType, ...rest } = res; 37 | const contentType = 38 | mediaType ?? 39 | (schema instanceof z.ZodString ? 'text/plain' : 'application/json'); 40 | 41 | if ( 42 | !mediaType && 43 | !(schema instanceof z.ZodObject) && 44 | !(schema instanceof z.ZodArray) 45 | ) { 46 | console.warn( 47 | `Your schema for ${path} is not an object or array, it's recommended to provide an explicit mediaType.`, 48 | ); 49 | } 50 | 51 | return { 52 | description: description ?? statusCodes[status], 53 | content: { 54 | [contentType]: { schema }, 55 | }, 56 | ...rest, 57 | }; 58 | } 59 | 60 | return res; 61 | }; 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hono-zod-openapi", 3 | "version": "1.0.1", 4 | "description": "Alternative Hono middleware for creating OpenAPI documentation from Zod schemas", 5 | "author": "Paweł Dąbrowski ", 6 | "homepage": "https://github.com/paolostyle/hono-zod-openapi#readme", 7 | "bugs": { 8 | "url": "https://github.com/paolostyle/hono-zod-openapi/issues" 9 | }, 10 | "repository": "github:paolostyle/hono-zod-openapi", 11 | "license": "MIT", 12 | "keywords": [ 13 | "hono", 14 | "zod", 15 | "openapi", 16 | "documentation", 17 | "middleware", 18 | "swagger", 19 | "typescript" 20 | ], 21 | "type": "module", 22 | "exports": { 23 | ".": { 24 | "types": "./dist/index.d.ts", 25 | "import": "./dist/index.js" 26 | } 27 | }, 28 | "files": [ 29 | "dist" 30 | ], 31 | "engines": { 32 | "node": ">=20" 33 | }, 34 | "scripts": { 35 | "build": "tsup src/index.ts --format esm --dts", 36 | "lint": "biome check", 37 | "lint:fix": "biome check --fix --unsafe", 38 | "prepare": "husky", 39 | "prepublishOnly": "pnpm run build", 40 | "test": "vitest --typecheck", 41 | "test:coverage": "vitest run --coverage", 42 | "test:ui": "vitest --ui", 43 | "typecheck": "tsc" 44 | }, 45 | "dependencies": { 46 | "@hono/zod-validator": "^0.7.3", 47 | "zod-openapi": "^5.4.2" 48 | }, 49 | "peerDependencies": { 50 | "hono": "^4.8.0", 51 | "zod": "^4.0.0" 52 | }, 53 | "devDependencies": { 54 | "@biomejs/biome": "1.9.4", 55 | "@hono/node-server": "^1.19.4", 56 | "@hono/swagger-ui": "^0.5.2", 57 | "@types/node": "^22.18.6", 58 | "@vitest/coverage-v8": "^3.2.4", 59 | "@vitest/ui": "^3.2.4", 60 | "husky": "^9.1.7", 61 | "tsup": "^8.5.0", 62 | "tsx": "^4.20.6", 63 | "typescript": "^5.9.2", 64 | "vitest": "^3.2.4", 65 | "zod": "^4.1.11" 66 | }, 67 | "packageManager": "pnpm@10.18.0+sha512.e804f889f1cecc40d572db084eec3e4881739f8dec69c0ff10d2d1beff9a4e309383ba27b5b750059d7f4c149535b6cd0d2cb1ed3aeb739239a4284a68f40cfa" 68 | } 69 | -------------------------------------------------------------------------------- /src/statusCodes.ts: -------------------------------------------------------------------------------- 1 | export const statusCodes = { 2 | default: 'Default', 3 | 100: '100 Continue', 4 | 101: '101 Switching Protocols', 5 | 102: '102 Processing', 6 | 103: '103 Early Hints', 7 | 200: '200 OK', 8 | 201: '201 Created', 9 | 202: '202 Accepted', 10 | 203: '203 Non-Authoritative Information', 11 | 204: '204 No Content', 12 | 205: '205 Reset Content', 13 | 206: '206 Partial Content', 14 | 207: '207 Multi-Status', 15 | 208: '208 Already Reported', 16 | 226: '226 IM Used', 17 | 300: '300 Multiple Choices', 18 | 301: '301 Moved Permanently', 19 | 302: '302 Found', 20 | 303: '303 See Other', 21 | 304: '304 Not Modified', 22 | 305: '305 Use Proxy', 23 | 306: '306', 24 | 307: '307 Temporary Redirect', 25 | 308: '308 Permanent Redirect', 26 | 400: '400 Bad Request', 27 | 401: '401 Unauthorized', 28 | 402: '402 Payment Required', 29 | 403: '403 Forbidden', 30 | 404: '404 Not Found', 31 | 405: '405 Method Not Allowed', 32 | 406: '406 Not Acceptable', 33 | 407: '407 Proxy Authentication Required', 34 | 408: '408 Request Timeout', 35 | 409: '409 Conflict', 36 | 410: '410 Gone', 37 | 411: '411 Length Required', 38 | 412: '412 Precondition Failed', 39 | 413: '413 Payload Too Large', 40 | 414: '414 URI Too Long', 41 | 415: '415 Unsupported Media Type', 42 | 416: '416 Range Not Satisfiable', 43 | 417: '417 Expectation Failed', 44 | 418: "418 I'm a teapot", 45 | 421: '421 Misdirected Request', 46 | 422: '422 Unprocessable Entity', 47 | 423: '423 Locked', 48 | 424: '424 Failed Dependency', 49 | 425: '425 Too Early', 50 | 426: '426 Upgrade Required', 51 | 428: '428 Precondition Required', 52 | 429: '429 Too Many Requests', 53 | 431: '431 Request Header Fields Too Large', 54 | 451: '451 Unavailable For Legal Reasons', 55 | 500: '500 Internal Server Error', 56 | 501: '501 Not Implemented', 57 | 502: '502 Bad Gateway', 58 | 503: '503 Service Unavailable', 59 | 504: '504 Gateway Timeout', 60 | 505: '505 HTTP Version Not Supported', 61 | 506: '506 Variant Also Negotiates', 62 | 507: '507 Insufficient Storage', 63 | 508: '508 Loop Detected', 64 | 510: '510 Not Extended', 65 | 511: '511 Network Authentication Required', 66 | '1XX': '1XX Informational', 67 | '2XX': '2XX Success', 68 | '3XX': '3XX Redirection', 69 | '4XX': '4XX Client Error', 70 | '5XX': '5XX Server Error', 71 | }; 72 | -------------------------------------------------------------------------------- /src/openApi.ts: -------------------------------------------------------------------------------- 1 | import { zValidator } from '@hono/zod-validator'; 2 | import { every } from 'hono/combine'; 3 | import { createMiddleware } from 'hono/factory'; 4 | import * as z from 'zod'; 5 | import type { 6 | HonoOpenApiMiddleware, 7 | HonoOpenApiOperation, 8 | HonoOpenApiRequestSchemas, 9 | ValidationTarget, 10 | ZodValidatorFn, 11 | } from './types.ts'; 12 | 13 | export const OpenApiSymbol = Symbol(); 14 | 15 | /** 16 | * Used internally to create the `openApi` middleware. You can use it if you have a custom `zod-validator` middleware, 17 | * e.g. one that has a custom error handler. Otherwise, you probably don't need it and you should just use `openApi` instead. 18 | * @param [zodValidator] `@hono/zod-validator`-compatible middleware 19 | * @returns `openApi` middleware 20 | */ 21 | export function createOpenApiMiddleware( 22 | zodValidator: ZodValidatorFn = zValidator, 23 | ): HonoOpenApiMiddleware { 24 | return function openApi(operation) { 25 | const { request } = operation; 26 | const metadata = { 27 | [OpenApiSymbol]: operation, 28 | }; 29 | 30 | if (!request) { 31 | const emptyMiddleware = createMiddleware(async (_, next) => { 32 | await next(); 33 | }); 34 | return Object.assign(emptyMiddleware, metadata); 35 | } 36 | 37 | const validators = Object.entries(request) 38 | .map(([target, schemaOrParams]) => { 39 | const schema = 40 | schemaOrParams instanceof z.ZodType 41 | ? schemaOrParams 42 | : schemaOrParams.validate !== false 43 | ? schemaOrParams.schema 44 | : null; 45 | 46 | if (!schema) return; 47 | 48 | return zodValidator(target as ValidationTarget, schema); 49 | }) 50 | .filter((v) => !!v); 51 | 52 | const middleware = every(...validators); 53 | 54 | return Object.assign(middleware, metadata); 55 | }; 56 | } 57 | 58 | /** 59 | * Hono middleware that documents decorated route. Additionally validates request body/query params/path params etc., 60 | * the same way `@hono/zod-validator` does. 61 | * 62 | * @see HonoOpenApiOperation for more information on how to use it. 63 | */ 64 | export const openApi: HonoOpenApiMiddleware = createOpenApiMiddleware(); 65 | 66 | /** 67 | * A no-op function, used to ensure proper validator's type inference and provide autocomplete in cases where you don't want to define the spec inline. 68 | * @example 69 | * 70 | * ```ts 71 | * const operation = defineOpenApiOperation({ 72 | * responses: { 73 | * 200: z.object({ name: z.string() }), 74 | * }, 75 | * request: { 76 | * json: z.object({ email: z.string() }), 77 | * }, 78 | * }); 79 | * 80 | * const app = new Hono().post('/user', openApi(operation), async (c) => { 81 | * const { name } = c.req.valid('json'); 82 | * 83 | * return c.json({ name }, 200); 84 | * }); 85 | * ``` 86 | */ 87 | export const defineOpenApiOperation = ( 88 | operation: HonoOpenApiOperation, 89 | ) => operation; 90 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. 4 | 5 | ## [1.0.1](https://github.com/paolostyle/hono-zod-openapi/compare/v1.0.0...v1.0.1) (2025-10-05) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * missing deno importmap version updates ([d0a2366](https://github.com/paolostyle/hono-zod-openapi/commit/d0a23668efabdad793709c873e4e03a5829ec590)) 11 | 12 | ## [1.0.0](https://github.com/paolostyle/hono-zod-openapi/compare/v0.5.0...v1.0.0) (2025-10-05) 13 | 14 | 15 | ### ⚠ BREAKING CHANGES 16 | 17 | * require node v20 as v18 is deprecated already 18 | * **deps:** enforce zod v4 usage 19 | 20 | ### Miscellaneous Chores 21 | 22 | * **deps:** enforce zod v4 usage ([1d5fa2d](https://github.com/paolostyle/hono-zod-openapi/commit/1d5fa2d0c1c81ac436562ab237e0da3b33d93fae)) 23 | * require node v20 as v18 is deprecated already ([f32b6d3](https://github.com/paolostyle/hono-zod-openapi/commit/f32b6d3b258f8ae3b4cbdd3189261ca7ef9f19ff)) 24 | 25 | ## [0.5.0](https://github.com/paolostyle/hono-zod-openapi/compare/v0.4.2...v0.5.0) (2024-11-13) 26 | 27 | 28 | ### Features 29 | 30 | * **deps:** upgrade zod-openapi to 4.0.0 ([5f93eed](https://github.com/paolostyle/hono-zod-openapi/commit/5f93eedcf3fa9b2fb957ed9c40e789f3b66ebd88)) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * adjust paths with params to the OpenAPI format ([0f52006](https://github.com/paolostyle/hono-zod-openapi/commit/0f520066f30f1e0a73ae9fc5f19c7a27a44da471)) 36 | * require hono ^4.6.10 as it includes fix that closes [#15](https://github.com/paolostyle/hono-zod-openapi/issues/15) ([1617c09](https://github.com/paolostyle/hono-zod-openapi/commit/1617c097167680f6c8d4d4c6482c22f836116caf)) 37 | 38 | ## [0.4.2](https://github.com/paolostyle/hono-zod-openapi/compare/v0.4.1...v0.4.2) (2024-11-02) 39 | 40 | 41 | ### Miscellaneous Chores 42 | 43 | * fix JSR publishing through CI ([667f13b](https://github.com/paolostyle/hono-zod-openapi/commit/667f13b6cea0f29b6171f9c252b0d4767a01e23e)) 44 | * include missing JSDocs to exported types ([5a50697](https://github.com/paolostyle/hono-zod-openapi/commit/5a506970fcb559c7a3b260dfa3e85c85bb890aa8)) 45 | 46 | ## [0.4.1](https://github.com/paolostyle/hono-zod-openapi/compare/v0.4.0...v0.4.1) (2024-10-31) 47 | 48 | 49 | ### Bug Fixes 50 | 51 | * use NPM version of Hono to unblock JSR release ([e9b13a5](https://github.com/paolostyle/hono-zod-openapi/commit/e9b13a53078104b61564a4a6b8899919830e9364)) 52 | 53 | ## [0.4.0](https://github.com/paolostyle/hono-zod-openapi/compare/hono-zod-openapi-v0.3.1...hono-zod-openapi-v0.4.0) (2024-10-31) 54 | 55 | 56 | ### Features 57 | 58 | * add basic JSDocs ([fd8bb84](https://github.com/paolostyle/hono-zod-openapi/commit/fd8bb8443344273d063c0b3ad87d95f61b66b244)) 59 | 60 | ## [0.3.1](https://github.com/paolostyle/hono-zod-openapi/compare/v0.3.0...v0.3.1) (2024-10-22) 61 | 62 | ### Features 63 | 64 | - JSR/Deno support ([#5](https://github.com/paolostyle/hono-zod-openapi/issues/5)) ([93316f3](https://github.com/paolostyle/hono-zod-openapi/commit/93316f38e7b23b74e3386227f65cbb682babd220)) 65 | 66 | ## [0.3.0](https://github.com/paolostyle/hono-zod-openapi/compare/v0.2.1...v0.3.0) (2024-10-11) 67 | 68 | ### ⚠ BREAKING CHANGES 69 | 70 | - rename `Operation` type to `HonoOpenApiOperation` - technically breaking as it was exported, but realistically you wouldn't use it without a good reason. 71 | 72 | ### Features 73 | 74 | - rename `Operation` type to `HonoOpenApiOperation`, export `HonoOpenApiRequestSchemas` ([e2bdda1](https://github.com/paolostyle/hono-zod-openapi/commit/e2bdda1439c61d106acf2d42a691024f17f3a3ef)) 75 | 76 | ## [0.2.1](https://github.com/paolostyle/hono-zod-openapi/compare/v0.2.0...v0.2.1) (2024-10-11) 77 | 78 | ### Features 79 | 80 | - export some types that might be useful for users ([5ecd9f8](https://github.com/paolostyle/hono-zod-openapi/commit/5ecd9f81293d99199c39afcc830740ba905a6e45)) 81 | 82 | ### Bug Fixes 83 | 84 | - allow Hono instances with different Env type parameter than default ([f77869c](https://github.com/paolostyle/hono-zod-openapi/commit/f77869c4553c8cf64ec81cbea9744d924cd7d435)), closes [#2](https://github.com/paolostyle/hono-zod-openapi/issues/2) 85 | 86 | ## [0.2.0](https://github.com/paolostyle/hono-zod-openapi/compare/v0.1.1...v0.2.0) (2024-10-06) 87 | 88 | ### ⚠ BREAKING CHANGES 89 | 90 | - Major rewrite: please adjust your code to the latest version 91 | 92 | ### Features 93 | 94 | - major rewrite, stabilized public API, decent test coverage ([0f19085](https://github.com/paolostyle/hono-zod-openapi/commit/0f190855e2ca46777939b94681fdf91c4f7ff477)) 95 | - ~~response validator ([#1](https://github.com/paolostyle/hono-zod-openapi/issues/1)) ([12ed885](https://github.com/paolostyle/hono-zod-openapi/commit/12ed8854f7b351434dc7412e967f6f0632d9fbe1))~~ 96 | 97 | ## [0.1.1](https://github.com/paolostyle/hono-zod-openapi/compare/0e7d2905992ed0df2e5ed39e6b231750b9f46c0d...v0.1.1) (2024-09-19) 98 | 99 | ### Features 100 | 101 | - configurable routeName, third argument endpointDetails ([0e7d290](https://github.com/paolostyle/hono-zod-openapi/commit/0e7d2905992ed0df2e5ed39e6b231750b9f46c0d)) 102 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Env, 3 | MiddlewareHandler, 4 | ValidationTargets as ValidationTargetsWithForm, 5 | } from 'hono'; 6 | import type { StatusCode } from 'hono/utils/http-status'; 7 | import type * as z from 'zod'; 8 | import type { 9 | ZodOpenApiObject, 10 | ZodOpenApiOperationObject, 11 | ZodOpenApiResponseObject, 12 | } from 'zod-openapi'; 13 | 14 | // biome-ignore lint/suspicious/noExplicitAny: 15 | export type AnyZ = z.ZodType; 16 | 17 | export type ValidationTarget = 'json' | 'query' | 'param' | 'cookie' | 'header'; 18 | type RequestParam = ValidationTarget; 19 | type ValidationSchemas = Partial>; 20 | type ValidationTargets = Omit; 21 | 22 | export type ValidationTargetParams = { 23 | /** 24 | * Zod schema for the target. 25 | */ 26 | schema: T; 27 | /** 28 | * Determines whether the target should be validated or if the schema should only be used for documentation. 29 | * @default true 30 | */ 31 | validate?: boolean; 32 | }; 33 | 34 | type StatusCodePrefix = '1' | '2' | '3' | '4' | '5'; 35 | type StatusCodeWithoutMinus1 = Exclude; 36 | export type StatusCodeWithWildcards = 37 | | StatusCodeWithoutMinus1 38 | | `${StatusCodePrefix}XX` 39 | | 'default'; 40 | 41 | /** 42 | * Mapping of zod-validator targets to their respective schemas, used both as a source of truth 43 | * for validation and for OpenAPI documentation. 44 | */ 45 | export type HonoOpenApiRequestSchemas = Partial< 46 | Record | AnyZ> 47 | >; 48 | 49 | export type Method = 'get' | 'put' | 'post' | 'delete' | 'options' | 'patch'; 50 | export type NormalizedRequestSchemas = Partial>; 51 | 52 | type HasUndefined = undefined extends T ? true : false; 53 | type IsUnknown = unknown extends T 54 | ? [T] extends [null] 55 | ? false 56 | : true 57 | : false; 58 | type Clean = { 59 | [K in keyof T as T[K] extends never ? never : K]: T[K]; 60 | } & {}; 61 | 62 | type ExtractInValues< 63 | Schema extends AnyZ, 64 | Target extends keyof Omit, 65 | In = z.input, 66 | > = HasUndefined extends true 67 | ? In extends ValidationTargets[Target] 68 | ? In 69 | : { [K2 in keyof In]?: ValidationTargets[Target][K2] } 70 | : In extends ValidationTargets[Target] 71 | ? In 72 | : { [K2 in keyof In]: ValidationTargets[Target][K2] }; 73 | 74 | type GetValidationSchemas = Clean<{ 75 | [K in keyof T]: T[K] extends ValidationTargetParams 76 | ? T[K]['validate'] extends false 77 | ? never 78 | : S 79 | : T[K] extends AnyZ 80 | ? T[K] 81 | : never; 82 | }>; 83 | 84 | type ToValidatorValues = { 85 | in: Clean<{ 86 | [K in keyof ValidationTargets]: IsUnknown extends true 87 | ? never 88 | : ExtractInValues, K>; 89 | }>; 90 | out: Clean<{ 91 | [K in keyof ValidationTargets]: IsUnknown extends true 92 | ? never 93 | : z.output>; 94 | }>; 95 | }; 96 | 97 | export type Values = ToValidatorValues< 98 | GetValidationSchemas 99 | >; 100 | 101 | export type ZodValidatorFn = < 102 | S extends AnyZ, 103 | T extends keyof ValidationTargets, 104 | >( 105 | target: T, 106 | schema: S, 107 | ) => MiddlewareHandler; 108 | 109 | export type EndpointDetails = Omit< 110 | ZodOpenApiOperationObject, 111 | 'responses' | 'requestBody' | 'requestParams' 112 | >; 113 | 114 | export interface ReferenceObject { 115 | $ref: string; 116 | summary?: string; 117 | description?: string; 118 | } 119 | 120 | interface SimpleResponseObject 121 | extends Pick { 122 | description?: string; 123 | schema: AnyZ; 124 | mediaType?: string; 125 | } 126 | 127 | /** 128 | * OpenAPI response object, augmented with Zod-based schema. 129 | */ 130 | export type HonoOpenApiResponseObject = 131 | | ZodOpenApiResponseObject 132 | | SimpleResponseObject 133 | | AnyZ 134 | | ReferenceObject; 135 | 136 | export type HonoOpenApiResponses = Partial< 137 | Record 138 | >; 139 | 140 | /** 141 | * OpenAPI operation object, augmented with Zod-based request and response schemas. 142 | * See README for exhaustive set of examples. 143 | */ 144 | export interface HonoOpenApiOperation< 145 | Req extends HonoOpenApiRequestSchemas = HonoOpenApiRequestSchemas, 146 | > extends Omit { 147 | request?: Req; 148 | responses: HonoOpenApiResponses; 149 | } 150 | 151 | /** 152 | * zod-openapi document without `openapi` property (set to 3.1.0, we do not support lower versions). 153 | * @see https://swagger.io/specification/ 154 | */ 155 | export type HonoOpenApiDocument = Omit; 156 | 157 | export type HonoOpenApiMiddleware = < 158 | Req extends HonoOpenApiRequestSchemas, 159 | E extends Env, 160 | P extends string, 161 | >( 162 | operation: HonoOpenApiOperation, 163 | ) => MiddlewareHandler>; 164 | -------------------------------------------------------------------------------- /src/createOpenApiDocument.ts: -------------------------------------------------------------------------------- 1 | import type { Env, Hono, Schema } from 'hono'; 2 | import * as z from 'zod'; 3 | import { 4 | type ZodOpenApiOperationObject, 5 | type ZodOpenApiPathsObject, 6 | type ZodOpenApiResponsesObject, 7 | createDocument, 8 | } from 'zod-openapi'; 9 | import { normalizeResponse } from './normalizeResponse.ts'; 10 | import { OpenApiSymbol } from './openApi.ts'; 11 | import type { 12 | HonoOpenApiDocument, 13 | HonoOpenApiOperation, 14 | HonoOpenApiRequestSchemas, 15 | HonoOpenApiResponses, 16 | Method, 17 | NormalizedRequestSchemas, 18 | StatusCodeWithWildcards, 19 | } from './types.ts'; 20 | 21 | interface DocumentRouteSettings { 22 | /** 23 | * Whether to add a new route with the OpenAPI document. 24 | * @default true 25 | */ 26 | addRoute?: boolean; 27 | /** 28 | * Route name under which the OpenAPI document will be available, assuming `settings.addRoute` is `true`. 29 | * @default '/doc' 30 | */ 31 | routeName?: string; 32 | } 33 | 34 | /** 35 | * Creates an OpenAPI document from a Hono router based on the routes decorated with `openApi` middleware. 36 | * By default it will create a new route at `/doc` that returns the OpenAPI document. 37 | * @param router Hono router containing routes decorated with `openApi` middleware 38 | * @param document OpenAPI document base. An object with at least `info` property is required 39 | * @param [routeSettings] Settings for the route that will serve the OpenAPI document 40 | * @returns object representing the OpenAPI document 41 | * 42 | * @example 43 | * ```ts 44 | * import { Hono } from 'hono'; 45 | * import { z } from 'zod'; 46 | * import { createOpenApiDocument, openApi } from 'hono-zod-openapi'; 47 | * 48 | * export const app = new Hono().get( 49 | * '/user', 50 | * openApi({ 51 | * tags: ['User'], 52 | * responses: { 53 | * 200: z.object({ hi: z.string() }).meta({ example: { hi: 'user' } }), 54 | * }, 55 | * request: { 56 | * query: z.object({ id: z.string() }), 57 | * }, 58 | * }), 59 | * (c) => { 60 | * const { id } = c.req.valid('query'); 61 | * return c.json({ hi: id }, 200); 62 | * }, 63 | * ); 64 | * 65 | * createOpenApiDocument(app, { 66 | * info: { 67 | * title: 'Example API', 68 | * version: '1.0.0', 69 | * }, 70 | * }); 71 | * ``` 72 | */ 73 | export function createOpenApiDocument< 74 | E extends Env, 75 | S extends Schema, 76 | P extends string, 77 | >( 78 | router: Hono, 79 | document: HonoOpenApiDocument, 80 | { addRoute = true, routeName = '/doc' }: DocumentRouteSettings = {}, 81 | ): ReturnType { 82 | const paths: ZodOpenApiPathsObject = {}; 83 | 84 | const decoratedRoutes = router.routes.filter( 85 | (route) => OpenApiSymbol in route.handler, 86 | ); 87 | 88 | for (const route of decoratedRoutes) { 89 | // biome-ignore lint/suspicious/noExplicitAny: must be done this way as we're smuggling the metadata behind user's back 90 | const { request, responses, ...rest } = (route.handler as any)[ 91 | OpenApiSymbol 92 | ] as HonoOpenApiOperation; 93 | 94 | const path = normalizePathParams(route.path); 95 | const pathWithMethod = `${route.method} ${path}`; 96 | 97 | const operation: ZodOpenApiOperationObject = { 98 | responses: processResponses(responses, pathWithMethod), 99 | ...(request ? processRequest(request) : {}), 100 | ...rest, 101 | }; 102 | 103 | if (!(path in paths)) { 104 | paths[path] = {}; 105 | } 106 | 107 | paths[path][route.method.toLowerCase() as Method] = operation; 108 | } 109 | 110 | const openApiDoc = createDocument({ 111 | ...document, 112 | openapi: '3.1.0', 113 | paths: { 114 | ...document.paths, 115 | ...paths, 116 | }, 117 | }); 118 | 119 | if (addRoute) { 120 | router.get(routeName, (c) => c.json(openApiDoc, 200)); 121 | } 122 | 123 | return openApiDoc; 124 | } 125 | 126 | export const processRequest = ( 127 | req: HonoOpenApiRequestSchemas, 128 | ): Pick => { 129 | const normalizedReq: NormalizedRequestSchemas = Object.fromEntries( 130 | Object.entries(req).map( 131 | ([key, value]) => 132 | [key, value instanceof z.ZodType ? value : value.schema] as const, 133 | ), 134 | ); 135 | 136 | const requestParams = Object.fromEntries( 137 | Object.entries({ 138 | cookie: normalizedReq.cookie, 139 | header: normalizedReq.header, 140 | query: normalizedReq.query, 141 | path: normalizedReq.param, 142 | }).filter(([_, schema]) => schema !== undefined), 143 | ); 144 | 145 | return { 146 | requestParams, 147 | requestBody: normalizedReq.json && { 148 | content: { 149 | 'application/json': { 150 | schema: normalizedReq.json, 151 | }, 152 | }, 153 | }, 154 | }; 155 | }; 156 | 157 | export const processResponses = ( 158 | res: HonoOpenApiResponses, 159 | path: string, 160 | ): ZodOpenApiResponsesObject => { 161 | return Object.fromEntries( 162 | Object.entries(res).map(([status, schema]) => { 163 | const response = normalizeResponse( 164 | schema, 165 | status as StatusCodeWithWildcards, 166 | path, 167 | ); 168 | return [status, response]; 169 | }), 170 | ); 171 | }; 172 | 173 | export const normalizePathParams = (path: string): string => { 174 | return path.replace(/:([a-zA-Z0-9-_]+)\??(\{.*?\})?/g, '{$1}'); 175 | }; 176 | -------------------------------------------------------------------------------- /src/normalizeResponse.test.ts: -------------------------------------------------------------------------------- 1 | import { beforeEach, describe, expect, it, vi } from 'vitest'; 2 | import * as z from 'zod'; 3 | import { normalizeResponse } from './normalizeResponse.ts'; 4 | import type { HonoOpenApiResponseObject } from './types.ts'; 5 | 6 | describe('normalize response', () => { 7 | beforeEach(() => { 8 | const warnCopy = console.warn; 9 | console.warn = vi.fn(); 10 | 11 | return () => { 12 | console.warn = warnCopy; 13 | }; 14 | }); 15 | 16 | it('returns self when passed reference object', () => { 17 | const refObject = { $ref: '#/components/schemas/SomeSchema' }; 18 | 19 | expect(normalizeResponse(refObject, 200, 'GET /somePath')).toEqual( 20 | refObject, 21 | ); 22 | }); 23 | 24 | it('returns self when passed zod-openapi response object', () => { 25 | const zodOpenApiResponseObject = { 26 | description: '200 OK', 27 | content: { 28 | 'application/json': { 29 | schema: z.object({ 30 | id: z.number(), 31 | name: z.string(), 32 | }), 33 | }, 34 | }, 35 | }; 36 | 37 | expect( 38 | normalizeResponse(zodOpenApiResponseObject, 200, 'GET /somePath'), 39 | ).toEqual(zodOpenApiResponseObject); 40 | }); 41 | 42 | it('returns self when passed plain OpenAPI response object', () => { 43 | const openApiResponseObject = { 44 | description: '200 OK', 45 | content: { 46 | 'application/json': { 47 | schema: { 48 | type: 'object', 49 | properties: { 50 | id: { type: 'number' }, 51 | name: { type: 'string' }, 52 | }, 53 | }, 54 | }, 55 | }, 56 | } as const; 57 | 58 | expect( 59 | normalizeResponse(openApiResponseObject, 200, 'GET /somePath'), 60 | ).toEqual(openApiResponseObject); 61 | }); 62 | 63 | describe('for zod schema', () => { 64 | it('normalizes object schema to application/json', () => { 65 | const objectSchema = z.object({ 66 | id: z.number(), 67 | name: z.string(), 68 | }); 69 | 70 | expect(normalizeResponse(objectSchema, 200, 'GET /somePath')).toEqual({ 71 | description: '200 OK', 72 | content: { 73 | 'application/json': { 74 | schema: objectSchema, 75 | }, 76 | }, 77 | }); 78 | expect(console.warn).not.toHaveBeenCalled(); 79 | }); 80 | 81 | it('normalizes array schema to application/json', () => { 82 | const arraySchema = z.array(z.string()); 83 | 84 | expect(normalizeResponse(arraySchema, 200, 'GET /somePath')).toEqual({ 85 | description: '200 OK', 86 | content: { 87 | 'application/json': { 88 | schema: arraySchema, 89 | }, 90 | }, 91 | }); 92 | expect(console.warn).not.toHaveBeenCalled(); 93 | }); 94 | 95 | it('normalizes string schema to text/plain and warns about no explicit mediaType', () => { 96 | const stringSchema = z.string(); 97 | 98 | expect(normalizeResponse(stringSchema, 200, 'GET /somePath')).toEqual({ 99 | description: '200 OK', 100 | content: { 101 | 'text/plain': { 102 | schema: stringSchema, 103 | }, 104 | }, 105 | }); 106 | expect(console.warn).toHaveBeenCalledWith( 107 | `Your schema for GET /somePath is not an object or array, it's recommended to provide an explicit mediaType.`, 108 | ); 109 | }); 110 | 111 | it('warns about no explicit mediaType for non-object and non-array schema but still defaults to application/json', () => { 112 | const numberSchema = z.number(); 113 | 114 | expect(normalizeResponse(numberSchema, 200, 'GET /somePath')).toEqual({ 115 | description: '200 OK', 116 | content: { 117 | 'application/json': { 118 | schema: numberSchema, 119 | }, 120 | }, 121 | }); 122 | expect(console.warn).toHaveBeenCalledWith( 123 | `Your schema for GET /somePath is not an object or array, it's recommended to provide an explicit mediaType.`, 124 | ); 125 | }); 126 | }); 127 | 128 | describe('for custom notation', () => { 129 | it('normalizes zod object schema to application/json', () => { 130 | const objectSchema: HonoOpenApiResponseObject = { 131 | schema: z.object({ 132 | id: z.number(), 133 | name: z.string(), 134 | }), 135 | }; 136 | 137 | expect(normalizeResponse(objectSchema, 200, 'GET /somePath')).toEqual({ 138 | description: '200 OK', 139 | content: { 140 | 'application/json': { 141 | schema: objectSchema.schema, 142 | }, 143 | }, 144 | }); 145 | expect(console.warn).not.toHaveBeenCalled(); 146 | }); 147 | 148 | it('normalizes zod array schema to application/json', () => { 149 | const arraySchema: HonoOpenApiResponseObject = { 150 | schema: z.array(z.string()), 151 | }; 152 | 153 | expect(normalizeResponse(arraySchema, 200, 'GET /somePath')).toEqual({ 154 | description: '200 OK', 155 | content: { 156 | 'application/json': { 157 | schema: arraySchema.schema, 158 | }, 159 | }, 160 | }); 161 | expect(console.warn).not.toHaveBeenCalled(); 162 | }); 163 | 164 | it('normalizes zod string schema to text/plain and warns about no explicit mediaType', () => { 165 | const stringSchema: HonoOpenApiResponseObject = { 166 | schema: z.string(), 167 | }; 168 | 169 | expect(normalizeResponse(stringSchema, 200, 'GET /somePath')).toEqual({ 170 | description: '200 OK', 171 | content: { 172 | 'text/plain': { 173 | schema: stringSchema.schema, 174 | }, 175 | }, 176 | }); 177 | expect(console.warn).toHaveBeenCalledWith( 178 | `Your schema for GET /somePath is not an object or array, it's recommended to provide an explicit mediaType.`, 179 | ); 180 | }); 181 | 182 | it('normalizes zod string schema to text/html when mediaType is provided without warning', () => { 183 | const stringSchema: HonoOpenApiResponseObject = { 184 | schema: z.string(), 185 | mediaType: 'text/html', 186 | }; 187 | 188 | expect(normalizeResponse(stringSchema, 200, 'GET /somePath')).toEqual({ 189 | description: '200 OK', 190 | content: { 191 | 'text/html': { 192 | schema: stringSchema.schema, 193 | }, 194 | }, 195 | }); 196 | expect(console.warn).not.toHaveBeenCalled(); 197 | }); 198 | 199 | it('allows empty schema when description provided', () => { 200 | const emptySchema: HonoOpenApiResponseObject = { 201 | description: 'Empty response', 202 | }; 203 | 204 | expect(normalizeResponse(emptySchema, 204, 'GET /somePath')).toEqual( 205 | emptySchema, 206 | ); 207 | expect(console.warn).not.toHaveBeenCalled(); 208 | }); 209 | 210 | it('properly passes other attributes', () => { 211 | const responseObj: HonoOpenApiResponseObject = { 212 | schema: z.object({ 213 | id: z.number(), 214 | name: z.string(), 215 | }), 216 | description: 'Custom description', 217 | mediaType: 'application/xml', // I don't think this makes sense but just for testing 218 | headers: z.object({ 219 | 'x-custom-header': z.string(), 220 | }), 221 | links: { 222 | 'x-custom-link': { 223 | summary: 'Custom link', 224 | }, 225 | }, 226 | }; 227 | 228 | expect(normalizeResponse(responseObj, 200, 'GET /somePath')).toEqual({ 229 | description: 'Custom description', 230 | content: { 231 | 'application/xml': { 232 | schema: responseObj.schema, 233 | }, 234 | }, 235 | headers: responseObj.headers, 236 | links: responseObj.links, 237 | }); 238 | }); 239 | }); 240 | }); 241 | -------------------------------------------------------------------------------- /src/createOpenApiDocument.test.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from 'hono'; 2 | import { describe, expect, it } from 'vitest'; 3 | import * as z from 'zod'; 4 | import { 5 | createOpenApiDocument, 6 | normalizePathParams, 7 | } from './createOpenApiDocument.ts'; 8 | import { defineOpenApiOperation, openApi } from './openApi.ts'; 9 | import type { 10 | HonoOpenApiOperation, 11 | HonoOpenApiRequestSchemas, 12 | } from './types.ts'; 13 | 14 | const documentData = { 15 | info: { 16 | title: 'Some API', 17 | version: '0.0.1', 18 | }, 19 | }; 20 | 21 | describe('createOpenApiDocument', () => { 22 | it('correctly passes metadata to the document and creates the document under /doc route', async () => { 23 | const app = new Hono(); 24 | 25 | createOpenApiDocument(app, documentData); 26 | 27 | const response = await app.request('/doc'); 28 | const openApiSpec = await response.json(); 29 | 30 | expect(response.status).toBe(200); 31 | expect(openApiSpec.openapi).toEqual('3.1.0'); 32 | expect(openApiSpec.info).toEqual(documentData.info); 33 | }); 34 | 35 | it('does not create route when addRoute = false', () => { 36 | const app = new Hono(); 37 | 38 | createOpenApiDocument(app, documentData, { addRoute: false }); 39 | 40 | expect(app.routes).toEqual([]); 41 | }); 42 | 43 | it('creates a route under different name when routeName is provided', () => { 44 | const app = new Hono(); 45 | 46 | createOpenApiDocument(app, documentData, { routeName: '/api-docs' }); 47 | 48 | expect(app.routes[0].path).toEqual('/api-docs'); 49 | }); 50 | 51 | it('correctly adds additional attributes to the document', async () => { 52 | const app = new Hono(); 53 | 54 | createOpenApiDocument(app, { 55 | ...documentData, 56 | servers: [{ url: 'https://api.example.com' }], 57 | }); 58 | 59 | const response = await app.request('/doc'); 60 | const openApiSpec = await response.json(); 61 | 62 | expect(openApiSpec.servers).toEqual([{ url: 'https://api.example.com' }]); 63 | }); 64 | 65 | it('returns correct openapi doc for simple response format', async () => { 66 | const app = new Hono().get( 67 | '/user', 68 | openApi({ 69 | responses: { 70 | 200: z.object({ hi: z.string() }).meta({ 71 | example: { hi: 'henlo' }, 72 | }), 73 | }, 74 | }), 75 | async (c) => { 76 | return c.json({ hi: 'string' }, 200); 77 | }, 78 | ); 79 | 80 | createOpenApiDocument(app, documentData); 81 | 82 | const response = await app.request('/doc'); 83 | const openApiSpec = await response.json(); 84 | 85 | expect(openApiSpec.paths['/user'].get.responses[200]).toEqual({ 86 | content: { 87 | 'application/json': { 88 | schema: { 89 | additionalProperties: false, 90 | example: { 91 | hi: 'henlo', 92 | }, 93 | properties: { 94 | hi: { 95 | type: 'string', 96 | }, 97 | }, 98 | required: ['hi'], 99 | type: 'object', 100 | }, 101 | }, 102 | }, 103 | description: '200 OK', 104 | }); 105 | }); 106 | 107 | it('returns correct openapi doc for custom object response format', async () => { 108 | const app = new Hono().get( 109 | '/user', 110 | openApi({ 111 | responses: { 112 | 200: { 113 | schema: z.object({ hi: z.string() }).meta({ 114 | example: { hi: 'henlo' }, 115 | }), 116 | description: 'Great success', 117 | }, 118 | }, 119 | }), 120 | async (c) => { 121 | return c.json({ hi: 'string' }, 200); 122 | }, 123 | ); 124 | 125 | createOpenApiDocument(app, documentData); 126 | 127 | const response = await app.request('/doc'); 128 | const openApiSpec = await response.json(); 129 | 130 | expect(openApiSpec.paths['/user'].get.responses[200]).toEqual({ 131 | content: { 132 | 'application/json': { 133 | schema: { 134 | additionalProperties: false, 135 | example: { 136 | hi: 'henlo', 137 | }, 138 | properties: { 139 | hi: { 140 | type: 'string', 141 | }, 142 | }, 143 | required: ['hi'], 144 | type: 'object', 145 | }, 146 | }, 147 | }, 148 | description: 'Great success', 149 | }); 150 | }); 151 | 152 | it('properly handles multiple responses', async () => { 153 | const app = new Hono().get( 154 | '/example', 155 | openApi({ 156 | responses: { 157 | 200: z.object({ wow: z.string() }), 158 | 400: z.object({ error: z.string() }), 159 | }, 160 | }), 161 | async (c) => { 162 | if (Math.random() > 0.5) { 163 | return c.json({ error: 'sike, wrong number' }, 200); 164 | } 165 | 166 | return c.json({ wow: 'cool' }, 200); 167 | }, 168 | ); 169 | 170 | createOpenApiDocument(app, documentData); 171 | 172 | const response = await app.request('/doc'); 173 | const openApiSpec = await response.json(); 174 | 175 | expect(openApiSpec.paths['/example'].get.responses[200]).toEqual({ 176 | content: { 177 | 'application/json': { 178 | schema: { 179 | additionalProperties: false, 180 | properties: { 181 | wow: { 182 | type: 'string', 183 | }, 184 | }, 185 | required: ['wow'], 186 | type: 'object', 187 | }, 188 | }, 189 | }, 190 | description: '200 OK', 191 | }); 192 | 193 | expect(openApiSpec.paths['/example'].get.responses[400]).toEqual({ 194 | content: { 195 | 'application/json': { 196 | schema: { 197 | additionalProperties: false, 198 | properties: { 199 | error: { 200 | type: 'string', 201 | }, 202 | }, 203 | required: ['error'], 204 | type: 'object', 205 | }, 206 | }, 207 | }, 208 | description: '400 Bad Request', 209 | }); 210 | }); 211 | 212 | it('properly passes request schema to the document', async () => { 213 | const app = new Hono().get( 214 | '/example', 215 | openApi({ 216 | request: { 217 | query: z.object({ name: z.string() }), 218 | cookie: { 219 | schema: z.object({ token: z.string() }), 220 | validate: false, 221 | }, 222 | }, 223 | responses: { 224 | 200: z.object({ hi: z.string() }), 225 | }, 226 | }), 227 | async (c) => { 228 | return c.json({ wow: 'cool' }, 200); 229 | }, 230 | ); 231 | 232 | createOpenApiDocument(app, documentData); 233 | 234 | const response = await app.request('/doc'); 235 | const openApiSpec = await response.json(); 236 | 237 | expect(openApiSpec.paths['/example'].get.parameters).toEqual([ 238 | { 239 | in: 'cookie', 240 | name: 'token', 241 | required: true, 242 | schema: { 243 | type: 'string', 244 | }, 245 | }, 246 | { 247 | in: 'query', 248 | name: 'name', 249 | required: true, 250 | schema: { 251 | type: 'string', 252 | }, 253 | }, 254 | ]); 255 | }); 256 | 257 | it('properly passes request body to the document', async () => { 258 | const app = new Hono().post( 259 | '/example', 260 | openApi({ 261 | request: { 262 | json: z.object({ name: z.string() }), 263 | }, 264 | responses: { 265 | 200: z.object({ hi: z.string() }), 266 | }, 267 | }), 268 | async (c) => { 269 | return c.json({ wow: 'cool' }, 200); 270 | }, 271 | ); 272 | 273 | createOpenApiDocument(app, documentData); 274 | 275 | const response = await app.request('/doc'); 276 | const openApiSpec = await response.json(); 277 | 278 | expect(openApiSpec.paths['/example'].post.requestBody).toEqual({ 279 | content: { 280 | 'application/json': { 281 | schema: { 282 | properties: { 283 | name: { 284 | type: 'string', 285 | }, 286 | }, 287 | required: ['name'], 288 | type: 'object', 289 | }, 290 | }, 291 | }, 292 | }); 293 | }); 294 | 295 | it('works with Hono instance with type parameters', () => { 296 | const taggedAuthRoute = ( 297 | tag: string, 298 | doc: HonoOpenApiOperation, 299 | ) => { 300 | return defineOpenApiOperation({ 301 | ...doc, 302 | tags: [tag], 303 | security: [{ apiKey: [] }], 304 | }); 305 | }; 306 | 307 | const app = new Hono<{ Bindings: { env: 'test' } }>().basePath('/api').get( 308 | '/example', 309 | openApi( 310 | taggedAuthRoute('auth', { 311 | responses: { 312 | 200: z.object({ hi: z.string() }), 313 | }, 314 | request: { 315 | query: z.object({ name: z.string() }), 316 | }, 317 | }), 318 | ), 319 | async (c) => { 320 | const { name } = c.req.valid('query'); 321 | }, 322 | ); 323 | 324 | createOpenApiDocument(app, documentData); 325 | }); 326 | 327 | it('normalizes path parameters correctly', async () => { 328 | const app = new Hono().get( 329 | '/user/:id', 330 | openApi({ 331 | request: { 332 | param: z.object({ id: z.string() }), 333 | }, 334 | responses: { 335 | 200: z.object({ id: z.string() }), 336 | }, 337 | }), 338 | async (c) => { 339 | const { id } = c.req.valid('param'); 340 | return c.json({ id }, 200); 341 | }, 342 | ); 343 | 344 | createOpenApiDocument(app, documentData); 345 | 346 | const response = await app.request('/doc'); 347 | const openApiSpec = await response.json(); 348 | 349 | expect(openApiSpec.paths['/user/{id}'].get.parameters).toEqual([ 350 | { 351 | in: 'path', 352 | name: 'id', 353 | required: true, 354 | schema: { 355 | type: 'string', 356 | }, 357 | }, 358 | ]); 359 | 360 | expect(openApiSpec.paths['/user/{id}']).toBeDefined(); 361 | }); 362 | }); 363 | 364 | describe('normalizePathParams', () => { 365 | it.each` 366 | honoPath | openApiPath 367 | ${':date{[0-9]+}'} | ${'{date}'} 368 | ${'/post/:date{[0-9]+}/:title{[a-z]+}'} | ${'/post/{date}/{title}'} 369 | ${'/posts/:filename{.+\\.png$}'} | ${'/posts/{filename}'} 370 | ${'/api/animal/:type?'} | ${'/api/animal/{type}'} 371 | ${'/:kek-1'} | ${'/{kek-1}'} 372 | ${'/:kek_id'} | ${'/{kek_id}'} 373 | ${'/posts/:id/comment/:comment_id'} | ${'/posts/{id}/comment/{comment_id}'} 374 | `('normalizes $honoPath to $openApiPath', ({ honoPath, openApiPath }) => { 375 | expect(normalizePathParams(honoPath)).toBe(openApiPath); 376 | }); 377 | }); 378 | -------------------------------------------------------------------------------- /src/openApi.test.ts: -------------------------------------------------------------------------------- 1 | import { Hono, type MiddlewareHandler } from 'hono'; 2 | import { testClient } from 'hono/testing'; 3 | import { describe, expect, expectTypeOf, it, vi } from 'vitest'; 4 | import * as z from 'zod'; 5 | import { 6 | createOpenApiMiddleware, 7 | defineOpenApiOperation, 8 | openApi, 9 | } from './openApi.ts'; 10 | 11 | describe('object-based openApi middleware', () => { 12 | it('works fine with request: undefined', async () => { 13 | const app = new Hono().post( 14 | '/user', 15 | openApi({ 16 | responses: { 17 | 200: z.object({ name: z.string() }), 18 | }, 19 | }), 20 | async (c) => { 21 | return c.json({ name: 'John' }, 200); 22 | }, 23 | ); 24 | 25 | const client = testClient(app); 26 | const response = await client.user.$post({}); 27 | 28 | expect(response.status).toBe(200); 29 | expect(await response.json()).toEqual({ name: 'John' }); 30 | }); 31 | 32 | it('integrates with zodValidator and validates request body', async () => { 33 | const app = new Hono().post( 34 | '/user', 35 | openApi({ 36 | responses: { 37 | default: z.object({ name: z.string() }), 38 | }, 39 | request: { 40 | json: z.object({ name: z.string() }), 41 | }, 42 | }), 43 | async (c) => { 44 | const body = c.req.valid('json'); 45 | 46 | expectTypeOf(body).toEqualTypeOf<{ name: string }>(); 47 | 48 | // @ts-expect-error c.req.valid() should only accept json 49 | const nonExistent = c.req.valid('cookie'); 50 | // @ts-expect-error c.req.valid() should only accept json 51 | const nonExistent2 = c.req.valid('header'); 52 | // @ts-expect-error c.req.valid() should only accept json 53 | const nonExistent3 = c.req.valid('query'); 54 | // @ts-expect-error c.req.valid() should only accept json 55 | const nonExistent4 = c.req.valid('param'); 56 | 57 | return c.json(body, 200); 58 | }, 59 | ); 60 | 61 | const client = testClient(app); 62 | const response = await client.user.$post({ json: { name: 'John' } }); 63 | 64 | expect(response.status).toBe(200); 65 | expect(await response.json()).toEqual({ name: 'John' }); 66 | 67 | // @ts-expect-error name should be a string 68 | const response2 = await client.user.$post({ json: { name: 123 } }); 69 | expect(response2.status).toBe(400); 70 | const errorResponse = (await response2.json()) as any; 71 | expect(errorResponse).toEqual({ 72 | error: { 73 | message: expect.stringContaining('expected string, received number'), 74 | name: 'ZodError', 75 | }, 76 | success: false, 77 | }); 78 | }); 79 | 80 | it.each(['cookie', 'header', 'query', 'param', 'json'] as const)( 81 | 'passes target %s and schema to validator', 82 | async (type) => { 83 | const validatorMock = vi.fn(); 84 | const someSchema = z.object({ name: z.string() }).optional(); 85 | const middleware = createOpenApiMiddleware(validatorMock); 86 | 87 | const app = new Hono().post( 88 | '/user', 89 | middleware({ 90 | request: { 91 | [type]: someSchema, 92 | }, 93 | responses: { 94 | default: someSchema, 95 | }, 96 | }), 97 | async (c) => { 98 | return c.json({ name: 'John' }, 200); 99 | }, 100 | ); 101 | 102 | const client = testClient(app); 103 | await client.user.$post({} as any); 104 | 105 | expect(validatorMock).toHaveBeenCalledWith(type, someSchema); 106 | }, 107 | ); 108 | 109 | it('passes multiple targets and schemas to validator', async () => { 110 | const validatorMock = vi.fn(); 111 | const someSchema = z.object({ name: z.string() }); 112 | const middleware = createOpenApiMiddleware(validatorMock); 113 | 114 | const app = new Hono().post( 115 | '/user', 116 | middleware({ 117 | responses: { 118 | 200: someSchema, 119 | }, 120 | request: { 121 | cookie: someSchema, 122 | header: someSchema, 123 | query: someSchema, 124 | json: someSchema, 125 | // alternative version though a bit redundant 126 | param: { schema: someSchema, validate: true }, 127 | }, 128 | }), 129 | async (c) => { 130 | return c.json({ name: 'John' }, 200); 131 | }, 132 | ); 133 | 134 | const client = testClient(app); 135 | await client.user.$post({} as any); 136 | 137 | expect(validatorMock).toHaveBeenCalledWith('cookie', someSchema); 138 | expect(validatorMock).toHaveBeenCalledWith('header', someSchema); 139 | expect(validatorMock).toHaveBeenCalledWith('query', someSchema); 140 | expect(validatorMock).toHaveBeenCalledWith('json', someSchema); 141 | expect(validatorMock).toHaveBeenCalledWith('param', someSchema); 142 | }); 143 | 144 | it('does not validate when validate is false', async () => { 145 | const validatorMock = vi.fn(); 146 | const someSchema = z.object({ name: z.string() }); 147 | const middleware = createOpenApiMiddleware(validatorMock); 148 | 149 | const app = new Hono().post( 150 | '/user', 151 | middleware({ 152 | responses: { 153 | 200: someSchema, 154 | }, 155 | request: { 156 | cookie: { schema: someSchema, validate: false }, 157 | header: { schema: someSchema, validate: false }, 158 | query: { schema: someSchema, validate: false }, 159 | json: { schema: someSchema, validate: false }, 160 | param: { schema: someSchema, validate: false }, 161 | }, 162 | }), 163 | async (c) => { 164 | // @ts-expect-error c.req.valid() should not accept any target 165 | const body = c.req.valid('json'); 166 | // @ts-expect-error c.req.valid() should not accept any target 167 | const nonExistent = c.req.valid('cookie'); 168 | // @ts-expect-error c.req.valid() should not accept any target 169 | const nonExistent2 = c.req.valid('header'); 170 | // @ts-expect-error c.req.valid() should not accept any target 171 | const nonExistent3 = c.req.valid('query'); 172 | // @ts-expect-error c.req.valid() should not accept any target 173 | const nonExistent4 = c.req.valid('param'); 174 | 175 | return c.json({ name: 'John' }, 200); 176 | }, 177 | ); 178 | 179 | const client = testClient(app); 180 | await client.user.$post({}); 181 | 182 | expect(validatorMock).not.toHaveBeenCalled(); 183 | }); 184 | 185 | it('types are working correctly when passed defined openAPI operation', async () => { 186 | const operation = defineOpenApiOperation({ 187 | responses: { 188 | 200: z.object({ name: z.string() }), 189 | }, 190 | request: { 191 | header: z.object({ 'api-key': z.string() }), 192 | json: z.object({ email: z.string() }), 193 | }, 194 | }); 195 | 196 | new Hono().post('/user', openApi(operation), async (c) => { 197 | const body = c.req.valid('json'); 198 | expectTypeOf(body).toEqualTypeOf<{ email: string }>(); 199 | 200 | const header = c.req.valid('header'); 201 | expectTypeOf(header).toEqualTypeOf<{ 'api-key': string }>(); 202 | 203 | return c.json({ name: 'John' }, 200); 204 | }); 205 | }); 206 | 207 | it('works on type-level with all possible response variants', () => { 208 | new Hono().post( 209 | '/user', 210 | openApi({ 211 | responses: { 212 | // 1. minimal version: just zod schema, media type is inferred to be application/json 213 | default: z.object({ name: z.string() }), 214 | // 2. library's own object notation 215 | // 2a. just schema, media type is inferred to be text/plain for z.strings() 216 | 200: { 217 | schema: z.string(), 218 | }, 219 | // 2b. schema + headers, media type is inferred to be application/json 220 | 201: { 221 | schema: z.object({ name: z.string() }), 222 | headers: z.object({ 'x-custom-header': z.string() }), 223 | }, 224 | // 2c. custom description (description is required in OpenAPI but we're providing defaults) 225 | 202: { 226 | description: 'Result is accepted', 227 | schema: z 228 | .object({ name: z.string() }) 229 | .meta({ example: { name: 'John' } }), 230 | }, 231 | // 2d. custom description, schema, explicit media type 232 | 203: { 233 | description: 'Some custom description', 234 | schema: z.string(), 235 | mediaType: 'text/html', 236 | }, 237 | // 2e. no response body: you need to provide at least a description 238 | 204: { 239 | description: 'No content', 240 | }, 241 | // 2f. no response body, but returns headers - still need to provide at least a description 242 | 205: { 243 | description: 'Just headers', 244 | headers: z.object({ 'x-custom-header': z.string() }), 245 | }, 246 | // 3. _invalid_ library's own object notations, some should be perhaps allowed 247 | // @ts-expect-error 3a. empty object - just add a description 248 | 300: {}, 249 | // @ts-expect-error 3b. just headers without description - just add a description 250 | 301: { 251 | headers: z.object({ 'x-custom-header': z.string() }), 252 | }, 253 | // @ts-expect-error 3c. just mediaType, adding description fixes the TypeScript error but it won't result in anything sensible 254 | 302: { 255 | mediaType: 'text/html', 256 | }, 257 | // 4. zod-openapi notation - description required, content type explicit, schema is a zod schema 258 | 400: { 259 | description: 'Some custom description', 260 | content: { 261 | 'application/json': { 262 | schema: z 263 | .object({ name: z.string() }) 264 | .meta({ example: { name: 'John' } }), 265 | }, 266 | }, 267 | }, 268 | // 5. regular OpenAPI notation - description required, content type explicit, schema is an OpenAPI object 269 | 401: { 270 | description: 'My error endpoint', 271 | content: { 272 | 'application/json': { 273 | schema: { 274 | type: 'object', 275 | properties: { 276 | name: { 277 | type: 'string', 278 | }, 279 | }, 280 | example: { 281 | name: 'John', 282 | }, 283 | }, 284 | }, 285 | }, 286 | }, 287 | // 6. reference object 288 | 402: { 289 | $ref: '#/components/responses/ServerError', 290 | }, 291 | }, 292 | }), 293 | async (c) => { 294 | return c.json({ name: 'John' }, 200); 295 | }, 296 | ); 297 | }); 298 | 299 | it('works properly with global middlewares', async () => { 300 | const nextMiddleware: MiddlewareHandler = async (c, next) => { 301 | await next(); 302 | }; 303 | 304 | const app = new Hono(); 305 | app.use('*', nextMiddleware); 306 | 307 | app.get( 308 | '/:id', 309 | openApi({ 310 | request: { 311 | param: z.object({ 312 | id: z.string(), 313 | }), 314 | }, 315 | responses: { 316 | 200: z.object({ id: z.string() }), 317 | }, 318 | }), 319 | (c) => { 320 | const { id } = c.req.valid('param'); 321 | return c.json({ id }, 200); 322 | }, 323 | ); 324 | 325 | const res = await app.request('/123'); 326 | const data = await res.json(); 327 | 328 | expect(data).toEqual({ id: '123' }); 329 | }); 330 | }); 331 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hono-zod-openapi 2 | 3 | [![NPM Version](https://img.shields.io/npm/v/hono-zod-openapi)](https://npmjs.com/package/hono-zod-openapi) 4 | [![JSR Version](https://img.shields.io/jsr/v/%40paolostyle/hono-zod-openapi)](https://jsr.io/@paolostyle/hono-zod-openapi) 5 | 6 | Alternative Hono middleware for creating OpenAPI documentation from Zod schemas 7 | 8 | ## Installation 9 | 10 | ``` 11 | npm install hono-zod-openapi hono zod 12 | ``` 13 | 14 | Or, if you prefer JSR: 15 | 16 | ``` 17 | jsr add @paolostyle/hono-zod-openapi 18 | ``` 19 | 20 | ## Why? 21 | 22 | Hono provides a 3rd-party middleware in their 23 | [middleware](https://github.com/honojs/middleware/tree/main/packages/zod-openapi) 24 | monorepo, which probably works alright, however my issue with this package is 25 | that it forces you to write your code in a different manner than you normally 26 | would in Hono. Refactoring the app becomes a significant hassle. 27 | 28 | This library provides an `openApi` middleware instead, which you can easily add 29 | to your existing codebase, and a `createOpenApiDocument` function, which will 30 | generate an OpenAPI-compliant JSON document and serve it under `/doc` route of 31 | your app (it's configurable, don't worry). 32 | 33 | ## Features 34 | 35 | - Super simple usage - just add a middleware and that's it! 36 | - Ability to generate OpenAPI docs both using simple, almost exclusively Zod 37 | schema-based notation, or with regular OpenAPI spec 38 | - Request validation - same functionality as `@hono/zod-validator` (we're using 39 | it as a dependency) 40 | - Fully compatible with Zod v4 (if you're still on Zod v3, please use v0.5.0) 41 | 42 | ## Usage 43 | 44 | This library is based on 45 | [`zod-openapi`](https://github.com/samchungy/zod-openapi) library (not the same 46 | one as the official package). 47 | 48 | ### Middleware 49 | 50 | `hono-zod-openapi` provides a middleware which you can attach to any endpoint. 51 | It accepts a single argument, an object that is mostly the same as the 52 | [OpenAPI Operation Object](https://swagger.io/specification/#operation-object). 53 | There are 2 main differences: 54 | 55 | - a `request` field, which functions essentially like a condensed version of 56 | `@hono/zod-validator`. For example, `{ json: z.object() }` is equivalent to 57 | `zValidator('json', z.object())`. Passing multiple attributes to the object is 58 | equivalent to calling multiple `zValidator`s. At the same time, **it will 59 | translate the validation schemas to OpenAPI notation**. There is no need to 60 | use `parameters` and `requestBody` fields at all (but it is still possible). 61 | 62 | - enhanced `responses` field which has essentially 4 variants: 63 | 64 | - Passing a Zod schema directly. For simple APIs this is more than enough. 65 | `description` field will be equal to the full HTTP status code (e.g. 66 | `200 OK` or `500 Internal Server Error`) and media type will be inferred 67 | based on the passed schema, though it is pretty simple now - for 68 | `z.string()` it will be `text/plain`, otherwise it's `application/json`. 69 | 70 | Example: 71 | 72 | ```ts 73 | openApi({ 74 | responses: { 75 | 200: z 76 | .object({ wow: z.string() }) 77 | .meta({ example: { wow: 'this is cool!' } }), 78 | }, 79 | }); 80 | ``` 81 | 82 |
83 | This will be equivalent to this OpenAPI spec: 84 | 85 | ```json 86 | { 87 | "responses": { 88 | "200": { 89 | "description": "200 OK", 90 | "content": { 91 | "application/json": { 92 | "schema": { 93 | "example": { 94 | "wow": "this is cool!" 95 | }, 96 | "properties": { 97 | "wow": { 98 | "type": "string" 99 | } 100 | }, 101 | "required": ["wow"], 102 | "type": "object" 103 | } 104 | } 105 | } 106 | } 107 | } 108 | } 109 | ``` 110 | 111 |
112 | 113 | - "Library notation" - a simplified, flattened format, similar to the official 114 | OpenAPI spec, but reduces annoying nesting. Convenient form if you want a 115 | custom description or need to pass extra data. 116 | 117 | Example: 118 | 119 | ```ts 120 | openApi({ 121 | responses: { 122 | 200: { 123 | // the only required field! Use .meta() method on the schema to add metadata 124 | schema: z.string().meta({ 125 | description: 'HTML code', 126 | example: 'hi!', 127 | }), 128 | // description is optional, as opposed to OpenAPI spec 129 | description: 'My description', 130 | // mediaType is optional, it's `text/plain` if schema is z.string() 131 | // otherwise it's `application/json`, in other scenarios it should be specified 132 | mediaType: 'text/html', 133 | // headers field is also optional, but you can also use Zod schema here 134 | headers: z.object({ 'x-custom': z.string() }), 135 | // ...you can also pass all the other fields you normally would here in OpenAPI spec 136 | }, 137 | }, 138 | }); 139 | ``` 140 | 141 |
142 | This will be equivalent to this OpenAPI spec: 143 | 144 | ```json 145 | { 146 | "responses": { 147 | "200": { 148 | "content": { 149 | "text/html": { 150 | "schema": { 151 | "description": "HTML code", 152 | "example": "hi!", 153 | "type": "string" 154 | } 155 | } 156 | }, 157 | "description": "My description", 158 | "headers": { 159 | "x-custom": { 160 | "required": true, 161 | "schema": { 162 | "type": "string" 163 | } 164 | } 165 | } 166 | } 167 | } 168 | } 169 | ``` 170 | 171 |
172 | 173 | - `zod-openapi` notation. Mostly useful when you need to have `content` in 174 | multiple formats, or you just want to be as close as possible to the 175 | official spec. 176 | 177 | Example: 178 | 179 | ```ts 180 | openApi({ 181 | responses: { 182 | 200: { 183 | // required 184 | description: 'Success response', 185 | content: { 186 | 'application/json': { 187 | schema: z.object({ welcome: z.string() }), 188 | }, 189 | }, 190 | // ...you can also pass all the other fields you normally would here in OpenAPI spec 191 | }, 192 | }, 193 | }); 194 | ``` 195 | 196 |
197 | This will be equivalent to this OpenAPI spec: 198 | 199 | ```json 200 | { 201 | "responses": { 202 | "200": { 203 | "content": { 204 | "application/json": { 205 | "schema": { 206 | "properties": { 207 | "welcome": { 208 | "type": "string" 209 | } 210 | }, 211 | "required": ["welcome"], 212 | "type": "object" 213 | } 214 | } 215 | }, 216 | "description": "Success response" 217 | } 218 | } 219 | } 220 | ``` 221 | 222 |
223 | 224 | - Classic OpenAPI spec notation: just 225 | [refer to the official spec](https://swagger.io/specification/#responses-object). 226 | Not recommended but it also just works. 227 | 228 | Since the object can get pretty large, you can use `defineOpenApiOperation` 229 | function to get the autocomplete in the IDE. 230 | 231 | Simple example: 232 | 233 | ```ts 234 | import { Hono } from 'hono'; 235 | import * as z from 'zod'; 236 | import { createOpenApiDocument, openApi } from 'hono-zod-openapi'; 237 | 238 | export const app = new Hono().get( 239 | '/user', 240 | openApi({ 241 | tags: ['User'], 242 | responses: { 243 | 200: z.object({ hi: z.string() }).meta({ example: { hi: 'user' } }), 244 | }, 245 | request: { 246 | query: z.object({ id: z.string() }), 247 | }, 248 | }), 249 | (c) => { 250 | // works identically to @hono/zod-validator 251 | const { id } = c.req.valid('query'); 252 | return c.json({ hi: id }, 200); 253 | }, 254 | ); 255 | 256 | // this will add a `GET /doc` route to the `app` router 257 | createOpenApiDocument(app, { 258 | info: { 259 | title: 'Example API', 260 | version: '1.0.0', 261 | }, 262 | }); 263 | ``` 264 | 265 |
266 | Calling GET /doc will result in this response: 267 | 268 | ```json 269 | { 270 | "info": { 271 | "title": "Example API", 272 | "version": "1.0.0" 273 | }, 274 | "openapi": "3.1.0", 275 | "paths": { 276 | "/user": { 277 | "get": { 278 | "tags": ["User"], 279 | "parameters": [ 280 | { 281 | "in": "query", 282 | "name": "id", 283 | "required": true, 284 | "schema": { 285 | "type": "string" 286 | } 287 | } 288 | ], 289 | "responses": { 290 | "200": { 291 | "content": { 292 | "application/json": { 293 | "schema": { 294 | "example": { 295 | "hi": "user" 296 | }, 297 | "properties": { 298 | "hi": { 299 | "type": "string" 300 | } 301 | }, 302 | "required": ["hi"], 303 | "type": "object" 304 | } 305 | } 306 | }, 307 | "description": "200 OK" 308 | } 309 | } 310 | } 311 | } 312 | } 313 | } 314 | ``` 315 | 316 |
317 | 318 | ## Recipes 319 | 320 | ### Authentication 321 | 322 | Generally you just need to follow one of the Authentication guides 323 | [here](https://swagger.io/docs/specification/v3_0/authentication/), depending on 324 | the type of authentication you're using. 325 | 326 | Bearer Auth example: 327 | 328 | ```ts 329 | const app = new Hono().get( 330 | '/example', 331 | openApi({ 332 | responses: { 333 | 200: z.object({}), 334 | }, 335 | security: [{ bearerAuth: [] }], 336 | }), 337 | async (c) => { 338 | return c.json({}, 200); 339 | }, 340 | ); 341 | 342 | createOpenApiDocument(app, { 343 | info: { 344 | title: 'Some API', 345 | version: '0.0.1', 346 | }, 347 | components: { 348 | securitySchemes: { 349 | bearerAuth: { 350 | type: 'http', 351 | scheme: 'bearer', 352 | }, 353 | }, 354 | }, 355 | // if you use bearer auth in every endpoint, you can add 356 | // this here instead of adding `security` to every route: 357 | // security: [{ bearerAuth: [] }], 358 | }); 359 | ``` 360 | 361 | ### Reusing common fields 362 | 363 | Adding the same fields to various routes over an over can be a bit tedious. You 364 | can create your own typesafe wrapper, which will provide the fields shared by 365 | multiple endpoints. For example, if a lot of your endpoints require a `security` 366 | field and a `tag`, you can create a function like this: 367 | 368 | ```ts 369 | const taggedAuthRoute = ( 370 | doc: HonoOpenApiOperation, 371 | ) => { 372 | return defineOpenApiOperation({ 373 | ...doc, 374 | tags: ['MyTag'], 375 | security: [{ apiKey: [] }], 376 | }); 377 | }; 378 | ``` 379 | 380 | and use it with `openApi` middleware: 381 | 382 | ```ts 383 | openApi( 384 | taggedAuthRoute({ 385 | request: { 386 | json: z.object({ field: z.number() }), 387 | }, 388 | }), 389 | ); 390 | ``` 391 | 392 | ### Custom error handling 393 | 394 | In general, `hono-zod-openapi` stays away from error handling and delegates it 395 | fully to `zod-validator`. `zod-validator`, however, accepts a third argument 396 | `hook`, using which you can intercept the validation result for every usage of 397 | the middleware. There is no direct equivalent for that in `hono-zod-openapi`, as 398 | in my experience it made more sense to create a custom middleware that wraps 399 | `zod-validator` and handles the errors in a unified way. That approach **is** 400 | supported. You can create your own `openApi` middleware using 401 | `createOpenApiMiddleware` - it's used internally to create `openApi` exported by 402 | the library. 403 | 404 | Example using an excellent `zod-validation-error` library that translates 405 | `ZodError`s into user friendly strings: 406 | 407 | ```ts 408 | import { zValidator } from '@hono/zod-validator'; 409 | import type { ValidationTargets } from 'hono'; 410 | import { HTTPException } from 'hono/http-exception'; 411 | import { createOpenApiMiddleware } from 'hono-zod-openapi'; 412 | import { fromZodError } from 'zod-validation-error'; 413 | import * as z from 'zod'; 414 | 415 | const zodValidator = ( 416 | target: T, 417 | schema: S, 418 | ) => 419 | zValidator(target, schema, (result, c) => { 420 | if (!result.success) { 421 | const validationError = fromZodError(result.error, { 422 | includePath: false, 423 | }); 424 | // you can handle that in `new Hono().onError()` or just use e.g. `c.json()` directly instead 425 | throw new HTTPException(400, { 426 | message: validationError.message, 427 | cause: validationError, 428 | }); 429 | } 430 | }); 431 | 432 | // works exactly the same way as `openApi` exported by `hono-zod-openapi` 433 | export const openApi = createOpenApiMiddleware(zodValidator); 434 | ``` 435 | 436 | If there is a need for handling errors on a case-by-case basis - create an issue 437 | and let's try to find a sensible solution for that! 438 | 439 | ## API 440 | 441 | ### `createOpenApiDocument` 442 | 443 | ```ts 444 | function createOpenApiDocument( 445 | router: Hono, 446 | document: Omit, 447 | { addRoute = true, routeName = '/doc' }: Settings = {}, 448 | ): ReturnType; 449 | ``` 450 | 451 | Call this function after you defined your Hono app to generate the OpenAPI 452 | document and host it under `/doc` route by default. `info` field in the second 453 | argument is required by the OpenAPI specification. You can pass there also any 454 | other fields available in the OpenAPI specification, e.g. `servers`, `security` 455 | or `components`. 456 | 457 | Examples: 458 | 459 | - typical usage: 460 | 461 | ```ts 462 | createOpenApiDocument(app, { 463 | info: { 464 | title: 'Example API', 465 | version: '1.0.0', 466 | }, 467 | }); 468 | ``` 469 | 470 | - add the route under /openApi route: 471 | 472 | ```ts 473 | createOpenApiDocument( 474 | app, 475 | { 476 | info: { 477 | title: 'Example API', 478 | version: '1.0.0', 479 | }, 480 | }, 481 | { routeName: '/openApi' }, 482 | ); 483 | ``` 484 | 485 | - don't add the route, just get the OpenAPI document as an object 486 | ```ts 487 | const openApiDoc = createOpenApiDocument( 488 | app, 489 | { 490 | info: { 491 | title: 'Example API', 492 | version: '1.0.0', 493 | }, 494 | }, 495 | { addRoute: false }, 496 | ); 497 | ``` 498 | 499 | ### `openApi` 500 | 501 | ```ts 502 | function openApi( 503 | operation: Operation, 504 | ): MiddlewareHandler>; 505 | ``` 506 | 507 | A Hono middleware used to document a given endpoint. Refer to the 508 | [Middleware](#middleware) section above to see the usage examples. 509 | 510 | ### `defineOpenApiOperation` 511 | 512 | A no-op function, used to ensure proper validator's type inference and provide 513 | autocomplete in cases where you don't want to define the spec inline. 514 | 515 | Example: 516 | 517 | ```ts 518 | const operation = defineOpenApiOperation({ 519 | responses: { 520 | 200: z.object({ name: z.string() }), 521 | }, 522 | request: { 523 | json: z.object({ email: z.string() }), 524 | }, 525 | }); 526 | 527 | const app = new Hono().post('/user', openApi(operation), async (c) => { 528 | const { name } = c.req.valid('json'); 529 | 530 | return c.json({ name }, 200); 531 | }); 532 | ``` 533 | 534 |
535 | This will result in this JSON document: 536 | 537 | ```json 538 | { 539 | "info": { 540 | "title": "Example API", 541 | "version": "1.0.0" 542 | }, 543 | "openapi": "3.1.0", 544 | "paths": { 545 | "/user": { 546 | "get": { 547 | "parameters": [ 548 | { 549 | "in": "cookie", 550 | "name": "session", 551 | "required": true, 552 | "schema": { 553 | "type": "string" 554 | } 555 | } 556 | ], 557 | "requestBody": { 558 | "content": { 559 | "application/json": { 560 | "schema": { 561 | "properties": { 562 | "email": { 563 | "type": "string" 564 | } 565 | }, 566 | "required": ["email"], 567 | "type": "object" 568 | } 569 | } 570 | } 571 | }, 572 | "responses": { 573 | "200": { 574 | "content": { 575 | "application/json": { 576 | "schema": { 577 | "properties": { 578 | "name": { 579 | "type": "string" 580 | } 581 | }, 582 | "required": ["name"], 583 | "type": "object" 584 | } 585 | } 586 | }, 587 | "description": "200 OK" 588 | }, 589 | "400": { 590 | "content": { 591 | "application/xml": { 592 | "schema": { 593 | "properties": { 594 | "message": { 595 | "type": "string" 596 | } 597 | }, 598 | "required": ["message"], 599 | "type": "object" 600 | } 601 | } 602 | }, 603 | "description": "Custom description" 604 | }, 605 | "401": { 606 | "content": { 607 | "application/json": { 608 | "schema": { 609 | "properties": { 610 | "message": { 611 | "type": "string" 612 | } 613 | }, 614 | "required": ["message"], 615 | "type": "object" 616 | } 617 | } 618 | }, 619 | "description": "Required description" 620 | }, 621 | "404": { 622 | "content": { 623 | "application/json": { 624 | "schema": { 625 | "properties": { 626 | "message": { 627 | "type": "string" 628 | } 629 | }, 630 | "required": ["message"], 631 | "type": "object" 632 | } 633 | } 634 | }, 635 | "description": "Not found" 636 | } 637 | }, 638 | "tags": ["User"] 639 | } 640 | } 641 | } 642 | } 643 | ``` 644 | 645 |
646 | 647 | ### `createOpenApiMiddleware` 648 | 649 | ```ts 650 | export function createOpenApiMiddleware( 651 | zodValidator: ZodValidatorFn = zValidator, 652 | ): HonoOpenApiMiddleware; 653 | ``` 654 | 655 | Used internally to create `openApi` instance. You can use it if you need custom 656 | error handling on the middleware level. 657 | 658 | ## Runtime compatibility 659 | 660 | While this package _should_ work in Bun, Deno, Cloudflare Workers and browsers 661 | (as I'm not using any platform specific APIs and I do not plan to), the codebase 662 | is currently tested against Node.js 20.x, 22.x and 24.x. I haven't found any 663 | tools that would help with cross-platform testing that wouldn't incur 664 | significant maintenance burden. 665 | 666 | For now I managed to successfully run the tests with Bun test runner with some 667 | grepping and used the lib in Cloudflare Workers and everything seemed to work 668 | fine. If you are using the library in non-Node runtime and encountered some 669 | bugs, please consider creating an issue. 670 | 671 | ## Contributing 672 | 673 | ### Local setup 674 | 675 | Run the following set of commands to set up the project. Corepack is required to 676 | install the correct version of PNPM. 677 | 678 | ```sh 679 | corepack enable 680 | corepack install 681 | pnpm i 682 | ``` 683 | 684 | Now you can run `pnpm test` to continuously run tests while developing. 685 | 686 | ### Commit naming conventions 687 | 688 | At the moment of writing this, we don't have an automated setup for 689 | [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) as none 690 | of the tooling I tried was really meeting my expectations, but Release Please, 691 | which takes care of the automated release process is using them to identify the 692 | need for releasing a new version. For now please try to do this manually 693 | (including in PR names), but automating this process would be great. 694 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | dependencies: 11 | '@hono/zod-validator': 12 | specifier: ^0.7.3 13 | version: 0.7.3(hono@4.9.9)(zod@4.1.11) 14 | hono: 15 | specifier: ^4.8.0 16 | version: 4.9.9 17 | zod-openapi: 18 | specifier: ^5.4.2 19 | version: 5.4.2(zod@4.1.11) 20 | devDependencies: 21 | '@biomejs/biome': 22 | specifier: 1.9.4 23 | version: 1.9.4 24 | '@hono/node-server': 25 | specifier: ^1.19.4 26 | version: 1.19.4(hono@4.9.9) 27 | '@hono/swagger-ui': 28 | specifier: ^0.5.2 29 | version: 0.5.2(hono@4.9.9) 30 | '@types/node': 31 | specifier: ^22.18.6 32 | version: 22.18.6 33 | '@vitest/coverage-v8': 34 | specifier: ^3.2.4 35 | version: 3.2.4(vitest@3.2.4) 36 | '@vitest/ui': 37 | specifier: ^3.2.4 38 | version: 3.2.4(vitest@3.2.4) 39 | husky: 40 | specifier: ^9.1.7 41 | version: 9.1.7 42 | tsup: 43 | specifier: ^8.5.0 44 | version: 8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.2)(yaml@2.5.1) 45 | tsx: 46 | specifier: ^4.20.6 47 | version: 4.20.6 48 | typescript: 49 | specifier: ^5.9.2 50 | version: 5.9.2 51 | vitest: 52 | specifier: ^3.2.4 53 | version: 3.2.4(@types/node@22.18.6)(@vitest/ui@3.2.4)(jsdom@25.0.1)(tsx@4.20.6)(yaml@2.5.1) 54 | zod: 55 | specifier: ^4.1.11 56 | version: 4.1.11 57 | 58 | packages: 59 | 60 | '@ampproject/remapping@2.3.0': 61 | resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} 62 | engines: {node: '>=6.0.0'} 63 | 64 | '@asamuzakjp/css-color@3.2.0': 65 | resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} 66 | 67 | '@babel/helper-string-parser@7.27.1': 68 | resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} 69 | engines: {node: '>=6.9.0'} 70 | 71 | '@babel/helper-validator-identifier@7.27.1': 72 | resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} 73 | engines: {node: '>=6.9.0'} 74 | 75 | '@babel/parser@7.28.4': 76 | resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} 77 | engines: {node: '>=6.0.0'} 78 | hasBin: true 79 | 80 | '@babel/types@7.28.4': 81 | resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} 82 | engines: {node: '>=6.9.0'} 83 | 84 | '@bcoe/v8-coverage@1.0.2': 85 | resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} 86 | engines: {node: '>=18'} 87 | 88 | '@biomejs/biome@1.9.4': 89 | resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} 90 | engines: {node: '>=14.21.3'} 91 | hasBin: true 92 | 93 | '@biomejs/cli-darwin-arm64@1.9.4': 94 | resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} 95 | engines: {node: '>=14.21.3'} 96 | cpu: [arm64] 97 | os: [darwin] 98 | 99 | '@biomejs/cli-darwin-x64@1.9.4': 100 | resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} 101 | engines: {node: '>=14.21.3'} 102 | cpu: [x64] 103 | os: [darwin] 104 | 105 | '@biomejs/cli-linux-arm64-musl@1.9.4': 106 | resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} 107 | engines: {node: '>=14.21.3'} 108 | cpu: [arm64] 109 | os: [linux] 110 | libc: [musl] 111 | 112 | '@biomejs/cli-linux-arm64@1.9.4': 113 | resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} 114 | engines: {node: '>=14.21.3'} 115 | cpu: [arm64] 116 | os: [linux] 117 | libc: [glibc] 118 | 119 | '@biomejs/cli-linux-x64-musl@1.9.4': 120 | resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} 121 | engines: {node: '>=14.21.3'} 122 | cpu: [x64] 123 | os: [linux] 124 | libc: [musl] 125 | 126 | '@biomejs/cli-linux-x64@1.9.4': 127 | resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} 128 | engines: {node: '>=14.21.3'} 129 | cpu: [x64] 130 | os: [linux] 131 | libc: [glibc] 132 | 133 | '@biomejs/cli-win32-arm64@1.9.4': 134 | resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} 135 | engines: {node: '>=14.21.3'} 136 | cpu: [arm64] 137 | os: [win32] 138 | 139 | '@biomejs/cli-win32-x64@1.9.4': 140 | resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} 141 | engines: {node: '>=14.21.3'} 142 | cpu: [x64] 143 | os: [win32] 144 | 145 | '@csstools/color-helpers@5.1.0': 146 | resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} 147 | engines: {node: '>=18'} 148 | 149 | '@csstools/css-calc@2.1.4': 150 | resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} 151 | engines: {node: '>=18'} 152 | peerDependencies: 153 | '@csstools/css-parser-algorithms': ^3.0.5 154 | '@csstools/css-tokenizer': ^3.0.4 155 | 156 | '@csstools/css-color-parser@3.1.0': 157 | resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} 158 | engines: {node: '>=18'} 159 | peerDependencies: 160 | '@csstools/css-parser-algorithms': ^3.0.5 161 | '@csstools/css-tokenizer': ^3.0.4 162 | 163 | '@csstools/css-parser-algorithms@3.0.5': 164 | resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} 165 | engines: {node: '>=18'} 166 | peerDependencies: 167 | '@csstools/css-tokenizer': ^3.0.4 168 | 169 | '@csstools/css-tokenizer@3.0.4': 170 | resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} 171 | engines: {node: '>=18'} 172 | 173 | '@esbuild/aix-ppc64@0.25.10': 174 | resolution: {integrity: sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==} 175 | engines: {node: '>=18'} 176 | cpu: [ppc64] 177 | os: [aix] 178 | 179 | '@esbuild/android-arm64@0.25.10': 180 | resolution: {integrity: sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==} 181 | engines: {node: '>=18'} 182 | cpu: [arm64] 183 | os: [android] 184 | 185 | '@esbuild/android-arm@0.25.10': 186 | resolution: {integrity: sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==} 187 | engines: {node: '>=18'} 188 | cpu: [arm] 189 | os: [android] 190 | 191 | '@esbuild/android-x64@0.25.10': 192 | resolution: {integrity: sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==} 193 | engines: {node: '>=18'} 194 | cpu: [x64] 195 | os: [android] 196 | 197 | '@esbuild/darwin-arm64@0.25.10': 198 | resolution: {integrity: sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==} 199 | engines: {node: '>=18'} 200 | cpu: [arm64] 201 | os: [darwin] 202 | 203 | '@esbuild/darwin-x64@0.25.10': 204 | resolution: {integrity: sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==} 205 | engines: {node: '>=18'} 206 | cpu: [x64] 207 | os: [darwin] 208 | 209 | '@esbuild/freebsd-arm64@0.25.10': 210 | resolution: {integrity: sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==} 211 | engines: {node: '>=18'} 212 | cpu: [arm64] 213 | os: [freebsd] 214 | 215 | '@esbuild/freebsd-x64@0.25.10': 216 | resolution: {integrity: sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==} 217 | engines: {node: '>=18'} 218 | cpu: [x64] 219 | os: [freebsd] 220 | 221 | '@esbuild/linux-arm64@0.25.10': 222 | resolution: {integrity: sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==} 223 | engines: {node: '>=18'} 224 | cpu: [arm64] 225 | os: [linux] 226 | 227 | '@esbuild/linux-arm@0.25.10': 228 | resolution: {integrity: sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==} 229 | engines: {node: '>=18'} 230 | cpu: [arm] 231 | os: [linux] 232 | 233 | '@esbuild/linux-ia32@0.25.10': 234 | resolution: {integrity: sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==} 235 | engines: {node: '>=18'} 236 | cpu: [ia32] 237 | os: [linux] 238 | 239 | '@esbuild/linux-loong64@0.25.10': 240 | resolution: {integrity: sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==} 241 | engines: {node: '>=18'} 242 | cpu: [loong64] 243 | os: [linux] 244 | 245 | '@esbuild/linux-mips64el@0.25.10': 246 | resolution: {integrity: sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==} 247 | engines: {node: '>=18'} 248 | cpu: [mips64el] 249 | os: [linux] 250 | 251 | '@esbuild/linux-ppc64@0.25.10': 252 | resolution: {integrity: sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==} 253 | engines: {node: '>=18'} 254 | cpu: [ppc64] 255 | os: [linux] 256 | 257 | '@esbuild/linux-riscv64@0.25.10': 258 | resolution: {integrity: sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==} 259 | engines: {node: '>=18'} 260 | cpu: [riscv64] 261 | os: [linux] 262 | 263 | '@esbuild/linux-s390x@0.25.10': 264 | resolution: {integrity: sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==} 265 | engines: {node: '>=18'} 266 | cpu: [s390x] 267 | os: [linux] 268 | 269 | '@esbuild/linux-x64@0.25.10': 270 | resolution: {integrity: sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==} 271 | engines: {node: '>=18'} 272 | cpu: [x64] 273 | os: [linux] 274 | 275 | '@esbuild/netbsd-arm64@0.25.10': 276 | resolution: {integrity: sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==} 277 | engines: {node: '>=18'} 278 | cpu: [arm64] 279 | os: [netbsd] 280 | 281 | '@esbuild/netbsd-x64@0.25.10': 282 | resolution: {integrity: sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==} 283 | engines: {node: '>=18'} 284 | cpu: [x64] 285 | os: [netbsd] 286 | 287 | '@esbuild/openbsd-arm64@0.25.10': 288 | resolution: {integrity: sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==} 289 | engines: {node: '>=18'} 290 | cpu: [arm64] 291 | os: [openbsd] 292 | 293 | '@esbuild/openbsd-x64@0.25.10': 294 | resolution: {integrity: sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==} 295 | engines: {node: '>=18'} 296 | cpu: [x64] 297 | os: [openbsd] 298 | 299 | '@esbuild/openharmony-arm64@0.25.10': 300 | resolution: {integrity: sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==} 301 | engines: {node: '>=18'} 302 | cpu: [arm64] 303 | os: [openharmony] 304 | 305 | '@esbuild/sunos-x64@0.25.10': 306 | resolution: {integrity: sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==} 307 | engines: {node: '>=18'} 308 | cpu: [x64] 309 | os: [sunos] 310 | 311 | '@esbuild/win32-arm64@0.25.10': 312 | resolution: {integrity: sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==} 313 | engines: {node: '>=18'} 314 | cpu: [arm64] 315 | os: [win32] 316 | 317 | '@esbuild/win32-ia32@0.25.10': 318 | resolution: {integrity: sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==} 319 | engines: {node: '>=18'} 320 | cpu: [ia32] 321 | os: [win32] 322 | 323 | '@esbuild/win32-x64@0.25.10': 324 | resolution: {integrity: sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==} 325 | engines: {node: '>=18'} 326 | cpu: [x64] 327 | os: [win32] 328 | 329 | '@hono/node-server@1.19.4': 330 | resolution: {integrity: sha512-AWKQZ/YkHUBSHeL/5Ld8FWgUs6wFf4TxGYxqp9wLZxRdFuHBpXmgOq+CuDoL4vllkZLzovCf5HBJnypiy3EtHA==} 331 | engines: {node: '>=18.14.1'} 332 | peerDependencies: 333 | hono: ^4 334 | 335 | '@hono/swagger-ui@0.5.2': 336 | resolution: {integrity: sha512-7wxLKdb8h7JTdZ+K8DJNE3KXQMIpJejkBTQjrYlUWF28Z1PGOKw6kUykARe5NTfueIN37jbyG/sBYsbzXzG53A==} 337 | peerDependencies: 338 | hono: '*' 339 | 340 | '@hono/zod-validator@0.7.3': 341 | resolution: {integrity: sha512-uYGdgVib3RlGD698WR5dVM0zB3UuPY5vHKXffGUbUh7r4xY+mFIhF3/v4AcQVLrU5CQdBso8BJr4wuVoCrjTuQ==} 342 | peerDependencies: 343 | hono: '>=3.9.0' 344 | zod: ^3.25.0 || ^4.0.0 345 | 346 | '@isaacs/cliui@8.0.2': 347 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 348 | engines: {node: '>=12'} 349 | 350 | '@istanbuljs/schema@0.1.3': 351 | resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} 352 | engines: {node: '>=8'} 353 | 354 | '@jridgewell/gen-mapping@0.3.13': 355 | resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} 356 | 357 | '@jridgewell/resolve-uri@3.1.2': 358 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 359 | engines: {node: '>=6.0.0'} 360 | 361 | '@jridgewell/sourcemap-codec@1.5.5': 362 | resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} 363 | 364 | '@jridgewell/trace-mapping@0.3.31': 365 | resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} 366 | 367 | '@pkgjs/parseargs@0.11.0': 368 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 369 | engines: {node: '>=14'} 370 | 371 | '@polka/url@1.0.0-next.29': 372 | resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} 373 | 374 | '@rollup/rollup-android-arm-eabi@4.52.3': 375 | resolution: {integrity: sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==} 376 | cpu: [arm] 377 | os: [android] 378 | 379 | '@rollup/rollup-android-arm64@4.52.3': 380 | resolution: {integrity: sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==} 381 | cpu: [arm64] 382 | os: [android] 383 | 384 | '@rollup/rollup-darwin-arm64@4.52.3': 385 | resolution: {integrity: sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==} 386 | cpu: [arm64] 387 | os: [darwin] 388 | 389 | '@rollup/rollup-darwin-x64@4.52.3': 390 | resolution: {integrity: sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==} 391 | cpu: [x64] 392 | os: [darwin] 393 | 394 | '@rollup/rollup-freebsd-arm64@4.52.3': 395 | resolution: {integrity: sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==} 396 | cpu: [arm64] 397 | os: [freebsd] 398 | 399 | '@rollup/rollup-freebsd-x64@4.52.3': 400 | resolution: {integrity: sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==} 401 | cpu: [x64] 402 | os: [freebsd] 403 | 404 | '@rollup/rollup-linux-arm-gnueabihf@4.52.3': 405 | resolution: {integrity: sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==} 406 | cpu: [arm] 407 | os: [linux] 408 | libc: [glibc] 409 | 410 | '@rollup/rollup-linux-arm-musleabihf@4.52.3': 411 | resolution: {integrity: sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==} 412 | cpu: [arm] 413 | os: [linux] 414 | libc: [musl] 415 | 416 | '@rollup/rollup-linux-arm64-gnu@4.52.3': 417 | resolution: {integrity: sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==} 418 | cpu: [arm64] 419 | os: [linux] 420 | libc: [glibc] 421 | 422 | '@rollup/rollup-linux-arm64-musl@4.52.3': 423 | resolution: {integrity: sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==} 424 | cpu: [arm64] 425 | os: [linux] 426 | libc: [musl] 427 | 428 | '@rollup/rollup-linux-loong64-gnu@4.52.3': 429 | resolution: {integrity: sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==} 430 | cpu: [loong64] 431 | os: [linux] 432 | libc: [glibc] 433 | 434 | '@rollup/rollup-linux-ppc64-gnu@4.52.3': 435 | resolution: {integrity: sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==} 436 | cpu: [ppc64] 437 | os: [linux] 438 | libc: [glibc] 439 | 440 | '@rollup/rollup-linux-riscv64-gnu@4.52.3': 441 | resolution: {integrity: sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==} 442 | cpu: [riscv64] 443 | os: [linux] 444 | libc: [glibc] 445 | 446 | '@rollup/rollup-linux-riscv64-musl@4.52.3': 447 | resolution: {integrity: sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==} 448 | cpu: [riscv64] 449 | os: [linux] 450 | libc: [musl] 451 | 452 | '@rollup/rollup-linux-s390x-gnu@4.52.3': 453 | resolution: {integrity: sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==} 454 | cpu: [s390x] 455 | os: [linux] 456 | libc: [glibc] 457 | 458 | '@rollup/rollup-linux-x64-gnu@4.52.3': 459 | resolution: {integrity: sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==} 460 | cpu: [x64] 461 | os: [linux] 462 | libc: [glibc] 463 | 464 | '@rollup/rollup-linux-x64-musl@4.52.3': 465 | resolution: {integrity: sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==} 466 | cpu: [x64] 467 | os: [linux] 468 | libc: [musl] 469 | 470 | '@rollup/rollup-openharmony-arm64@4.52.3': 471 | resolution: {integrity: sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==} 472 | cpu: [arm64] 473 | os: [openharmony] 474 | 475 | '@rollup/rollup-win32-arm64-msvc@4.52.3': 476 | resolution: {integrity: sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==} 477 | cpu: [arm64] 478 | os: [win32] 479 | 480 | '@rollup/rollup-win32-ia32-msvc@4.52.3': 481 | resolution: {integrity: sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==} 482 | cpu: [ia32] 483 | os: [win32] 484 | 485 | '@rollup/rollup-win32-x64-gnu@4.52.3': 486 | resolution: {integrity: sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==} 487 | cpu: [x64] 488 | os: [win32] 489 | 490 | '@rollup/rollup-win32-x64-msvc@4.52.3': 491 | resolution: {integrity: sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==} 492 | cpu: [x64] 493 | os: [win32] 494 | 495 | '@types/chai@5.2.2': 496 | resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} 497 | 498 | '@types/deep-eql@4.0.2': 499 | resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} 500 | 501 | '@types/estree@1.0.8': 502 | resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} 503 | 504 | '@types/node@22.18.6': 505 | resolution: {integrity: sha512-r8uszLPpeIWbNKtvWRt/DbVi5zbqZyj1PTmhRMqBMvDnaz1QpmSKujUtJLrqGZeoM8v72MfYggDceY4K1itzWQ==} 506 | 507 | '@vitest/coverage-v8@3.2.4': 508 | resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==} 509 | peerDependencies: 510 | '@vitest/browser': 3.2.4 511 | vitest: 3.2.4 512 | peerDependenciesMeta: 513 | '@vitest/browser': 514 | optional: true 515 | 516 | '@vitest/expect@3.2.4': 517 | resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} 518 | 519 | '@vitest/mocker@3.2.4': 520 | resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} 521 | peerDependencies: 522 | msw: ^2.4.9 523 | vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 524 | peerDependenciesMeta: 525 | msw: 526 | optional: true 527 | vite: 528 | optional: true 529 | 530 | '@vitest/pretty-format@3.2.4': 531 | resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} 532 | 533 | '@vitest/runner@3.2.4': 534 | resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} 535 | 536 | '@vitest/snapshot@3.2.4': 537 | resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} 538 | 539 | '@vitest/spy@3.2.4': 540 | resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} 541 | 542 | '@vitest/ui@3.2.4': 543 | resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==} 544 | peerDependencies: 545 | vitest: 3.2.4 546 | 547 | '@vitest/utils@3.2.4': 548 | resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} 549 | 550 | acorn@8.15.0: 551 | resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} 552 | engines: {node: '>=0.4.0'} 553 | hasBin: true 554 | 555 | agent-base@7.1.4: 556 | resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} 557 | engines: {node: '>= 14'} 558 | 559 | ansi-regex@5.0.1: 560 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 561 | engines: {node: '>=8'} 562 | 563 | ansi-regex@6.2.2: 564 | resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} 565 | engines: {node: '>=12'} 566 | 567 | ansi-styles@4.3.0: 568 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 569 | engines: {node: '>=8'} 570 | 571 | ansi-styles@6.2.3: 572 | resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} 573 | engines: {node: '>=12'} 574 | 575 | any-promise@1.3.0: 576 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 577 | 578 | assertion-error@2.0.1: 579 | resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} 580 | engines: {node: '>=12'} 581 | 582 | ast-v8-to-istanbul@0.3.5: 583 | resolution: {integrity: sha512-9SdXjNheSiE8bALAQCQQuT6fgQaoxJh7IRYrRGZ8/9nv8WhJeC1aXAwN8TbaOssGOukUvyvnkgD9+Yuykvl1aA==} 584 | 585 | asynckit@0.4.0: 586 | resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} 587 | 588 | balanced-match@1.0.2: 589 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 590 | 591 | brace-expansion@2.0.2: 592 | resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} 593 | 594 | bundle-require@5.1.0: 595 | resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} 596 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 597 | peerDependencies: 598 | esbuild: '>=0.18' 599 | 600 | cac@6.7.14: 601 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 602 | engines: {node: '>=8'} 603 | 604 | call-bind-apply-helpers@1.0.2: 605 | resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} 606 | engines: {node: '>= 0.4'} 607 | 608 | chai@5.3.3: 609 | resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} 610 | engines: {node: '>=18'} 611 | 612 | check-error@2.1.1: 613 | resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} 614 | engines: {node: '>= 16'} 615 | 616 | chokidar@4.0.3: 617 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 618 | engines: {node: '>= 14.16.0'} 619 | 620 | color-convert@2.0.1: 621 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 622 | engines: {node: '>=7.0.0'} 623 | 624 | color-name@1.1.4: 625 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 626 | 627 | combined-stream@1.0.8: 628 | resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} 629 | engines: {node: '>= 0.8'} 630 | 631 | commander@4.1.1: 632 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 633 | engines: {node: '>= 6'} 634 | 635 | confbox@0.1.8: 636 | resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} 637 | 638 | consola@3.4.2: 639 | resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} 640 | engines: {node: ^14.18.0 || >=16.10.0} 641 | 642 | cross-spawn@7.0.6: 643 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 644 | engines: {node: '>= 8'} 645 | 646 | cssstyle@4.6.0: 647 | resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} 648 | engines: {node: '>=18'} 649 | 650 | data-urls@5.0.0: 651 | resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} 652 | engines: {node: '>=18'} 653 | 654 | debug@4.4.3: 655 | resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} 656 | engines: {node: '>=6.0'} 657 | peerDependencies: 658 | supports-color: '*' 659 | peerDependenciesMeta: 660 | supports-color: 661 | optional: true 662 | 663 | decimal.js@10.6.0: 664 | resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} 665 | 666 | deep-eql@5.0.2: 667 | resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} 668 | engines: {node: '>=6'} 669 | 670 | delayed-stream@1.0.0: 671 | resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} 672 | engines: {node: '>=0.4.0'} 673 | 674 | dunder-proto@1.0.1: 675 | resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} 676 | engines: {node: '>= 0.4'} 677 | 678 | eastasianwidth@0.2.0: 679 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 680 | 681 | emoji-regex@8.0.0: 682 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 683 | 684 | emoji-regex@9.2.2: 685 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 686 | 687 | entities@6.0.1: 688 | resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} 689 | engines: {node: '>=0.12'} 690 | 691 | es-define-property@1.0.1: 692 | resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} 693 | engines: {node: '>= 0.4'} 694 | 695 | es-errors@1.3.0: 696 | resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} 697 | engines: {node: '>= 0.4'} 698 | 699 | es-module-lexer@1.7.0: 700 | resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} 701 | 702 | es-object-atoms@1.1.1: 703 | resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} 704 | engines: {node: '>= 0.4'} 705 | 706 | es-set-tostringtag@2.1.0: 707 | resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} 708 | engines: {node: '>= 0.4'} 709 | 710 | esbuild@0.25.10: 711 | resolution: {integrity: sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==} 712 | engines: {node: '>=18'} 713 | hasBin: true 714 | 715 | estree-walker@3.0.3: 716 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 717 | 718 | expect-type@1.2.2: 719 | resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} 720 | engines: {node: '>=12.0.0'} 721 | 722 | fdir@6.5.0: 723 | resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} 724 | engines: {node: '>=12.0.0'} 725 | peerDependencies: 726 | picomatch: ^3 || ^4 727 | peerDependenciesMeta: 728 | picomatch: 729 | optional: true 730 | 731 | fflate@0.8.2: 732 | resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} 733 | 734 | fix-dts-default-cjs-exports@1.0.1: 735 | resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} 736 | 737 | flatted@3.3.3: 738 | resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} 739 | 740 | foreground-child@3.3.1: 741 | resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} 742 | engines: {node: '>=14'} 743 | 744 | form-data@4.0.4: 745 | resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} 746 | engines: {node: '>= 6'} 747 | 748 | fsevents@2.3.3: 749 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 750 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 751 | os: [darwin] 752 | 753 | function-bind@1.1.2: 754 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 755 | 756 | get-intrinsic@1.3.0: 757 | resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} 758 | engines: {node: '>= 0.4'} 759 | 760 | get-proto@1.0.1: 761 | resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} 762 | engines: {node: '>= 0.4'} 763 | 764 | get-tsconfig@4.10.1: 765 | resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} 766 | 767 | glob@10.4.5: 768 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 769 | hasBin: true 770 | 771 | gopd@1.2.0: 772 | resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} 773 | engines: {node: '>= 0.4'} 774 | 775 | has-flag@4.0.0: 776 | resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} 777 | engines: {node: '>=8'} 778 | 779 | has-symbols@1.1.0: 780 | resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} 781 | engines: {node: '>= 0.4'} 782 | 783 | has-tostringtag@1.0.2: 784 | resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} 785 | engines: {node: '>= 0.4'} 786 | 787 | hasown@2.0.2: 788 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 789 | engines: {node: '>= 0.4'} 790 | 791 | hono@4.9.9: 792 | resolution: {integrity: sha512-Hxw4wT6zjJGZJdkJzAx9PyBdf7ZpxaTSA0NfxqjLghwMrLBX8p33hJBzoETRakF3UJu6OdNQBZAlNSkGqKFukw==} 793 | engines: {node: '>=16.9.0'} 794 | 795 | html-encoding-sniffer@4.0.0: 796 | resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} 797 | engines: {node: '>=18'} 798 | 799 | html-escaper@2.0.2: 800 | resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} 801 | 802 | http-proxy-agent@7.0.2: 803 | resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} 804 | engines: {node: '>= 14'} 805 | 806 | https-proxy-agent@7.0.6: 807 | resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} 808 | engines: {node: '>= 14'} 809 | 810 | husky@9.1.7: 811 | resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} 812 | engines: {node: '>=18'} 813 | hasBin: true 814 | 815 | iconv-lite@0.6.3: 816 | resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} 817 | engines: {node: '>=0.10.0'} 818 | 819 | is-fullwidth-code-point@3.0.0: 820 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 821 | engines: {node: '>=8'} 822 | 823 | is-potential-custom-element-name@1.0.1: 824 | resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} 825 | 826 | isexe@2.0.0: 827 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 828 | 829 | istanbul-lib-coverage@3.2.2: 830 | resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} 831 | engines: {node: '>=8'} 832 | 833 | istanbul-lib-report@3.0.1: 834 | resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} 835 | engines: {node: '>=10'} 836 | 837 | istanbul-lib-source-maps@5.0.6: 838 | resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} 839 | engines: {node: '>=10'} 840 | 841 | istanbul-reports@3.2.0: 842 | resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} 843 | engines: {node: '>=8'} 844 | 845 | jackspeak@3.4.3: 846 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 847 | 848 | joycon@3.1.1: 849 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 850 | engines: {node: '>=10'} 851 | 852 | js-tokens@9.0.1: 853 | resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} 854 | 855 | jsdom@25.0.1: 856 | resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==} 857 | engines: {node: '>=18'} 858 | peerDependencies: 859 | canvas: ^2.11.2 860 | peerDependenciesMeta: 861 | canvas: 862 | optional: true 863 | 864 | lilconfig@3.1.3: 865 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 866 | engines: {node: '>=14'} 867 | 868 | lines-and-columns@1.2.4: 869 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 870 | 871 | load-tsconfig@0.2.5: 872 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 873 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 874 | 875 | lodash.sortby@4.7.0: 876 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} 877 | 878 | loupe@3.2.1: 879 | resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} 880 | 881 | lru-cache@10.4.3: 882 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 883 | 884 | magic-string@0.30.19: 885 | resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} 886 | 887 | magicast@0.3.5: 888 | resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} 889 | 890 | make-dir@4.0.0: 891 | resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} 892 | engines: {node: '>=10'} 893 | 894 | math-intrinsics@1.1.0: 895 | resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} 896 | engines: {node: '>= 0.4'} 897 | 898 | mime-db@1.52.0: 899 | resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} 900 | engines: {node: '>= 0.6'} 901 | 902 | mime-types@2.1.35: 903 | resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 904 | engines: {node: '>= 0.6'} 905 | 906 | minimatch@9.0.5: 907 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 908 | engines: {node: '>=16 || 14 >=14.17'} 909 | 910 | minipass@7.1.2: 911 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 912 | engines: {node: '>=16 || 14 >=14.17'} 913 | 914 | mlly@1.8.0: 915 | resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} 916 | 917 | mrmime@2.0.1: 918 | resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} 919 | engines: {node: '>=10'} 920 | 921 | ms@2.1.3: 922 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 923 | 924 | mz@2.7.0: 925 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 926 | 927 | nanoid@3.3.11: 928 | resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} 929 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 930 | hasBin: true 931 | 932 | nwsapi@2.2.22: 933 | resolution: {integrity: sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==} 934 | 935 | object-assign@4.1.1: 936 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 937 | engines: {node: '>=0.10.0'} 938 | 939 | package-json-from-dist@1.0.1: 940 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 941 | 942 | parse5@7.3.0: 943 | resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} 944 | 945 | path-key@3.1.1: 946 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 947 | engines: {node: '>=8'} 948 | 949 | path-scurry@1.11.1: 950 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 951 | engines: {node: '>=16 || 14 >=14.18'} 952 | 953 | pathe@2.0.3: 954 | resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} 955 | 956 | pathval@2.0.1: 957 | resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} 958 | engines: {node: '>= 14.16'} 959 | 960 | picocolors@1.1.1: 961 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 962 | 963 | picomatch@4.0.3: 964 | resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} 965 | engines: {node: '>=12'} 966 | 967 | pirates@4.0.7: 968 | resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} 969 | engines: {node: '>= 6'} 970 | 971 | pkg-types@1.3.1: 972 | resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} 973 | 974 | postcss-load-config@6.0.1: 975 | resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} 976 | engines: {node: '>= 18'} 977 | peerDependencies: 978 | jiti: '>=1.21.0' 979 | postcss: '>=8.0.9' 980 | tsx: ^4.8.1 981 | yaml: ^2.4.2 982 | peerDependenciesMeta: 983 | jiti: 984 | optional: true 985 | postcss: 986 | optional: true 987 | tsx: 988 | optional: true 989 | yaml: 990 | optional: true 991 | 992 | postcss@8.5.6: 993 | resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} 994 | engines: {node: ^10 || ^12 || >=14} 995 | 996 | punycode@2.3.1: 997 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 998 | engines: {node: '>=6'} 999 | 1000 | readdirp@4.1.2: 1001 | resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} 1002 | engines: {node: '>= 14.18.0'} 1003 | 1004 | resolve-from@5.0.0: 1005 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 1006 | engines: {node: '>=8'} 1007 | 1008 | resolve-pkg-maps@1.0.0: 1009 | resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} 1010 | 1011 | rollup@4.52.3: 1012 | resolution: {integrity: sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==} 1013 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 1014 | hasBin: true 1015 | 1016 | rrweb-cssom@0.7.1: 1017 | resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} 1018 | 1019 | rrweb-cssom@0.8.0: 1020 | resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} 1021 | 1022 | safer-buffer@2.1.2: 1023 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 1024 | 1025 | saxes@6.0.0: 1026 | resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} 1027 | engines: {node: '>=v12.22.7'} 1028 | 1029 | semver@7.7.2: 1030 | resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} 1031 | engines: {node: '>=10'} 1032 | hasBin: true 1033 | 1034 | shebang-command@2.0.0: 1035 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1036 | engines: {node: '>=8'} 1037 | 1038 | shebang-regex@3.0.0: 1039 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1040 | engines: {node: '>=8'} 1041 | 1042 | siginfo@2.0.0: 1043 | resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} 1044 | 1045 | signal-exit@4.1.0: 1046 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 1047 | engines: {node: '>=14'} 1048 | 1049 | sirv@3.0.2: 1050 | resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} 1051 | engines: {node: '>=18'} 1052 | 1053 | source-map-js@1.2.1: 1054 | resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} 1055 | engines: {node: '>=0.10.0'} 1056 | 1057 | source-map@0.8.0-beta.0: 1058 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} 1059 | engines: {node: '>= 8'} 1060 | deprecated: The work that was done in this beta branch won't be included in future versions 1061 | 1062 | stackback@0.0.2: 1063 | resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} 1064 | 1065 | std-env@3.9.0: 1066 | resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} 1067 | 1068 | string-width@4.2.3: 1069 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 1070 | engines: {node: '>=8'} 1071 | 1072 | string-width@5.1.2: 1073 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 1074 | engines: {node: '>=12'} 1075 | 1076 | strip-ansi@6.0.1: 1077 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1078 | engines: {node: '>=8'} 1079 | 1080 | strip-ansi@7.1.2: 1081 | resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} 1082 | engines: {node: '>=12'} 1083 | 1084 | strip-literal@3.1.0: 1085 | resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} 1086 | 1087 | sucrase@3.35.0: 1088 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1089 | engines: {node: '>=16 || 14 >=14.17'} 1090 | hasBin: true 1091 | 1092 | supports-color@7.2.0: 1093 | resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} 1094 | engines: {node: '>=8'} 1095 | 1096 | symbol-tree@3.2.4: 1097 | resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} 1098 | 1099 | test-exclude@7.0.1: 1100 | resolution: {integrity: sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==} 1101 | engines: {node: '>=18'} 1102 | 1103 | thenify-all@1.6.0: 1104 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1105 | engines: {node: '>=0.8'} 1106 | 1107 | thenify@3.3.1: 1108 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1109 | 1110 | tinybench@2.9.0: 1111 | resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} 1112 | 1113 | tinyexec@0.3.2: 1114 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 1115 | 1116 | tinyglobby@0.2.15: 1117 | resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} 1118 | engines: {node: '>=12.0.0'} 1119 | 1120 | tinypool@1.1.1: 1121 | resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} 1122 | engines: {node: ^18.0.0 || >=20.0.0} 1123 | 1124 | tinyrainbow@2.0.0: 1125 | resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} 1126 | engines: {node: '>=14.0.0'} 1127 | 1128 | tinyspy@4.0.4: 1129 | resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} 1130 | engines: {node: '>=14.0.0'} 1131 | 1132 | tldts-core@6.1.86: 1133 | resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} 1134 | 1135 | tldts@6.1.86: 1136 | resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} 1137 | hasBin: true 1138 | 1139 | totalist@3.0.1: 1140 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 1141 | engines: {node: '>=6'} 1142 | 1143 | tough-cookie@5.1.2: 1144 | resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} 1145 | engines: {node: '>=16'} 1146 | 1147 | tr46@1.0.1: 1148 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} 1149 | 1150 | tr46@5.1.1: 1151 | resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} 1152 | engines: {node: '>=18'} 1153 | 1154 | tree-kill@1.2.2: 1155 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1156 | hasBin: true 1157 | 1158 | ts-interface-checker@0.1.13: 1159 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1160 | 1161 | tsup@8.5.0: 1162 | resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} 1163 | engines: {node: '>=18'} 1164 | hasBin: true 1165 | peerDependencies: 1166 | '@microsoft/api-extractor': ^7.36.0 1167 | '@swc/core': ^1 1168 | postcss: ^8.4.12 1169 | typescript: '>=4.5.0' 1170 | peerDependenciesMeta: 1171 | '@microsoft/api-extractor': 1172 | optional: true 1173 | '@swc/core': 1174 | optional: true 1175 | postcss: 1176 | optional: true 1177 | typescript: 1178 | optional: true 1179 | 1180 | tsx@4.20.6: 1181 | resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} 1182 | engines: {node: '>=18.0.0'} 1183 | hasBin: true 1184 | 1185 | typescript@5.9.2: 1186 | resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} 1187 | engines: {node: '>=14.17'} 1188 | hasBin: true 1189 | 1190 | ufo@1.6.1: 1191 | resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} 1192 | 1193 | undici-types@6.21.0: 1194 | resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} 1195 | 1196 | vite-node@3.2.4: 1197 | resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} 1198 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1199 | hasBin: true 1200 | 1201 | vite@7.1.7: 1202 | resolution: {integrity: sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==} 1203 | engines: {node: ^20.19.0 || >=22.12.0} 1204 | hasBin: true 1205 | peerDependencies: 1206 | '@types/node': ^20.19.0 || >=22.12.0 1207 | jiti: '>=1.21.0' 1208 | less: ^4.0.0 1209 | lightningcss: ^1.21.0 1210 | sass: ^1.70.0 1211 | sass-embedded: ^1.70.0 1212 | stylus: '>=0.54.8' 1213 | sugarss: ^5.0.0 1214 | terser: ^5.16.0 1215 | tsx: ^4.8.1 1216 | yaml: ^2.4.2 1217 | peerDependenciesMeta: 1218 | '@types/node': 1219 | optional: true 1220 | jiti: 1221 | optional: true 1222 | less: 1223 | optional: true 1224 | lightningcss: 1225 | optional: true 1226 | sass: 1227 | optional: true 1228 | sass-embedded: 1229 | optional: true 1230 | stylus: 1231 | optional: true 1232 | sugarss: 1233 | optional: true 1234 | terser: 1235 | optional: true 1236 | tsx: 1237 | optional: true 1238 | yaml: 1239 | optional: true 1240 | 1241 | vitest@3.2.4: 1242 | resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} 1243 | engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} 1244 | hasBin: true 1245 | peerDependencies: 1246 | '@edge-runtime/vm': '*' 1247 | '@types/debug': ^4.1.12 1248 | '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 1249 | '@vitest/browser': 3.2.4 1250 | '@vitest/ui': 3.2.4 1251 | happy-dom: '*' 1252 | jsdom: '*' 1253 | peerDependenciesMeta: 1254 | '@edge-runtime/vm': 1255 | optional: true 1256 | '@types/debug': 1257 | optional: true 1258 | '@types/node': 1259 | optional: true 1260 | '@vitest/browser': 1261 | optional: true 1262 | '@vitest/ui': 1263 | optional: true 1264 | happy-dom: 1265 | optional: true 1266 | jsdom: 1267 | optional: true 1268 | 1269 | w3c-xmlserializer@5.0.0: 1270 | resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} 1271 | engines: {node: '>=18'} 1272 | 1273 | webidl-conversions@4.0.2: 1274 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} 1275 | 1276 | webidl-conversions@7.0.0: 1277 | resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} 1278 | engines: {node: '>=12'} 1279 | 1280 | whatwg-encoding@3.1.1: 1281 | resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} 1282 | engines: {node: '>=18'} 1283 | 1284 | whatwg-mimetype@4.0.0: 1285 | resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} 1286 | engines: {node: '>=18'} 1287 | 1288 | whatwg-url@14.2.0: 1289 | resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} 1290 | engines: {node: '>=18'} 1291 | 1292 | whatwg-url@7.1.0: 1293 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} 1294 | 1295 | which@2.0.2: 1296 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1297 | engines: {node: '>= 8'} 1298 | hasBin: true 1299 | 1300 | why-is-node-running@2.3.0: 1301 | resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} 1302 | engines: {node: '>=8'} 1303 | hasBin: true 1304 | 1305 | wrap-ansi@7.0.0: 1306 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1307 | engines: {node: '>=10'} 1308 | 1309 | wrap-ansi@8.1.0: 1310 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1311 | engines: {node: '>=12'} 1312 | 1313 | ws@8.18.3: 1314 | resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} 1315 | engines: {node: '>=10.0.0'} 1316 | peerDependencies: 1317 | bufferutil: ^4.0.1 1318 | utf-8-validate: '>=5.0.2' 1319 | peerDependenciesMeta: 1320 | bufferutil: 1321 | optional: true 1322 | utf-8-validate: 1323 | optional: true 1324 | 1325 | xml-name-validator@5.0.0: 1326 | resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} 1327 | engines: {node: '>=18'} 1328 | 1329 | xmlchars@2.2.0: 1330 | resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} 1331 | 1332 | yaml@2.5.1: 1333 | resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} 1334 | engines: {node: '>= 14'} 1335 | hasBin: true 1336 | 1337 | zod-openapi@5.4.2: 1338 | resolution: {integrity: sha512-F2s/1E/8Ahd43JhrkqE/dc13qjaGF/VTdUVq7rtRKvyDWyuYYryyzdxHnzH1ff1zLpd4KkvNvIpeBnVQShlxYg==} 1339 | engines: {node: '>=20'} 1340 | peerDependencies: 1341 | zod: ^3.25.74 || ^4.0.0 1342 | 1343 | zod@4.1.11: 1344 | resolution: {integrity: sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==} 1345 | 1346 | snapshots: 1347 | 1348 | '@ampproject/remapping@2.3.0': 1349 | dependencies: 1350 | '@jridgewell/gen-mapping': 0.3.13 1351 | '@jridgewell/trace-mapping': 0.3.31 1352 | 1353 | '@asamuzakjp/css-color@3.2.0': 1354 | dependencies: 1355 | '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) 1356 | '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) 1357 | '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) 1358 | '@csstools/css-tokenizer': 3.0.4 1359 | lru-cache: 10.4.3 1360 | optional: true 1361 | 1362 | '@babel/helper-string-parser@7.27.1': {} 1363 | 1364 | '@babel/helper-validator-identifier@7.27.1': {} 1365 | 1366 | '@babel/parser@7.28.4': 1367 | dependencies: 1368 | '@babel/types': 7.28.4 1369 | 1370 | '@babel/types@7.28.4': 1371 | dependencies: 1372 | '@babel/helper-string-parser': 7.27.1 1373 | '@babel/helper-validator-identifier': 7.27.1 1374 | 1375 | '@bcoe/v8-coverage@1.0.2': {} 1376 | 1377 | '@biomejs/biome@1.9.4': 1378 | optionalDependencies: 1379 | '@biomejs/cli-darwin-arm64': 1.9.4 1380 | '@biomejs/cli-darwin-x64': 1.9.4 1381 | '@biomejs/cli-linux-arm64': 1.9.4 1382 | '@biomejs/cli-linux-arm64-musl': 1.9.4 1383 | '@biomejs/cli-linux-x64': 1.9.4 1384 | '@biomejs/cli-linux-x64-musl': 1.9.4 1385 | '@biomejs/cli-win32-arm64': 1.9.4 1386 | '@biomejs/cli-win32-x64': 1.9.4 1387 | 1388 | '@biomejs/cli-darwin-arm64@1.9.4': 1389 | optional: true 1390 | 1391 | '@biomejs/cli-darwin-x64@1.9.4': 1392 | optional: true 1393 | 1394 | '@biomejs/cli-linux-arm64-musl@1.9.4': 1395 | optional: true 1396 | 1397 | '@biomejs/cli-linux-arm64@1.9.4': 1398 | optional: true 1399 | 1400 | '@biomejs/cli-linux-x64-musl@1.9.4': 1401 | optional: true 1402 | 1403 | '@biomejs/cli-linux-x64@1.9.4': 1404 | optional: true 1405 | 1406 | '@biomejs/cli-win32-arm64@1.9.4': 1407 | optional: true 1408 | 1409 | '@biomejs/cli-win32-x64@1.9.4': 1410 | optional: true 1411 | 1412 | '@csstools/color-helpers@5.1.0': 1413 | optional: true 1414 | 1415 | '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': 1416 | dependencies: 1417 | '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) 1418 | '@csstools/css-tokenizer': 3.0.4 1419 | optional: true 1420 | 1421 | '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': 1422 | dependencies: 1423 | '@csstools/color-helpers': 5.1.0 1424 | '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) 1425 | '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) 1426 | '@csstools/css-tokenizer': 3.0.4 1427 | optional: true 1428 | 1429 | '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': 1430 | dependencies: 1431 | '@csstools/css-tokenizer': 3.0.4 1432 | optional: true 1433 | 1434 | '@csstools/css-tokenizer@3.0.4': 1435 | optional: true 1436 | 1437 | '@esbuild/aix-ppc64@0.25.10': 1438 | optional: true 1439 | 1440 | '@esbuild/android-arm64@0.25.10': 1441 | optional: true 1442 | 1443 | '@esbuild/android-arm@0.25.10': 1444 | optional: true 1445 | 1446 | '@esbuild/android-x64@0.25.10': 1447 | optional: true 1448 | 1449 | '@esbuild/darwin-arm64@0.25.10': 1450 | optional: true 1451 | 1452 | '@esbuild/darwin-x64@0.25.10': 1453 | optional: true 1454 | 1455 | '@esbuild/freebsd-arm64@0.25.10': 1456 | optional: true 1457 | 1458 | '@esbuild/freebsd-x64@0.25.10': 1459 | optional: true 1460 | 1461 | '@esbuild/linux-arm64@0.25.10': 1462 | optional: true 1463 | 1464 | '@esbuild/linux-arm@0.25.10': 1465 | optional: true 1466 | 1467 | '@esbuild/linux-ia32@0.25.10': 1468 | optional: true 1469 | 1470 | '@esbuild/linux-loong64@0.25.10': 1471 | optional: true 1472 | 1473 | '@esbuild/linux-mips64el@0.25.10': 1474 | optional: true 1475 | 1476 | '@esbuild/linux-ppc64@0.25.10': 1477 | optional: true 1478 | 1479 | '@esbuild/linux-riscv64@0.25.10': 1480 | optional: true 1481 | 1482 | '@esbuild/linux-s390x@0.25.10': 1483 | optional: true 1484 | 1485 | '@esbuild/linux-x64@0.25.10': 1486 | optional: true 1487 | 1488 | '@esbuild/netbsd-arm64@0.25.10': 1489 | optional: true 1490 | 1491 | '@esbuild/netbsd-x64@0.25.10': 1492 | optional: true 1493 | 1494 | '@esbuild/openbsd-arm64@0.25.10': 1495 | optional: true 1496 | 1497 | '@esbuild/openbsd-x64@0.25.10': 1498 | optional: true 1499 | 1500 | '@esbuild/openharmony-arm64@0.25.10': 1501 | optional: true 1502 | 1503 | '@esbuild/sunos-x64@0.25.10': 1504 | optional: true 1505 | 1506 | '@esbuild/win32-arm64@0.25.10': 1507 | optional: true 1508 | 1509 | '@esbuild/win32-ia32@0.25.10': 1510 | optional: true 1511 | 1512 | '@esbuild/win32-x64@0.25.10': 1513 | optional: true 1514 | 1515 | '@hono/node-server@1.19.4(hono@4.9.9)': 1516 | dependencies: 1517 | hono: 4.9.9 1518 | 1519 | '@hono/swagger-ui@0.5.2(hono@4.9.9)': 1520 | dependencies: 1521 | hono: 4.9.9 1522 | 1523 | '@hono/zod-validator@0.7.3(hono@4.9.9)(zod@4.1.11)': 1524 | dependencies: 1525 | hono: 4.9.9 1526 | zod: 4.1.11 1527 | 1528 | '@isaacs/cliui@8.0.2': 1529 | dependencies: 1530 | string-width: 5.1.2 1531 | string-width-cjs: string-width@4.2.3 1532 | strip-ansi: 7.1.2 1533 | strip-ansi-cjs: strip-ansi@6.0.1 1534 | wrap-ansi: 8.1.0 1535 | wrap-ansi-cjs: wrap-ansi@7.0.0 1536 | 1537 | '@istanbuljs/schema@0.1.3': {} 1538 | 1539 | '@jridgewell/gen-mapping@0.3.13': 1540 | dependencies: 1541 | '@jridgewell/sourcemap-codec': 1.5.5 1542 | '@jridgewell/trace-mapping': 0.3.31 1543 | 1544 | '@jridgewell/resolve-uri@3.1.2': {} 1545 | 1546 | '@jridgewell/sourcemap-codec@1.5.5': {} 1547 | 1548 | '@jridgewell/trace-mapping@0.3.31': 1549 | dependencies: 1550 | '@jridgewell/resolve-uri': 3.1.2 1551 | '@jridgewell/sourcemap-codec': 1.5.5 1552 | 1553 | '@pkgjs/parseargs@0.11.0': 1554 | optional: true 1555 | 1556 | '@polka/url@1.0.0-next.29': {} 1557 | 1558 | '@rollup/rollup-android-arm-eabi@4.52.3': 1559 | optional: true 1560 | 1561 | '@rollup/rollup-android-arm64@4.52.3': 1562 | optional: true 1563 | 1564 | '@rollup/rollup-darwin-arm64@4.52.3': 1565 | optional: true 1566 | 1567 | '@rollup/rollup-darwin-x64@4.52.3': 1568 | optional: true 1569 | 1570 | '@rollup/rollup-freebsd-arm64@4.52.3': 1571 | optional: true 1572 | 1573 | '@rollup/rollup-freebsd-x64@4.52.3': 1574 | optional: true 1575 | 1576 | '@rollup/rollup-linux-arm-gnueabihf@4.52.3': 1577 | optional: true 1578 | 1579 | '@rollup/rollup-linux-arm-musleabihf@4.52.3': 1580 | optional: true 1581 | 1582 | '@rollup/rollup-linux-arm64-gnu@4.52.3': 1583 | optional: true 1584 | 1585 | '@rollup/rollup-linux-arm64-musl@4.52.3': 1586 | optional: true 1587 | 1588 | '@rollup/rollup-linux-loong64-gnu@4.52.3': 1589 | optional: true 1590 | 1591 | '@rollup/rollup-linux-ppc64-gnu@4.52.3': 1592 | optional: true 1593 | 1594 | '@rollup/rollup-linux-riscv64-gnu@4.52.3': 1595 | optional: true 1596 | 1597 | '@rollup/rollup-linux-riscv64-musl@4.52.3': 1598 | optional: true 1599 | 1600 | '@rollup/rollup-linux-s390x-gnu@4.52.3': 1601 | optional: true 1602 | 1603 | '@rollup/rollup-linux-x64-gnu@4.52.3': 1604 | optional: true 1605 | 1606 | '@rollup/rollup-linux-x64-musl@4.52.3': 1607 | optional: true 1608 | 1609 | '@rollup/rollup-openharmony-arm64@4.52.3': 1610 | optional: true 1611 | 1612 | '@rollup/rollup-win32-arm64-msvc@4.52.3': 1613 | optional: true 1614 | 1615 | '@rollup/rollup-win32-ia32-msvc@4.52.3': 1616 | optional: true 1617 | 1618 | '@rollup/rollup-win32-x64-gnu@4.52.3': 1619 | optional: true 1620 | 1621 | '@rollup/rollup-win32-x64-msvc@4.52.3': 1622 | optional: true 1623 | 1624 | '@types/chai@5.2.2': 1625 | dependencies: 1626 | '@types/deep-eql': 4.0.2 1627 | 1628 | '@types/deep-eql@4.0.2': {} 1629 | 1630 | '@types/estree@1.0.8': {} 1631 | 1632 | '@types/node@22.18.6': 1633 | dependencies: 1634 | undici-types: 6.21.0 1635 | 1636 | '@vitest/coverage-v8@3.2.4(vitest@3.2.4)': 1637 | dependencies: 1638 | '@ampproject/remapping': 2.3.0 1639 | '@bcoe/v8-coverage': 1.0.2 1640 | ast-v8-to-istanbul: 0.3.5 1641 | debug: 4.4.3 1642 | istanbul-lib-coverage: 3.2.2 1643 | istanbul-lib-report: 3.0.1 1644 | istanbul-lib-source-maps: 5.0.6 1645 | istanbul-reports: 3.2.0 1646 | magic-string: 0.30.19 1647 | magicast: 0.3.5 1648 | std-env: 3.9.0 1649 | test-exclude: 7.0.1 1650 | tinyrainbow: 2.0.0 1651 | vitest: 3.2.4(@types/node@22.18.6)(@vitest/ui@3.2.4)(jsdom@25.0.1)(tsx@4.20.6)(yaml@2.5.1) 1652 | transitivePeerDependencies: 1653 | - supports-color 1654 | 1655 | '@vitest/expect@3.2.4': 1656 | dependencies: 1657 | '@types/chai': 5.2.2 1658 | '@vitest/spy': 3.2.4 1659 | '@vitest/utils': 3.2.4 1660 | chai: 5.3.3 1661 | tinyrainbow: 2.0.0 1662 | 1663 | '@vitest/mocker@3.2.4(vite@7.1.7(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1))': 1664 | dependencies: 1665 | '@vitest/spy': 3.2.4 1666 | estree-walker: 3.0.3 1667 | magic-string: 0.30.19 1668 | optionalDependencies: 1669 | vite: 7.1.7(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1) 1670 | 1671 | '@vitest/pretty-format@3.2.4': 1672 | dependencies: 1673 | tinyrainbow: 2.0.0 1674 | 1675 | '@vitest/runner@3.2.4': 1676 | dependencies: 1677 | '@vitest/utils': 3.2.4 1678 | pathe: 2.0.3 1679 | strip-literal: 3.1.0 1680 | 1681 | '@vitest/snapshot@3.2.4': 1682 | dependencies: 1683 | '@vitest/pretty-format': 3.2.4 1684 | magic-string: 0.30.19 1685 | pathe: 2.0.3 1686 | 1687 | '@vitest/spy@3.2.4': 1688 | dependencies: 1689 | tinyspy: 4.0.4 1690 | 1691 | '@vitest/ui@3.2.4(vitest@3.2.4)': 1692 | dependencies: 1693 | '@vitest/utils': 3.2.4 1694 | fflate: 0.8.2 1695 | flatted: 3.3.3 1696 | pathe: 2.0.3 1697 | sirv: 3.0.2 1698 | tinyglobby: 0.2.15 1699 | tinyrainbow: 2.0.0 1700 | vitest: 3.2.4(@types/node@22.18.6)(@vitest/ui@3.2.4)(jsdom@25.0.1)(tsx@4.20.6)(yaml@2.5.1) 1701 | 1702 | '@vitest/utils@3.2.4': 1703 | dependencies: 1704 | '@vitest/pretty-format': 3.2.4 1705 | loupe: 3.2.1 1706 | tinyrainbow: 2.0.0 1707 | 1708 | acorn@8.15.0: {} 1709 | 1710 | agent-base@7.1.4: 1711 | optional: true 1712 | 1713 | ansi-regex@5.0.1: {} 1714 | 1715 | ansi-regex@6.2.2: {} 1716 | 1717 | ansi-styles@4.3.0: 1718 | dependencies: 1719 | color-convert: 2.0.1 1720 | 1721 | ansi-styles@6.2.3: {} 1722 | 1723 | any-promise@1.3.0: {} 1724 | 1725 | assertion-error@2.0.1: {} 1726 | 1727 | ast-v8-to-istanbul@0.3.5: 1728 | dependencies: 1729 | '@jridgewell/trace-mapping': 0.3.31 1730 | estree-walker: 3.0.3 1731 | js-tokens: 9.0.1 1732 | 1733 | asynckit@0.4.0: 1734 | optional: true 1735 | 1736 | balanced-match@1.0.2: {} 1737 | 1738 | brace-expansion@2.0.2: 1739 | dependencies: 1740 | balanced-match: 1.0.2 1741 | 1742 | bundle-require@5.1.0(esbuild@0.25.10): 1743 | dependencies: 1744 | esbuild: 0.25.10 1745 | load-tsconfig: 0.2.5 1746 | 1747 | cac@6.7.14: {} 1748 | 1749 | call-bind-apply-helpers@1.0.2: 1750 | dependencies: 1751 | es-errors: 1.3.0 1752 | function-bind: 1.1.2 1753 | optional: true 1754 | 1755 | chai@5.3.3: 1756 | dependencies: 1757 | assertion-error: 2.0.1 1758 | check-error: 2.1.1 1759 | deep-eql: 5.0.2 1760 | loupe: 3.2.1 1761 | pathval: 2.0.1 1762 | 1763 | check-error@2.1.1: {} 1764 | 1765 | chokidar@4.0.3: 1766 | dependencies: 1767 | readdirp: 4.1.2 1768 | 1769 | color-convert@2.0.1: 1770 | dependencies: 1771 | color-name: 1.1.4 1772 | 1773 | color-name@1.1.4: {} 1774 | 1775 | combined-stream@1.0.8: 1776 | dependencies: 1777 | delayed-stream: 1.0.0 1778 | optional: true 1779 | 1780 | commander@4.1.1: {} 1781 | 1782 | confbox@0.1.8: {} 1783 | 1784 | consola@3.4.2: {} 1785 | 1786 | cross-spawn@7.0.6: 1787 | dependencies: 1788 | path-key: 3.1.1 1789 | shebang-command: 2.0.0 1790 | which: 2.0.2 1791 | 1792 | cssstyle@4.6.0: 1793 | dependencies: 1794 | '@asamuzakjp/css-color': 3.2.0 1795 | rrweb-cssom: 0.8.0 1796 | optional: true 1797 | 1798 | data-urls@5.0.0: 1799 | dependencies: 1800 | whatwg-mimetype: 4.0.0 1801 | whatwg-url: 14.2.0 1802 | optional: true 1803 | 1804 | debug@4.4.3: 1805 | dependencies: 1806 | ms: 2.1.3 1807 | 1808 | decimal.js@10.6.0: 1809 | optional: true 1810 | 1811 | deep-eql@5.0.2: {} 1812 | 1813 | delayed-stream@1.0.0: 1814 | optional: true 1815 | 1816 | dunder-proto@1.0.1: 1817 | dependencies: 1818 | call-bind-apply-helpers: 1.0.2 1819 | es-errors: 1.3.0 1820 | gopd: 1.2.0 1821 | optional: true 1822 | 1823 | eastasianwidth@0.2.0: {} 1824 | 1825 | emoji-regex@8.0.0: {} 1826 | 1827 | emoji-regex@9.2.2: {} 1828 | 1829 | entities@6.0.1: 1830 | optional: true 1831 | 1832 | es-define-property@1.0.1: 1833 | optional: true 1834 | 1835 | es-errors@1.3.0: 1836 | optional: true 1837 | 1838 | es-module-lexer@1.7.0: {} 1839 | 1840 | es-object-atoms@1.1.1: 1841 | dependencies: 1842 | es-errors: 1.3.0 1843 | optional: true 1844 | 1845 | es-set-tostringtag@2.1.0: 1846 | dependencies: 1847 | es-errors: 1.3.0 1848 | get-intrinsic: 1.3.0 1849 | has-tostringtag: 1.0.2 1850 | hasown: 2.0.2 1851 | optional: true 1852 | 1853 | esbuild@0.25.10: 1854 | optionalDependencies: 1855 | '@esbuild/aix-ppc64': 0.25.10 1856 | '@esbuild/android-arm': 0.25.10 1857 | '@esbuild/android-arm64': 0.25.10 1858 | '@esbuild/android-x64': 0.25.10 1859 | '@esbuild/darwin-arm64': 0.25.10 1860 | '@esbuild/darwin-x64': 0.25.10 1861 | '@esbuild/freebsd-arm64': 0.25.10 1862 | '@esbuild/freebsd-x64': 0.25.10 1863 | '@esbuild/linux-arm': 0.25.10 1864 | '@esbuild/linux-arm64': 0.25.10 1865 | '@esbuild/linux-ia32': 0.25.10 1866 | '@esbuild/linux-loong64': 0.25.10 1867 | '@esbuild/linux-mips64el': 0.25.10 1868 | '@esbuild/linux-ppc64': 0.25.10 1869 | '@esbuild/linux-riscv64': 0.25.10 1870 | '@esbuild/linux-s390x': 0.25.10 1871 | '@esbuild/linux-x64': 0.25.10 1872 | '@esbuild/netbsd-arm64': 0.25.10 1873 | '@esbuild/netbsd-x64': 0.25.10 1874 | '@esbuild/openbsd-arm64': 0.25.10 1875 | '@esbuild/openbsd-x64': 0.25.10 1876 | '@esbuild/openharmony-arm64': 0.25.10 1877 | '@esbuild/sunos-x64': 0.25.10 1878 | '@esbuild/win32-arm64': 0.25.10 1879 | '@esbuild/win32-ia32': 0.25.10 1880 | '@esbuild/win32-x64': 0.25.10 1881 | 1882 | estree-walker@3.0.3: 1883 | dependencies: 1884 | '@types/estree': 1.0.8 1885 | 1886 | expect-type@1.2.2: {} 1887 | 1888 | fdir@6.5.0(picomatch@4.0.3): 1889 | optionalDependencies: 1890 | picomatch: 4.0.3 1891 | 1892 | fflate@0.8.2: {} 1893 | 1894 | fix-dts-default-cjs-exports@1.0.1: 1895 | dependencies: 1896 | magic-string: 0.30.19 1897 | mlly: 1.8.0 1898 | rollup: 4.52.3 1899 | 1900 | flatted@3.3.3: {} 1901 | 1902 | foreground-child@3.3.1: 1903 | dependencies: 1904 | cross-spawn: 7.0.6 1905 | signal-exit: 4.1.0 1906 | 1907 | form-data@4.0.4: 1908 | dependencies: 1909 | asynckit: 0.4.0 1910 | combined-stream: 1.0.8 1911 | es-set-tostringtag: 2.1.0 1912 | hasown: 2.0.2 1913 | mime-types: 2.1.35 1914 | optional: true 1915 | 1916 | fsevents@2.3.3: 1917 | optional: true 1918 | 1919 | function-bind@1.1.2: 1920 | optional: true 1921 | 1922 | get-intrinsic@1.3.0: 1923 | dependencies: 1924 | call-bind-apply-helpers: 1.0.2 1925 | es-define-property: 1.0.1 1926 | es-errors: 1.3.0 1927 | es-object-atoms: 1.1.1 1928 | function-bind: 1.1.2 1929 | get-proto: 1.0.1 1930 | gopd: 1.2.0 1931 | has-symbols: 1.1.0 1932 | hasown: 2.0.2 1933 | math-intrinsics: 1.1.0 1934 | optional: true 1935 | 1936 | get-proto@1.0.1: 1937 | dependencies: 1938 | dunder-proto: 1.0.1 1939 | es-object-atoms: 1.1.1 1940 | optional: true 1941 | 1942 | get-tsconfig@4.10.1: 1943 | dependencies: 1944 | resolve-pkg-maps: 1.0.0 1945 | 1946 | glob@10.4.5: 1947 | dependencies: 1948 | foreground-child: 3.3.1 1949 | jackspeak: 3.4.3 1950 | minimatch: 9.0.5 1951 | minipass: 7.1.2 1952 | package-json-from-dist: 1.0.1 1953 | path-scurry: 1.11.1 1954 | 1955 | gopd@1.2.0: 1956 | optional: true 1957 | 1958 | has-flag@4.0.0: {} 1959 | 1960 | has-symbols@1.1.0: 1961 | optional: true 1962 | 1963 | has-tostringtag@1.0.2: 1964 | dependencies: 1965 | has-symbols: 1.1.0 1966 | optional: true 1967 | 1968 | hasown@2.0.2: 1969 | dependencies: 1970 | function-bind: 1.1.2 1971 | optional: true 1972 | 1973 | hono@4.9.9: {} 1974 | 1975 | html-encoding-sniffer@4.0.0: 1976 | dependencies: 1977 | whatwg-encoding: 3.1.1 1978 | optional: true 1979 | 1980 | html-escaper@2.0.2: {} 1981 | 1982 | http-proxy-agent@7.0.2: 1983 | dependencies: 1984 | agent-base: 7.1.4 1985 | debug: 4.4.3 1986 | transitivePeerDependencies: 1987 | - supports-color 1988 | optional: true 1989 | 1990 | https-proxy-agent@7.0.6: 1991 | dependencies: 1992 | agent-base: 7.1.4 1993 | debug: 4.4.3 1994 | transitivePeerDependencies: 1995 | - supports-color 1996 | optional: true 1997 | 1998 | husky@9.1.7: {} 1999 | 2000 | iconv-lite@0.6.3: 2001 | dependencies: 2002 | safer-buffer: 2.1.2 2003 | optional: true 2004 | 2005 | is-fullwidth-code-point@3.0.0: {} 2006 | 2007 | is-potential-custom-element-name@1.0.1: 2008 | optional: true 2009 | 2010 | isexe@2.0.0: {} 2011 | 2012 | istanbul-lib-coverage@3.2.2: {} 2013 | 2014 | istanbul-lib-report@3.0.1: 2015 | dependencies: 2016 | istanbul-lib-coverage: 3.2.2 2017 | make-dir: 4.0.0 2018 | supports-color: 7.2.0 2019 | 2020 | istanbul-lib-source-maps@5.0.6: 2021 | dependencies: 2022 | '@jridgewell/trace-mapping': 0.3.31 2023 | debug: 4.4.3 2024 | istanbul-lib-coverage: 3.2.2 2025 | transitivePeerDependencies: 2026 | - supports-color 2027 | 2028 | istanbul-reports@3.2.0: 2029 | dependencies: 2030 | html-escaper: 2.0.2 2031 | istanbul-lib-report: 3.0.1 2032 | 2033 | jackspeak@3.4.3: 2034 | dependencies: 2035 | '@isaacs/cliui': 8.0.2 2036 | optionalDependencies: 2037 | '@pkgjs/parseargs': 0.11.0 2038 | 2039 | joycon@3.1.1: {} 2040 | 2041 | js-tokens@9.0.1: {} 2042 | 2043 | jsdom@25.0.1: 2044 | dependencies: 2045 | cssstyle: 4.6.0 2046 | data-urls: 5.0.0 2047 | decimal.js: 10.6.0 2048 | form-data: 4.0.4 2049 | html-encoding-sniffer: 4.0.0 2050 | http-proxy-agent: 7.0.2 2051 | https-proxy-agent: 7.0.6 2052 | is-potential-custom-element-name: 1.0.1 2053 | nwsapi: 2.2.22 2054 | parse5: 7.3.0 2055 | rrweb-cssom: 0.7.1 2056 | saxes: 6.0.0 2057 | symbol-tree: 3.2.4 2058 | tough-cookie: 5.1.2 2059 | w3c-xmlserializer: 5.0.0 2060 | webidl-conversions: 7.0.0 2061 | whatwg-encoding: 3.1.1 2062 | whatwg-mimetype: 4.0.0 2063 | whatwg-url: 14.2.0 2064 | ws: 8.18.3 2065 | xml-name-validator: 5.0.0 2066 | transitivePeerDependencies: 2067 | - bufferutil 2068 | - supports-color 2069 | - utf-8-validate 2070 | optional: true 2071 | 2072 | lilconfig@3.1.3: {} 2073 | 2074 | lines-and-columns@1.2.4: {} 2075 | 2076 | load-tsconfig@0.2.5: {} 2077 | 2078 | lodash.sortby@4.7.0: {} 2079 | 2080 | loupe@3.2.1: {} 2081 | 2082 | lru-cache@10.4.3: {} 2083 | 2084 | magic-string@0.30.19: 2085 | dependencies: 2086 | '@jridgewell/sourcemap-codec': 1.5.5 2087 | 2088 | magicast@0.3.5: 2089 | dependencies: 2090 | '@babel/parser': 7.28.4 2091 | '@babel/types': 7.28.4 2092 | source-map-js: 1.2.1 2093 | 2094 | make-dir@4.0.0: 2095 | dependencies: 2096 | semver: 7.7.2 2097 | 2098 | math-intrinsics@1.1.0: 2099 | optional: true 2100 | 2101 | mime-db@1.52.0: 2102 | optional: true 2103 | 2104 | mime-types@2.1.35: 2105 | dependencies: 2106 | mime-db: 1.52.0 2107 | optional: true 2108 | 2109 | minimatch@9.0.5: 2110 | dependencies: 2111 | brace-expansion: 2.0.2 2112 | 2113 | minipass@7.1.2: {} 2114 | 2115 | mlly@1.8.0: 2116 | dependencies: 2117 | acorn: 8.15.0 2118 | pathe: 2.0.3 2119 | pkg-types: 1.3.1 2120 | ufo: 1.6.1 2121 | 2122 | mrmime@2.0.1: {} 2123 | 2124 | ms@2.1.3: {} 2125 | 2126 | mz@2.7.0: 2127 | dependencies: 2128 | any-promise: 1.3.0 2129 | object-assign: 4.1.1 2130 | thenify-all: 1.6.0 2131 | 2132 | nanoid@3.3.11: {} 2133 | 2134 | nwsapi@2.2.22: 2135 | optional: true 2136 | 2137 | object-assign@4.1.1: {} 2138 | 2139 | package-json-from-dist@1.0.1: {} 2140 | 2141 | parse5@7.3.0: 2142 | dependencies: 2143 | entities: 6.0.1 2144 | optional: true 2145 | 2146 | path-key@3.1.1: {} 2147 | 2148 | path-scurry@1.11.1: 2149 | dependencies: 2150 | lru-cache: 10.4.3 2151 | minipass: 7.1.2 2152 | 2153 | pathe@2.0.3: {} 2154 | 2155 | pathval@2.0.1: {} 2156 | 2157 | picocolors@1.1.1: {} 2158 | 2159 | picomatch@4.0.3: {} 2160 | 2161 | pirates@4.0.7: {} 2162 | 2163 | pkg-types@1.3.1: 2164 | dependencies: 2165 | confbox: 0.1.8 2166 | mlly: 1.8.0 2167 | pathe: 2.0.3 2168 | 2169 | postcss-load-config@6.0.1(postcss@8.5.6)(tsx@4.20.6)(yaml@2.5.1): 2170 | dependencies: 2171 | lilconfig: 3.1.3 2172 | optionalDependencies: 2173 | postcss: 8.5.6 2174 | tsx: 4.20.6 2175 | yaml: 2.5.1 2176 | 2177 | postcss@8.5.6: 2178 | dependencies: 2179 | nanoid: 3.3.11 2180 | picocolors: 1.1.1 2181 | source-map-js: 1.2.1 2182 | 2183 | punycode@2.3.1: {} 2184 | 2185 | readdirp@4.1.2: {} 2186 | 2187 | resolve-from@5.0.0: {} 2188 | 2189 | resolve-pkg-maps@1.0.0: {} 2190 | 2191 | rollup@4.52.3: 2192 | dependencies: 2193 | '@types/estree': 1.0.8 2194 | optionalDependencies: 2195 | '@rollup/rollup-android-arm-eabi': 4.52.3 2196 | '@rollup/rollup-android-arm64': 4.52.3 2197 | '@rollup/rollup-darwin-arm64': 4.52.3 2198 | '@rollup/rollup-darwin-x64': 4.52.3 2199 | '@rollup/rollup-freebsd-arm64': 4.52.3 2200 | '@rollup/rollup-freebsd-x64': 4.52.3 2201 | '@rollup/rollup-linux-arm-gnueabihf': 4.52.3 2202 | '@rollup/rollup-linux-arm-musleabihf': 4.52.3 2203 | '@rollup/rollup-linux-arm64-gnu': 4.52.3 2204 | '@rollup/rollup-linux-arm64-musl': 4.52.3 2205 | '@rollup/rollup-linux-loong64-gnu': 4.52.3 2206 | '@rollup/rollup-linux-ppc64-gnu': 4.52.3 2207 | '@rollup/rollup-linux-riscv64-gnu': 4.52.3 2208 | '@rollup/rollup-linux-riscv64-musl': 4.52.3 2209 | '@rollup/rollup-linux-s390x-gnu': 4.52.3 2210 | '@rollup/rollup-linux-x64-gnu': 4.52.3 2211 | '@rollup/rollup-linux-x64-musl': 4.52.3 2212 | '@rollup/rollup-openharmony-arm64': 4.52.3 2213 | '@rollup/rollup-win32-arm64-msvc': 4.52.3 2214 | '@rollup/rollup-win32-ia32-msvc': 4.52.3 2215 | '@rollup/rollup-win32-x64-gnu': 4.52.3 2216 | '@rollup/rollup-win32-x64-msvc': 4.52.3 2217 | fsevents: 2.3.3 2218 | 2219 | rrweb-cssom@0.7.1: 2220 | optional: true 2221 | 2222 | rrweb-cssom@0.8.0: 2223 | optional: true 2224 | 2225 | safer-buffer@2.1.2: 2226 | optional: true 2227 | 2228 | saxes@6.0.0: 2229 | dependencies: 2230 | xmlchars: 2.2.0 2231 | optional: true 2232 | 2233 | semver@7.7.2: {} 2234 | 2235 | shebang-command@2.0.0: 2236 | dependencies: 2237 | shebang-regex: 3.0.0 2238 | 2239 | shebang-regex@3.0.0: {} 2240 | 2241 | siginfo@2.0.0: {} 2242 | 2243 | signal-exit@4.1.0: {} 2244 | 2245 | sirv@3.0.2: 2246 | dependencies: 2247 | '@polka/url': 1.0.0-next.29 2248 | mrmime: 2.0.1 2249 | totalist: 3.0.1 2250 | 2251 | source-map-js@1.2.1: {} 2252 | 2253 | source-map@0.8.0-beta.0: 2254 | dependencies: 2255 | whatwg-url: 7.1.0 2256 | 2257 | stackback@0.0.2: {} 2258 | 2259 | std-env@3.9.0: {} 2260 | 2261 | string-width@4.2.3: 2262 | dependencies: 2263 | emoji-regex: 8.0.0 2264 | is-fullwidth-code-point: 3.0.0 2265 | strip-ansi: 6.0.1 2266 | 2267 | string-width@5.1.2: 2268 | dependencies: 2269 | eastasianwidth: 0.2.0 2270 | emoji-regex: 9.2.2 2271 | strip-ansi: 7.1.2 2272 | 2273 | strip-ansi@6.0.1: 2274 | dependencies: 2275 | ansi-regex: 5.0.1 2276 | 2277 | strip-ansi@7.1.2: 2278 | dependencies: 2279 | ansi-regex: 6.2.2 2280 | 2281 | strip-literal@3.1.0: 2282 | dependencies: 2283 | js-tokens: 9.0.1 2284 | 2285 | sucrase@3.35.0: 2286 | dependencies: 2287 | '@jridgewell/gen-mapping': 0.3.13 2288 | commander: 4.1.1 2289 | glob: 10.4.5 2290 | lines-and-columns: 1.2.4 2291 | mz: 2.7.0 2292 | pirates: 4.0.7 2293 | ts-interface-checker: 0.1.13 2294 | 2295 | supports-color@7.2.0: 2296 | dependencies: 2297 | has-flag: 4.0.0 2298 | 2299 | symbol-tree@3.2.4: 2300 | optional: true 2301 | 2302 | test-exclude@7.0.1: 2303 | dependencies: 2304 | '@istanbuljs/schema': 0.1.3 2305 | glob: 10.4.5 2306 | minimatch: 9.0.5 2307 | 2308 | thenify-all@1.6.0: 2309 | dependencies: 2310 | thenify: 3.3.1 2311 | 2312 | thenify@3.3.1: 2313 | dependencies: 2314 | any-promise: 1.3.0 2315 | 2316 | tinybench@2.9.0: {} 2317 | 2318 | tinyexec@0.3.2: {} 2319 | 2320 | tinyglobby@0.2.15: 2321 | dependencies: 2322 | fdir: 6.5.0(picomatch@4.0.3) 2323 | picomatch: 4.0.3 2324 | 2325 | tinypool@1.1.1: {} 2326 | 2327 | tinyrainbow@2.0.0: {} 2328 | 2329 | tinyspy@4.0.4: {} 2330 | 2331 | tldts-core@6.1.86: 2332 | optional: true 2333 | 2334 | tldts@6.1.86: 2335 | dependencies: 2336 | tldts-core: 6.1.86 2337 | optional: true 2338 | 2339 | totalist@3.0.1: {} 2340 | 2341 | tough-cookie@5.1.2: 2342 | dependencies: 2343 | tldts: 6.1.86 2344 | optional: true 2345 | 2346 | tr46@1.0.1: 2347 | dependencies: 2348 | punycode: 2.3.1 2349 | 2350 | tr46@5.1.1: 2351 | dependencies: 2352 | punycode: 2.3.1 2353 | optional: true 2354 | 2355 | tree-kill@1.2.2: {} 2356 | 2357 | ts-interface-checker@0.1.13: {} 2358 | 2359 | tsup@8.5.0(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.2)(yaml@2.5.1): 2360 | dependencies: 2361 | bundle-require: 5.1.0(esbuild@0.25.10) 2362 | cac: 6.7.14 2363 | chokidar: 4.0.3 2364 | consola: 3.4.2 2365 | debug: 4.4.3 2366 | esbuild: 0.25.10 2367 | fix-dts-default-cjs-exports: 1.0.1 2368 | joycon: 3.1.1 2369 | picocolors: 1.1.1 2370 | postcss-load-config: 6.0.1(postcss@8.5.6)(tsx@4.20.6)(yaml@2.5.1) 2371 | resolve-from: 5.0.0 2372 | rollup: 4.52.3 2373 | source-map: 0.8.0-beta.0 2374 | sucrase: 3.35.0 2375 | tinyexec: 0.3.2 2376 | tinyglobby: 0.2.15 2377 | tree-kill: 1.2.2 2378 | optionalDependencies: 2379 | postcss: 8.5.6 2380 | typescript: 5.9.2 2381 | transitivePeerDependencies: 2382 | - jiti 2383 | - supports-color 2384 | - tsx 2385 | - yaml 2386 | 2387 | tsx@4.20.6: 2388 | dependencies: 2389 | esbuild: 0.25.10 2390 | get-tsconfig: 4.10.1 2391 | optionalDependencies: 2392 | fsevents: 2.3.3 2393 | 2394 | typescript@5.9.2: {} 2395 | 2396 | ufo@1.6.1: {} 2397 | 2398 | undici-types@6.21.0: {} 2399 | 2400 | vite-node@3.2.4(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1): 2401 | dependencies: 2402 | cac: 6.7.14 2403 | debug: 4.4.3 2404 | es-module-lexer: 1.7.0 2405 | pathe: 2.0.3 2406 | vite: 7.1.7(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1) 2407 | transitivePeerDependencies: 2408 | - '@types/node' 2409 | - jiti 2410 | - less 2411 | - lightningcss 2412 | - sass 2413 | - sass-embedded 2414 | - stylus 2415 | - sugarss 2416 | - supports-color 2417 | - terser 2418 | - tsx 2419 | - yaml 2420 | 2421 | vite@7.1.7(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1): 2422 | dependencies: 2423 | esbuild: 0.25.10 2424 | fdir: 6.5.0(picomatch@4.0.3) 2425 | picomatch: 4.0.3 2426 | postcss: 8.5.6 2427 | rollup: 4.52.3 2428 | tinyglobby: 0.2.15 2429 | optionalDependencies: 2430 | '@types/node': 22.18.6 2431 | fsevents: 2.3.3 2432 | tsx: 4.20.6 2433 | yaml: 2.5.1 2434 | 2435 | vitest@3.2.4(@types/node@22.18.6)(@vitest/ui@3.2.4)(jsdom@25.0.1)(tsx@4.20.6)(yaml@2.5.1): 2436 | dependencies: 2437 | '@types/chai': 5.2.2 2438 | '@vitest/expect': 3.2.4 2439 | '@vitest/mocker': 3.2.4(vite@7.1.7(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1)) 2440 | '@vitest/pretty-format': 3.2.4 2441 | '@vitest/runner': 3.2.4 2442 | '@vitest/snapshot': 3.2.4 2443 | '@vitest/spy': 3.2.4 2444 | '@vitest/utils': 3.2.4 2445 | chai: 5.3.3 2446 | debug: 4.4.3 2447 | expect-type: 1.2.2 2448 | magic-string: 0.30.19 2449 | pathe: 2.0.3 2450 | picomatch: 4.0.3 2451 | std-env: 3.9.0 2452 | tinybench: 2.9.0 2453 | tinyexec: 0.3.2 2454 | tinyglobby: 0.2.15 2455 | tinypool: 1.1.1 2456 | tinyrainbow: 2.0.0 2457 | vite: 7.1.7(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1) 2458 | vite-node: 3.2.4(@types/node@22.18.6)(tsx@4.20.6)(yaml@2.5.1) 2459 | why-is-node-running: 2.3.0 2460 | optionalDependencies: 2461 | '@types/node': 22.18.6 2462 | '@vitest/ui': 3.2.4(vitest@3.2.4) 2463 | jsdom: 25.0.1 2464 | transitivePeerDependencies: 2465 | - jiti 2466 | - less 2467 | - lightningcss 2468 | - msw 2469 | - sass 2470 | - sass-embedded 2471 | - stylus 2472 | - sugarss 2473 | - supports-color 2474 | - terser 2475 | - tsx 2476 | - yaml 2477 | 2478 | w3c-xmlserializer@5.0.0: 2479 | dependencies: 2480 | xml-name-validator: 5.0.0 2481 | optional: true 2482 | 2483 | webidl-conversions@4.0.2: {} 2484 | 2485 | webidl-conversions@7.0.0: 2486 | optional: true 2487 | 2488 | whatwg-encoding@3.1.1: 2489 | dependencies: 2490 | iconv-lite: 0.6.3 2491 | optional: true 2492 | 2493 | whatwg-mimetype@4.0.0: 2494 | optional: true 2495 | 2496 | whatwg-url@14.2.0: 2497 | dependencies: 2498 | tr46: 5.1.1 2499 | webidl-conversions: 7.0.0 2500 | optional: true 2501 | 2502 | whatwg-url@7.1.0: 2503 | dependencies: 2504 | lodash.sortby: 4.7.0 2505 | tr46: 1.0.1 2506 | webidl-conversions: 4.0.2 2507 | 2508 | which@2.0.2: 2509 | dependencies: 2510 | isexe: 2.0.0 2511 | 2512 | why-is-node-running@2.3.0: 2513 | dependencies: 2514 | siginfo: 2.0.0 2515 | stackback: 0.0.2 2516 | 2517 | wrap-ansi@7.0.0: 2518 | dependencies: 2519 | ansi-styles: 4.3.0 2520 | string-width: 4.2.3 2521 | strip-ansi: 6.0.1 2522 | 2523 | wrap-ansi@8.1.0: 2524 | dependencies: 2525 | ansi-styles: 6.2.3 2526 | string-width: 5.1.2 2527 | strip-ansi: 7.1.2 2528 | 2529 | ws@8.18.3: 2530 | optional: true 2531 | 2532 | xml-name-validator@5.0.0: 2533 | optional: true 2534 | 2535 | xmlchars@2.2.0: 2536 | optional: true 2537 | 2538 | yaml@2.5.1: 2539 | optional: true 2540 | 2541 | zod-openapi@5.4.2(zod@4.1.11): 2542 | dependencies: 2543 | zod: 4.1.11 2544 | 2545 | zod@4.1.11: {} 2546 | --------------------------------------------------------------------------------