├── .eslintrc.js ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.ts ├── bun.lock ├── example ├── index.ts ├── index2.ts ├── index3.ts └── plugin.ts ├── package.json ├── src ├── index.ts ├── scalar │ └── index.ts ├── swagger │ ├── index.ts │ └── types.ts ├── types.ts └── utils.ts ├── test ├── index.test.ts ├── node │ ├── .gitignore │ ├── cjs │ │ ├── index.js │ │ └── package.json │ └── esm │ │ ├── index.js │ │ └── package.json └── validate-schema.test.ts ├── tsconfig.dts.json └── tsconfig.json /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "es2021": true, 4 | "node": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended" 9 | ], 10 | "parser": "@typescript-eslint/parser", 11 | "parserOptions": { 12 | "ecmaVersion": "latest", 13 | "sourceType": "module" 14 | }, 15 | "plugins": [ 16 | "@typescript-eslint" 17 | ], 18 | "rules": { 19 | "@typescript-eslint/ban-types": 'off', 20 | '@typescript-eslint/no-explicit-any': 'off' 21 | }, 22 | "ignorePatterns": ["example/*", "tests/**/*"] 23 | } 24 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: 'npm' 4 | directory: './' 5 | schedule: 6 | interval: 'daily' 7 | 8 | - package-ecosystem: 'github-actions' 9 | directory: './' 10 | schedule: 11 | interval: 'daily' 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Code CI 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | build: 9 | name: Build and test code 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | 16 | - name: Setup bun 17 | uses: oven-sh/setup-bun@v1 18 | with: 19 | bun-version: latest 20 | 21 | - name: Install packages 22 | run: bun install 23 | 24 | - name: Build code 25 | run: bun run build 26 | 27 | - name: Test 28 | run: bun run test 29 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | defaults: 8 | run: 9 | shell: bash 10 | 11 | permissions: 12 | id-token: write 13 | 14 | env: 15 | # Enable debug logging for actions 16 | ACTIONS_RUNNER_DEBUG: true 17 | 18 | jobs: 19 | publish-npm: 20 | name: 'Publish: npm Registry' 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: 'Checkout' 24 | uses: actions/checkout@v4 25 | 26 | - name: 'Setup Bun' 27 | uses: oven-sh/setup-bun@v1 28 | with: 29 | bun-version: latest 30 | registry-url: "https://registry.npmjs.org" 31 | 32 | - uses: actions/setup-node@v4 33 | with: 34 | node-version: '20.x' 35 | registry-url: 'https://registry.npmjs.org' 36 | 37 | - name: Install packages 38 | run: bun install 39 | 40 | - name: Build code 41 | run: bun run build 42 | 43 | - name: Test 44 | run: bun run test 45 | 46 | - name: 'Publish' 47 | env: 48 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 49 | run: | 50 | npm publish --provenance --access=public 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules 4 | .pnpm-debug.log 5 | dist 6 | 7 | build -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .gitignore 4 | .prettierrc 5 | .cjs.swcrc 6 | .es.swcrc 7 | bun.lockb 8 | 9 | node_modules 10 | tsconfig.json 11 | pnpm-lock.yaml 12 | jest.config.js 13 | nodemon.json 14 | 15 | example 16 | src 17 | tests 18 | test 19 | CHANGELOG.md 20 | .eslintrc.js 21 | tsconfig.cjs.json 22 | tsconfig.esm.json 23 | tsconfig.dts.json 24 | 25 | src 26 | build.ts 27 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "tabWidth": 4, 4 | "semi": false, 5 | "singleQuote": true, 6 | "trailingComma": "none" 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.3.0-exp.1 - 1 May 2025 2 | Improvement: 3 | - use static response for documentation page 4 | - plugin is no longer async 5 | - model should be synced globally 6 | - use `parse` instead of `type` to determine content type 7 | 8 | # 1.3.0-exp.0 - 23 Apr 2025 9 | Change: 10 | - Add support for Elysia 1.3 11 | 12 | # 1.2.2 - 22 Feb 2024 13 | Bug fix: 14 | - [#185](https://github.com/elysiajs/elysia-swagger/pull/185) Fix path issue in Scalar config 15 | 16 | # 1.2.1 - 19 Feb 2024 17 | Bug fix: 18 | - [#154](https://github.com/elysiajs/elysia-swagger/pull/154) prevent failed to fetch spec from URL error 19 | - [elysia#1063](https://github.com/elysiajs/elysia/issues/1063) Using t.Ref as response schema results in invalid OpenAPI specification 20 | - handle unfold recursive Ref to schema 21 | 22 | # 1.2.0-rc.0 - 23 Dec 2024 23 | Change: 24 | - Add support for Elysia 1.2 25 | 26 | # 1.1.6 - 17 Nov 2024 27 | Bug fix: 28 | - [#156](https://github.com/elysiajs/elysia-swagger/pull/156) add type check in cloneHook 29 | 30 | # 1.1.4 - 9 Oct 2024 31 | Bug fix: 32 | - Fix duplicate object reference 33 | 34 | # 1.1.2 - 5 Sep 2024 35 | Feature: 36 | - add provenance publish 37 | 38 | # 1.1.1 - 12 Aug 2024 39 | Feature: 40 | - add hide flag 41 | 42 | # 1.1.0 - 16 Jul 2024 43 | Change: 44 | - Add support for Elysia 1.1 45 | 46 | 47 | # 1.1.0-rc.0 - 12 Jul 2024 48 | Change: 49 | - Add support for Elysia 1.1 50 | 51 | 52 | # 1.0.2 - 18 Mar 2024 53 | Change: 54 | - Add support for Elysia 1.0 55 | 56 | 57 | # 1.0.0 - 16 Mar 2024 58 | Change: 59 | - Add support for Elysia 1.0 60 | 61 | 62 | # 1.0.0-rc.0 - 1 Mar 2024 63 | Change: 64 | - Add support for Elysia 1.0 65 | 66 | 67 | # 1.0.0-beta.1 - 17 Feb 2024 68 | Change: 69 | - Add support for Elysia 1.0 70 | 71 | 72 | # 1.0.0-beta.0 - 6 Feb 2024 73 | Change: 74 | - Add support for Elysia 1.0 75 | 76 | # 0.8.5 - 24 Jan 2024 77 | Bug fix: 78 | - [#39](https://github.com/elysiajs/elysia-swagger/issues/39) Array type does not work 79 | 80 | # 0.8.4 - 24 Jan 2024 81 | Feature: 82 | - [#96](https://github.com/elysiajs/elysia-swagger/pull/96) move to scalar configuration prop 83 | - [#95](https://github.com/elysiajs/elysia-swagger/pulls?q=is%3Apr+is%3Aclosed) Scalar CDN option 84 | - [#92](https://github.com/elysiajs/elysia-swagger/pull/92) update scalar to 1.13.0 and using latest instead of hardcoded version 85 | 86 | # 0.8.3 - 8 Jan 2024 87 | Bug fix: 88 | - Using local Scalar API reference instead of leftover one (oppsie 👉👈) 89 | 90 | # 0.8.2 - 8 Jan 2024 91 | Improvement: 92 | - Extract type inference to reduce bundle-size 93 | 94 | # 0.8.1 - 7 Jan 2024 95 | Change: 96 | - Using Scalar provider as new default 97 | 98 | # 0.8.0-rc.0 - 15 Dec 2023 99 | Change: 100 | - Add support for Elysia 0.8 101 | 102 | # 0.7.5 103 | Improvement: 104 | - #[59](https://github.com/elysiajs/elysia-swagger/pull/59) use relative path to swagger json #59 105 | 106 | # 0.7.4 - 27 Oct 2023 107 | Improvement: 108 | - [#24](https://github.com/elysiajs/elysia-swagger/pull/24) - adding schema validity test 109 | 110 | Change: 111 | - [#48](https://github.com/elysiajs/elysia-swagger/pull/48) update Swagger UI to 4.9.0 112 | - [#36](https://github.com/elysiajs/elysia-swagger/pull/36 ) point to generated .d.ts instead of raw .ts 113 | 114 | Bug fix: 115 | - [#41](https://github.com/elysiajs/elysia-swagger/pull/41) parameters mapping, fix 116 | - [#43](https://github.com/elysiajs/elysia-swagger/pull/43) typo in default documentation 117 | 118 | # 0.7.3 - 26 Sep 2023 119 | Feature: 120 | - [#19](https://github.com/elysiajs/elysia-swagger/pull/19) feat: handle nullish response types 121 | - [#18](https://github.com/elysiajs/elysia-swagger/pull/18) swagger ui options 122 | 123 | 124 | Improvement: 125 | - [#23](https://github.com/elysiajs/elysia-swagger/pull/23) Add github action to run bun test 126 | - remove `removeComment` from tsconfig to show JSDoc 127 | - add `theme` to customize Swagger CSS link 128 | - add `autoDarkMode` using poor man Swagger dark mode CSS 😭 129 | 130 | Change: 131 | - Set default swagger version to 5.7.2 132 | 133 | Bug fix: 134 | - [#16](https://github.com/elysiajs/elysia-swagger/pull/16) fix: use global prefix 135 | 136 | # 0.7.2 - 21 Sep 2023 137 | Bug fix: 138 | - Paths is undefined 139 | - Models is not showing 140 | 141 | # 0.7.1 - 20 Sep 2023 142 | Bug fix: 143 | - Add openapi-types as dependencies 144 | - Fix `any` returned type 145 | 146 | # 0.7.0 - 20 Sep 2023 147 | - Add support for Elysia 0. 148 | 149 | # 0.7.0-beta.0 - 18 Sep 2023 150 | - Add support for Elysia 0.7 151 | 152 | # 0.6.2 - 11 Sep 2023 153 | - Ship lodash.cloneDeep type 154 | 155 | # 0.6.1 - 17 Aug 2023 156 | - Add support for user provided components 157 | 158 | # 0.6.0 - 6 Aug 2023 159 | - Add support for Elysia 0.6 160 | 161 | # 0.6.0-rc.0 - 6 Aug 2023 162 | - Add support for Elysia 0.6 163 | # 0.5.0 - 15 May 2023 164 | - Add support for Elysia 0.5 165 | - Add CommonJS support 166 | 167 | # 0.3.0 - 17 Mar 2023 168 | Improvement: 169 | - Add support for Elysia 0.3.0 170 | 171 | # 0.3.0-rc.0 - 7 Mar 2023 172 | Improvement: 173 | - Add support for Elysia 0.3.0-rc.0 174 | 175 | # 0.3.0-beta.0 - 25 Feb 2023 176 | Improvement: 177 | - Support Elysia >= 0.3.0-beta.0 178 | 179 | Breaking Change: 180 | - Update from OpenAPI 2.x to OpenAPI 3.0.3 181 | - `swagger.swagger` is renamed to `swagger.documentation` 182 | 183 | # 0.1.1 - 8 Jan 2023 184 | Bug fix: 185 | - Infers path type 186 | 187 | # 0.1.0-rc.3 - 13 Dec 2022 188 | Improvement: 189 | - Add support for Elysia 0.1.0-rc.5 190 | 191 | # 0.1.0-rc.2 - 9 Dec 2022 192 | Improvement: 193 | - Support for Elysia 0.1.0-rc.1 onward 194 | 195 | Fix: 196 | - Add main fields Bundlephobia 197 | 198 | # 0.1.0-rc.1 - 6 Dec 2022 199 | Improvement: 200 | - Support for Elysia 0.1.0-rc.1 onward 201 | 202 | # 0.0.0-experimental.3 - 29 Nov 2022 203 | Change: 204 | - Support for KingWorld 0.0.0-experimental.51 205 | 206 | # 0.0.0-experimental.2 - 22 Nov 2022 207 | Change: 208 | - Support for KingWorld 0.0.0-experimental.51 209 | 210 | # 0.0.0-experimental.1 - 12 Nov 2022 211 | Improvement: 212 | - Auto infers path params if schema is presented 213 | - Auto infers path params now merge with schema.params 214 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 saltyAom 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @elysiajs/swagger 2 | Plugin for [elysia](https://github.com/elysiajs/elysia) to auto-generate Swagger page. 3 | 4 | ## Installation 5 | ```bash 6 | bun add @elysiajs/swagger 7 | ``` 8 | 9 | ## Example 10 | ```typescript 11 | import { Elysia, t } from 'elysia' 12 | import { swagger } from '@elysiajs/swagger' 13 | 14 | const app = new Elysia() 15 | .use(swagger()) 16 | .get('/', () => 'hi', { response: t.String({ description: 'sample description' }) }) 17 | .post( 18 | '/json/:id', 19 | ({ body, params: { id }, query: { name } }) => ({ 20 | ...body, 21 | id, 22 | name 23 | }), 24 | { 25 | params: t.Object({ 26 | id: t.String() 27 | }), 28 | query: t.Object({ 29 | name: t.String() 30 | }), 31 | body: t.Object({ 32 | username: t.String(), 33 | password: t.String() 34 | }), 35 | response: t.Object({ 36 | username: t.String(), 37 | password: t.String(), 38 | id: t.String(), 39 | name: t.String() 40 | }, { description: 'sample description' }) 41 | } 42 | ) 43 | .listen(8080); 44 | ``` 45 | 46 | Then go to `http://localhost:8080/swagger`. 47 | 48 | # config 49 | 50 | ## provider 51 | @default 'scalar' 52 | Choose between [Scalar](https://github.com/scalar/scalar) & [SwaggerUI](https://github.com/swagger-api/swagger-ui) 53 | 54 | ## scalar 55 | Customize scalarConfig, refers to [Scalar config](https://github.com/scalar/scalar/blob/main/documentation/configuration.md) 56 | 57 | ## swagger 58 | Customize Swagger config, refers to [Swagger 3.0.3 config](https://swagger.io/specification/v3) 59 | 60 | ## path 61 | @default '/swagger' 62 | 63 | The endpoint to expose Swagger 64 | 65 | ## excludeStaticFile 66 | @default true 67 | 68 | Determine if Swagger should exclude static files. 69 | 70 | ## exclude 71 | @default [] 72 | 73 | Paths to exclude from the Swagger endpoint 74 | -------------------------------------------------------------------------------- /build.ts: -------------------------------------------------------------------------------- 1 | import { $ } from 'bun' 2 | import { build, type Options } from 'tsup' 3 | 4 | await $`rm -rf dist` 5 | 6 | const tsupConfig: Options = { 7 | entry: ['src/**/*.ts'], 8 | splitting: false, 9 | sourcemap: false, 10 | clean: true, 11 | bundle: true 12 | } satisfies Options 13 | 14 | await Promise.all([ 15 | // ? tsup esm 16 | build({ 17 | outDir: 'dist', 18 | format: 'esm', 19 | target: 'node20', 20 | cjsInterop: false, 21 | ...tsupConfig 22 | }), 23 | // ? tsup cjs 24 | build({ 25 | outDir: 'dist/cjs', 26 | format: 'cjs', 27 | target: 'node20', 28 | // dts: true, 29 | ...tsupConfig 30 | }) 31 | ]) 32 | 33 | await $`tsc --project tsconfig.dts.json` 34 | 35 | await Promise.all([$`cp dist/*.d.ts dist/cjs`]) 36 | 37 | process.exit() 38 | -------------------------------------------------------------------------------- /bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "@elysiajs/swagger", 6 | "dependencies": { 7 | "@scalar/themes": "^0.9.52", 8 | "@scalar/types": "^0.0.12", 9 | "openapi-types": "^12.1.3", 10 | "pathe": "^1.1.2", 11 | }, 12 | "devDependencies": { 13 | "@apidevtools/swagger-parser": "^10.1.0", 14 | "@types/bun": "1.1.14", 15 | "elysia": "1.3.0-exp.71", 16 | "eslint": "9.6.0", 17 | "tsup": "^8.1.0", 18 | "typescript": "^5.5.3", 19 | }, 20 | "peerDependencies": { 21 | "elysia": ">= 1.3.0", 22 | }, 23 | }, 24 | }, 25 | "packages": { 26 | "@apidevtools/json-schema-ref-parser": ["@apidevtools/json-schema-ref-parser@11.7.2", "", { "dependencies": { "@jsdevtools/ono": "^7.1.3", "@types/json-schema": "^7.0.15", "js-yaml": "^4.1.0" } }, "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA=="], 27 | 28 | "@apidevtools/openapi-schemas": ["@apidevtools/openapi-schemas@2.1.0", "", {}, "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ=="], 29 | 30 | "@apidevtools/swagger-methods": ["@apidevtools/swagger-methods@3.0.2", "", {}, "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg=="], 31 | 32 | "@apidevtools/swagger-parser": ["@apidevtools/swagger-parser@10.1.1", "", { "dependencies": { "@apidevtools/json-schema-ref-parser": "11.7.2", "@apidevtools/openapi-schemas": "^2.1.0", "@apidevtools/swagger-methods": "^3.0.2", "@jsdevtools/ono": "^7.1.3", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "call-me-maybe": "^1.0.2" }, "peerDependencies": { "openapi-types": ">=7" } }, "sha512-u/kozRnsPO/x8QtKYJOqoGtC4kH6yg1lfYkB9Au0WhYB0FNLpyFusttQtvhlwjtG3rOwiRz4D8DnnXa8iEpIKA=="], 33 | 34 | "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ=="], 35 | 36 | "@esbuild/android-arm": ["@esbuild/android-arm@0.25.3", "", { "os": "android", "cpu": "arm" }, "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A=="], 37 | 38 | "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.3", "", { "os": "android", "cpu": "arm64" }, "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ=="], 39 | 40 | "@esbuild/android-x64": ["@esbuild/android-x64@0.25.3", "", { "os": "android", "cpu": "x64" }, "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ=="], 41 | 42 | "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w=="], 43 | 44 | "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A=="], 45 | 46 | "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw=="], 47 | 48 | "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q=="], 49 | 50 | "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.3", "", { "os": "linux", "cpu": "arm" }, "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ=="], 51 | 52 | "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A=="], 53 | 54 | "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw=="], 55 | 56 | "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g=="], 57 | 58 | "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag=="], 59 | 60 | "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg=="], 61 | 62 | "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA=="], 63 | 64 | "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ=="], 65 | 66 | "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.3", "", { "os": "linux", "cpu": "x64" }, "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA=="], 67 | 68 | "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.3", "", { "os": "none", "cpu": "arm64" }, "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA=="], 69 | 70 | "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.3", "", { "os": "none", "cpu": "x64" }, "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g=="], 71 | 72 | "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ=="], 73 | 74 | "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w=="], 75 | 76 | "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA=="], 77 | 78 | "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ=="], 79 | 80 | "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew=="], 81 | 82 | "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.3", "", { "os": "win32", "cpu": "x64" }, "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg=="], 83 | 84 | "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.6.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-KTsJMmobmbrFLe3LDh0PC2FXpcSYJt/MLjlkh/9LEnmKYLSYmT/0EW9JWANjeoemiuZrmogti0tW5Ch+qNUYDw=="], 85 | 86 | "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], 87 | 88 | "@eslint/config-array": ["@eslint/config-array@0.17.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-BlYOpej8AQ8Ev9xVqroV7a02JK3SkBAaN9GfMMH9W6Ch8FlQlkjGw4Ir7+FgYwfirivAf4t+GtzuAxqfukmISA=="], 89 | 90 | "@eslint/eslintrc": ["@eslint/eslintrc@3.3.1", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ=="], 91 | 92 | "@eslint/js": ["@eslint/js@9.6.0", "", {}, "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A=="], 93 | 94 | "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], 95 | 96 | "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], 97 | 98 | "@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], 99 | 100 | "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], 101 | 102 | "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.8", "", { "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA=="], 103 | 104 | "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 105 | 106 | "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], 107 | 108 | "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], 109 | 110 | "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="], 111 | 112 | "@jsdevtools/ono": ["@jsdevtools/ono@7.1.3", "", {}, "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg=="], 113 | 114 | "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], 115 | 116 | "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], 117 | 118 | "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], 119 | 120 | "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], 121 | 122 | "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.40.1", "", { "os": "android", "cpu": "arm" }, "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw=="], 123 | 124 | "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.40.1", "", { "os": "android", "cpu": "arm64" }, "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw=="], 125 | 126 | "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.40.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA=="], 127 | 128 | "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.40.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw=="], 129 | 130 | "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.40.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw=="], 131 | 132 | "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.40.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q=="], 133 | 134 | "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.40.1", "", { "os": "linux", "cpu": "arm" }, "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg=="], 135 | 136 | "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.40.1", "", { "os": "linux", "cpu": "arm" }, "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg=="], 137 | 138 | "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.40.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg=="], 139 | 140 | "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.40.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ=="], 141 | 142 | "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.40.1", "", { "os": "linux", "cpu": "none" }, "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ=="], 143 | 144 | "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.40.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg=="], 145 | 146 | "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.40.1", "", { "os": "linux", "cpu": "none" }, "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ=="], 147 | 148 | "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.40.1", "", { "os": "linux", "cpu": "none" }, "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA=="], 149 | 150 | "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.40.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg=="], 151 | 152 | "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.40.1", "", { "os": "linux", "cpu": "x64" }, "sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ=="], 153 | 154 | "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.40.1", "", { "os": "linux", "cpu": "x64" }, "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ=="], 155 | 156 | "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.40.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg=="], 157 | 158 | "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.40.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA=="], 159 | 160 | "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.40.1", "", { "os": "win32", "cpu": "x64" }, "sha512-ECyOuDeH3C1I8jH2MK1RtBJW+YPMvSfT0a5NN0nHfQYnDSJ6tUiZH3gzwVP5/Kfh/+Tt7tpWVF9LXNTnhTJ3kA=="], 161 | 162 | "@scalar/openapi-types": ["@scalar/openapi-types@0.1.1", "", {}, "sha512-NMy3QNk6ytcCoPUGJH0t4NNr36OWXgZhA3ormr3TvhX1NDgoF95wFyodGVH8xiHeUyn2/FxtETm8UBLbB5xEmg=="], 163 | 164 | "@scalar/themes": ["@scalar/themes@0.9.86", "", { "dependencies": { "@scalar/types": "0.1.7" } }, "sha512-QUHo9g5oSWi+0Lm1vJY9TaMZRau8LHg+vte7q5BVTBnu6NuQfigCaN+ouQ73FqIVd96TwMO6Db+dilK1B+9row=="], 165 | 166 | "@scalar/types": ["@scalar/types@0.0.12", "", { "dependencies": { "@scalar/openapi-types": "0.1.1", "@unhead/schema": "^1.9.5" } }, "sha512-XYZ36lSEx87i4gDqopQlGCOkdIITHHEvgkuJFrXFATQs9zHARop0PN0g4RZYWj+ZpCUclOcaOjbCt8JGe22mnQ=="], 167 | 168 | "@sinclair/typebox": ["@sinclair/typebox@0.34.33", "", {}, "sha512-5HAV9exOMcXRUxo+9iYB5n09XxzCXnfy4VTNW4xnDv+FgjzAGY989C28BIdljKqmF+ZltUwujE3aossvcVtq6g=="], 169 | 170 | "@types/bun": ["@types/bun@1.1.14", "", { "dependencies": { "bun-types": "1.1.37" } }, "sha512-opVYiFGtO2af0dnWBdZWlioLBoxSdDO5qokaazLhq8XQtGZbY4pY3/JxY8Zdf/hEwGubbp7ErZXoN1+h2yesxA=="], 171 | 172 | "@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="], 173 | 174 | "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], 175 | 176 | "@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="], 177 | 178 | "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], 179 | 180 | "@unhead/schema": ["@unhead/schema@1.11.20", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA=="], 181 | 182 | "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], 183 | 184 | "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], 185 | 186 | "ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="], 187 | 188 | "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], 189 | 190 | "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 191 | 192 | "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 193 | 194 | "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], 195 | 196 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], 197 | 198 | "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], 199 | 200 | "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], 201 | 202 | "bun-types": ["bun-types@1.1.37", "", { "dependencies": { "@types/node": "~20.12.8", "@types/ws": "~8.5.10" } }, "sha512-C65lv6eBr3LPJWFZ2gswyrGZ82ljnH8flVE03xeXxKhi2ZGtFiO4isRKTKnitbSqtRAcaqYSR6djt1whI66AbA=="], 203 | 204 | "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="], 205 | 206 | "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], 207 | 208 | "call-me-maybe": ["call-me-maybe@1.0.2", "", {}, "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ=="], 209 | 210 | "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], 211 | 212 | "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 213 | 214 | "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], 215 | 216 | "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 217 | 218 | "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 219 | 220 | "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], 221 | 222 | "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], 223 | 224 | "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], 225 | 226 | "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], 227 | 228 | "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], 229 | 230 | "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], 231 | 232 | "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], 233 | 234 | "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], 235 | 236 | "elysia": ["elysia@1.3.0-exp.71", "", { "dependencies": { "@sinclair/typebox": "^0.34.33", "cookie": "^1.0.2", "exact-mirror": "0.1.1", "fast-decode-uri-component": "^1.0.1", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["file-type", "typescript"] }, "sha512-jL7z5OzJgs8pCzEXRmzzYu972S9hILiab7bVD3VBJHAE/9EMdG5uzxWA++3rxJXPEW7HvK3E31zaJKv6TtKgqA=="], 237 | 238 | "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], 239 | 240 | "esbuild": ["esbuild@0.25.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.3", "@esbuild/android-arm": "0.25.3", "@esbuild/android-arm64": "0.25.3", "@esbuild/android-x64": "0.25.3", "@esbuild/darwin-arm64": "0.25.3", "@esbuild/darwin-x64": "0.25.3", "@esbuild/freebsd-arm64": "0.25.3", "@esbuild/freebsd-x64": "0.25.3", "@esbuild/linux-arm": "0.25.3", "@esbuild/linux-arm64": "0.25.3", "@esbuild/linux-ia32": "0.25.3", "@esbuild/linux-loong64": "0.25.3", "@esbuild/linux-mips64el": "0.25.3", "@esbuild/linux-ppc64": "0.25.3", "@esbuild/linux-riscv64": "0.25.3", "@esbuild/linux-s390x": "0.25.3", "@esbuild/linux-x64": "0.25.3", "@esbuild/netbsd-arm64": "0.25.3", "@esbuild/netbsd-x64": "0.25.3", "@esbuild/openbsd-arm64": "0.25.3", "@esbuild/openbsd-x64": "0.25.3", "@esbuild/sunos-x64": "0.25.3", "@esbuild/win32-arm64": "0.25.3", "@esbuild/win32-ia32": "0.25.3", "@esbuild/win32-x64": "0.25.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q=="], 241 | 242 | "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], 243 | 244 | "eslint": ["eslint@9.6.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/config-array": "^0.17.0", "@eslint/eslintrc": "^3.1.0", "@eslint/js": "9.6.0", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.0.1", "eslint-visitor-keys": "^4.0.0", "espree": "^10.1.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-ElQkdLMEEqQNM9Njff+2Y4q2afHk7JpkPvrd7Xh7xefwgQynqPxwf55J7di9+MEibWUGdNjFF9ITG9Pck5M84w=="], 245 | 246 | "eslint-scope": ["eslint-scope@8.3.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ=="], 247 | 248 | "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], 249 | 250 | "espree": ["espree@10.3.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.0" } }, "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg=="], 251 | 252 | "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], 253 | 254 | "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], 255 | 256 | "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], 257 | 258 | "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], 259 | 260 | "exact-mirror": ["exact-mirror@0.1.1", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-jygrs/z9JT3UBDVPsu4vLy8gqtTLTxVzoxLmDzkVXHizRGixDMdkdLF98ChZxsqHL0F7IcpTf8GUFRqa2qt3uw=="], 261 | 262 | "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], 263 | 264 | "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], 265 | 266 | "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], 267 | 268 | "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], 269 | 270 | "fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="], 271 | 272 | "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], 273 | 274 | "fdir": ["fdir@6.4.4", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg=="], 275 | 276 | "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], 277 | 278 | "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], 279 | 280 | "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], 281 | 282 | "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], 283 | 284 | "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], 285 | 286 | "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 287 | 288 | "glob": ["glob@10.4.5", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg=="], 289 | 290 | "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], 291 | 292 | "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], 293 | 294 | "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], 295 | 296 | "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], 297 | 298 | "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], 299 | 300 | "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], 301 | 302 | "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], 303 | 304 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 305 | 306 | "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], 307 | 308 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 309 | 310 | "is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="], 311 | 312 | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 313 | 314 | "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], 315 | 316 | "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], 317 | 318 | "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], 319 | 320 | "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], 321 | 322 | "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 323 | 324 | "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], 325 | 326 | "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], 327 | 328 | "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], 329 | 330 | "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], 331 | 332 | "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], 333 | 334 | "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="], 335 | 336 | "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], 337 | 338 | "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], 339 | 340 | "lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="], 341 | 342 | "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], 343 | 344 | "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], 345 | 346 | "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], 347 | 348 | "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 349 | 350 | "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], 351 | 352 | "nanoid": ["nanoid@5.1.5", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw=="], 353 | 354 | "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], 355 | 356 | "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], 357 | 358 | "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], 359 | 360 | "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], 361 | 362 | "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], 363 | 364 | "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], 365 | 366 | "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], 367 | 368 | "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], 369 | 370 | "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], 371 | 372 | "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], 373 | 374 | "path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], 375 | 376 | "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], 377 | 378 | "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 379 | 380 | "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], 381 | 382 | "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], 383 | 384 | "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], 385 | 386 | "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], 387 | 388 | "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], 389 | 390 | "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], 391 | 392 | "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], 393 | 394 | "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], 395 | 396 | "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], 397 | 398 | "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], 399 | 400 | "rollup": ["rollup@4.40.1", "", { "dependencies": { "@types/estree": "1.0.7" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.1", "@rollup/rollup-android-arm64": "4.40.1", "@rollup/rollup-darwin-arm64": "4.40.1", "@rollup/rollup-darwin-x64": "4.40.1", "@rollup/rollup-freebsd-arm64": "4.40.1", "@rollup/rollup-freebsd-x64": "4.40.1", "@rollup/rollup-linux-arm-gnueabihf": "4.40.1", "@rollup/rollup-linux-arm-musleabihf": "4.40.1", "@rollup/rollup-linux-arm64-gnu": "4.40.1", "@rollup/rollup-linux-arm64-musl": "4.40.1", "@rollup/rollup-linux-loongarch64-gnu": "4.40.1", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.1", "@rollup/rollup-linux-riscv64-gnu": "4.40.1", "@rollup/rollup-linux-riscv64-musl": "4.40.1", "@rollup/rollup-linux-s390x-gnu": "4.40.1", "@rollup/rollup-linux-x64-gnu": "4.40.1", "@rollup/rollup-linux-x64-musl": "4.40.1", "@rollup/rollup-win32-arm64-msvc": "4.40.1", "@rollup/rollup-win32-ia32-msvc": "4.40.1", "@rollup/rollup-win32-x64-msvc": "4.40.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-C5VvvgCCyfyotVITIAv+4efVytl5F7wt+/I2i9q9GZcEXW9BP52YYOXC58igUi+LFZVHukErIIqQSWwv/M3WRw=="], 401 | 402 | "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], 403 | 404 | "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], 405 | 406 | "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], 407 | 408 | "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], 409 | 410 | "source-map": ["source-map@0.8.0-beta.0", "", { "dependencies": { "whatwg-url": "^7.0.0" } }, "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="], 411 | 412 | "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], 413 | 414 | "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], 415 | 416 | "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 417 | 418 | "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 419 | 420 | "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], 421 | 422 | "sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="], 423 | 424 | "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 425 | 426 | "text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], 427 | 428 | "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], 429 | 430 | "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], 431 | 432 | "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], 433 | 434 | "tinyglobby": ["tinyglobby@0.2.13", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw=="], 435 | 436 | "tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="], 437 | 438 | "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], 439 | 440 | "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], 441 | 442 | "tsup": ["tsup@8.4.0", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.25.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "0.8.0-beta.0", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ=="], 443 | 444 | "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], 445 | 446 | "type-fest": ["type-fest@4.40.1", "", {}, "sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA=="], 447 | 448 | "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], 449 | 450 | "undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], 451 | 452 | "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], 453 | 454 | "webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], 455 | 456 | "whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="], 457 | 458 | "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], 459 | 460 | "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], 461 | 462 | "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], 463 | 464 | "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], 465 | 466 | "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], 467 | 468 | "zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="], 469 | 470 | "zod": ["zod@3.24.3", "", {}, "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg=="], 471 | 472 | "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 473 | 474 | "@eslint/eslintrc/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], 475 | 476 | "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], 477 | 478 | "@scalar/themes/@scalar/types": ["@scalar/types@0.1.7", "", { "dependencies": { "@scalar/openapi-types": "0.2.0", "@unhead/schema": "^1.11.11", "nanoid": "^5.1.5", "type-fest": "^4.20.0", "zod": "^3.23.8" } }, "sha512-irIDYzTQG2KLvFbuTI8k2Pz/R4JR+zUUSykVTbEMatkzMmVFnn1VzNSMlODbadycwZunbnL2tA27AXed9URVjw=="], 479 | 480 | "eslint/ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], 481 | 482 | "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], 483 | 484 | "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], 485 | 486 | "string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], 487 | 488 | "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 489 | 490 | "wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], 491 | 492 | "wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], 493 | 494 | "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], 495 | 496 | "@eslint/eslintrc/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], 497 | 498 | "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], 499 | 500 | "@scalar/themes/@scalar/types/@scalar/openapi-types": ["@scalar/openapi-types@0.2.0", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-waiKk12cRCqyUCWTOX0K1WEVX46+hVUK+zRPzAahDJ7G0TApvbNkuy5wx7aoUyEk++HHde0XuQnshXnt8jsddA=="], 501 | 502 | "eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], 503 | 504 | "glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], 505 | 506 | "string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], 507 | 508 | "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 509 | 510 | "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], 511 | } 512 | } 513 | -------------------------------------------------------------------------------- /example/index.ts: -------------------------------------------------------------------------------- 1 | import { Elysia, t } from 'elysia' 2 | import { swagger } from '../src/index' 3 | 4 | const schema = t.Object({ 5 | test: t.Literal('hello') 6 | }) 7 | 8 | const app = new Elysia() 9 | .use( 10 | swagger({ 11 | provider: 'scalar', 12 | documentation: { 13 | info: { 14 | title: 'Elysia Scalar', 15 | version: '0.8.1' 16 | }, 17 | tags: [ 18 | { 19 | name: 'Test', 20 | description: 'Hello' 21 | } 22 | ], 23 | components: { 24 | schemas: { 25 | User: { 26 | description: 'string' 27 | } 28 | }, 29 | securitySchemes: { 30 | JwtAuth: { 31 | type: 'http', 32 | scheme: 'bearer', 33 | bearerFormat: 'JWT', 34 | description: 'Enter JWT Bearer token **_only_**' 35 | } 36 | } 37 | } 38 | }, 39 | swaggerOptions: { 40 | persistAuthorization: true 41 | } 42 | }) 43 | ) 44 | .model({ schema }) 45 | .get( 46 | '/', 47 | () => { 48 | return { test: 'hello' as const } 49 | }, 50 | { 51 | response: 'schema' 52 | } 53 | ) 54 | .post('/json', ({ body }) => body, { 55 | parse: 'formdata', 56 | body: 'schema', 57 | response: 'schema' 58 | }) 59 | .listen(3000) 60 | -------------------------------------------------------------------------------- /example/index2.ts: -------------------------------------------------------------------------------- 1 | import { Elysia } from 'elysia' 2 | import { swagger } from '../src/index' 3 | import { plugin } from './plugin' 4 | 5 | const app = new Elysia({ 6 | // aot: false 7 | }) 8 | .use( 9 | swagger({ 10 | documentation: { 11 | info: { 12 | title: 'Elysia', 13 | version: '0.6.10' 14 | }, 15 | tags: [ 16 | { 17 | name: 'Test', 18 | description: 'Hello' 19 | } 20 | ], 21 | security: [ 22 | {JwtAuth: []} 23 | ], 24 | components: { 25 | schemas: { 26 | User: { 27 | description: 'string' 28 | } 29 | }, 30 | securitySchemes: { 31 | JwtAuth: { 32 | type: 'http', 33 | scheme: 'bearer', 34 | bearerFormat: 'JWT', 35 | description: 'Enter JWT Bearer token **_only_**' 36 | } 37 | } 38 | } 39 | }, 40 | swaggerOptions: { 41 | persistAuthorization: true 42 | }, 43 | }) 44 | ) 45 | .use(plugin) 46 | .listen(3000) 47 | -------------------------------------------------------------------------------- /example/index3.ts: -------------------------------------------------------------------------------- 1 | import { Elysia, InternalRoute } from 'elysia' 2 | import { swagger } from '../src/index' 3 | import { plugin } from './plugin' 4 | import { registerSchemaPath } from '../src/utils' 5 | 6 | const app = new Elysia() 7 | .use( 8 | swagger({ 9 | provider: 'scalar', 10 | documentation: { 11 | info: { 12 | title: 'Elysia Scalar', 13 | version: '0.8.1' 14 | }, 15 | tags: [ 16 | { 17 | name: 'Test', 18 | description: 'Hello' 19 | } 20 | ], 21 | paths: { 22 | "/b/": { 23 | get: { 24 | operationId: "getB", 25 | summary: "Ping Pong B", 26 | description: "Lorem Ipsum Dolar", 27 | tags: [ "Test" ], 28 | responses: { 29 | "200": { 30 | description: "test" 31 | }, 32 | }, 33 | }, 34 | }, 35 | }, 36 | components: { 37 | schemas: { 38 | User: { 39 | description: 'string' 40 | } 41 | }, 42 | securitySchemes: { 43 | JwtAuth: { 44 | type: 'http', 45 | scheme: 'bearer', 46 | bearerFormat: 'JWT', 47 | description: 'Enter JWT Bearer token **_only_**' 48 | } 49 | } 50 | } 51 | }, 52 | swaggerOptions: { 53 | persistAuthorization: true 54 | } 55 | }) 56 | ) 57 | .use(plugin) 58 | .listen(3000) 59 | 60 | console.log(app.rsaoutes) 61 | -------------------------------------------------------------------------------- /example/plugin.ts: -------------------------------------------------------------------------------- 1 | import { Elysia, t } from 'elysia' 2 | 3 | export const plugin = new Elysia({ 4 | prefix: '/a' 5 | }) 6 | .model({ 7 | sign: t.Object( 8 | { 9 | username: t.String(), 10 | password: t.String() 11 | }, 12 | { 13 | description: 'Models for handling authentication' 14 | } 15 | ), 16 | number: t.Number() 17 | }) 18 | .get('/', ({ set }) => 'hi', { 19 | detail: { 20 | summary: 'Ping Pong', 21 | description: 'Lorem Ipsum Dolar', 22 | tags: ['Test'] 23 | } 24 | }) 25 | .get('/unpath/:id', ({ params: { id } }) => id, { 26 | params: t.Object({ 27 | id: t.String({ 28 | description: 'Extract value from path parameter' 29 | }) 30 | }), 31 | detail: { 32 | deprecated: true 33 | } 34 | }) 35 | .post('/json', ({ body }) => body, { 36 | type: 'json', 37 | body: 'sign', 38 | response: { 39 | 200: 'sign' 40 | }, 41 | detail: { 42 | summary: 'Using reference model' 43 | } 44 | }) 45 | .post( 46 | '/json/:id', 47 | ({ body, params: { id }, query: { name, email, } }) => ({ 48 | ...body, 49 | id 50 | }), 51 | { 52 | body: 'sign', 53 | params: t.Object({ 54 | id: t.Numeric() 55 | }), 56 | query: t.Object({ 57 | name: t.String(), 58 | email: t.String({ 59 | description: 'sample email description', 60 | format: 'email', 61 | examples: ['test@test.com'] 62 | }), 63 | birthday: t.String({ 64 | description: 'sample birthday description', 65 | pattern: '\\d{4}-\\d{2}-\\d{2}', 66 | minLength: 10, 67 | maxLength: 10, 68 | examples: ['2024-01-01'] 69 | }), 70 | gender: t.Union([t.Literal('M'), t.Literal('F')]) 71 | }), 72 | response: { 73 | 200: t.Object( 74 | { 75 | id: t.Number(), 76 | username: t.String(), 77 | password: t.String() 78 | }, 79 | { 80 | title: 'User', 81 | description: "Contains user's confidential metadata" 82 | } 83 | ), 84 | 418: t.Array( 85 | t.Object({ 86 | error: t.String() 87 | }) 88 | ), 89 | }, 90 | detail: { 91 | summary: 'Complex JSON' 92 | } 93 | } 94 | ) 95 | .post('/file', ({ body: { file } }) => file, { 96 | type: 'formdata', 97 | body: t.Object({ 98 | file: t.File({ 99 | type: ['image/jpeg', 'image/'], 100 | minSize: '1k', 101 | maxSize: '5m' 102 | }) 103 | }), 104 | response: t.File() 105 | }) 106 | // .post('/files', ({ body: { files } }) => files[0], { 107 | // schema: { 108 | // body: t.Object({ 109 | // files: t.Files({ 110 | // type: 'image', 111 | // maxSize: '5m' 112 | // }) 113 | // }), 114 | // response: t.File() 115 | // } 116 | // }) 117 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@elysiajs/swagger", 3 | "version": "1.3.0", 4 | "description": "Plugin for Elysia to auto-generate Swagger page", 5 | "author": { 6 | "name": "saltyAom", 7 | "url": "https://github.com/SaltyAom", 8 | "email": "saltyaom@gmail.com" 9 | }, 10 | "main": "./dist/cjs/index.js", 11 | "module": "./dist/index.mjs", 12 | "types": "./dist/index.d.ts", 13 | "exports": { 14 | "./package.json": "./package.json", 15 | ".": { 16 | "types": "./dist/index.d.ts", 17 | "import": "./dist/index.mjs", 18 | "require": "./dist/cjs/index.js" 19 | }, 20 | "./types": { 21 | "types": "./dist/types.d.ts", 22 | "import": "./dist/types.mjs", 23 | "require": "./dist/cjs/types.js" 24 | }, 25 | "./utils": { 26 | "types": "./dist/utils.d.ts", 27 | "import": "./dist/utils.mjs", 28 | "require": "./dist/cjs/utils.js" 29 | }, 30 | "./scalar": { 31 | "types": "./dist/scalar/index.d.ts", 32 | "import": "./dist/scalar/index.mjs", 33 | "require": "./dist/cjs/scalar/index.js" 34 | }, 35 | "./scalar/theme": { 36 | "types": "./dist/scalar/theme.d.ts", 37 | "import": "./dist/scalar/theme.mjs", 38 | "require": "./dist/cjs/scalar/theme.js" 39 | } 40 | }, 41 | "keywords": [ 42 | "elysia", 43 | "swagger" 44 | ], 45 | "homepage": "https://github.com/elysiajs/elysia-swagger", 46 | "repository": { 47 | "type": "git", 48 | "url": "https://github.com/elysiajs/elysia-swagger" 49 | }, 50 | "bugs": "https://github.com/elysiajs/elysia-swagger/issues", 51 | "license": "MIT", 52 | "scripts": { 53 | "dev": "bun run --watch example/index.ts", 54 | "test": "bun test && npm run test:node", 55 | "test:node": "npm install --prefix ./test/node/cjs/ && npm install --prefix ./test/node/esm/ && node ./test/node/cjs/index.js && node ./test/node/esm/index.js", 56 | "build": "bun build.ts", 57 | "release": "npm run build && npm run test && npm publish --access public" 58 | }, 59 | "peerDependencies": { 60 | "elysia": ">= 1.3.0" 61 | }, 62 | "devDependencies": { 63 | "@apidevtools/swagger-parser": "^10.1.0", 64 | "@types/bun": "1.1.14", 65 | "elysia": "1.3.0-exp.71", 66 | "eslint": "9.6.0", 67 | "tsup": "^8.1.0", 68 | "typescript": "^5.5.3" 69 | }, 70 | "dependencies": { 71 | "@scalar/themes": "^0.9.52", 72 | "@scalar/types": "^0.0.12", 73 | "openapi-types": "^12.1.3", 74 | "pathe": "^1.1.2" 75 | } 76 | } -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 2 | import { Elysia, type InternalRoute } from 'elysia' 3 | 4 | import { SwaggerUIRender } from './swagger' 5 | import { ScalarRender } from './scalar' 6 | 7 | import { filterPaths, registerSchemaPath } from './utils' 8 | 9 | import type { OpenAPIV3 } from 'openapi-types' 10 | import type { ReferenceConfiguration } from '@scalar/types' 11 | import type { ElysiaSwaggerConfig } from './types' 12 | 13 | /** 14 | * Plugin for [elysia](https://github.com/elysiajs/elysia) that auto-generate Swagger page. 15 | * 16 | * @see https://github.com/elysiajs/elysia-swagger 17 | */ 18 | export const swagger = ({ 19 | provider = 'scalar', 20 | scalarVersion = 'latest', 21 | scalarCDN = '', 22 | scalarConfig = {}, 23 | documentation = {}, 24 | version = '5.9.0', 25 | excludeStaticFile = true, 26 | path = '/swagger' as Path, 27 | specPath = `${path}/json`, 28 | exclude = [], 29 | swaggerOptions = {}, 30 | theme = `https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css`, 31 | autoDarkMode = true, 32 | excludeMethods = ['OPTIONS'], 33 | excludeTags = [] 34 | }: ElysiaSwaggerConfig = {}) => { 35 | const schema = {} 36 | let totalRoutes = 0 37 | 38 | if (!version) 39 | version = `https://unpkg.com/swagger-ui-dist@${version}/swagger-ui.css` 40 | 41 | const info = { 42 | title: 'Elysia Documentation', 43 | description: 'Development documentation', 44 | version: '0.0.0', 45 | ...documentation.info 46 | } 47 | 48 | const relativePath = path.startsWith('/') ? path.slice(1) : path 49 | 50 | const app = new Elysia({ name: '@elysiajs/swagger' }) 51 | 52 | const page = new Response( 53 | provider === 'swagger-ui' 54 | ? SwaggerUIRender( 55 | info, 56 | version, 57 | theme, 58 | JSON.stringify( 59 | { 60 | url: specPath, 61 | dom_id: '#swagger-ui', 62 | ...swaggerOptions 63 | }, 64 | (_, value) => 65 | typeof value === 'function' ? undefined : value 66 | ), 67 | autoDarkMode 68 | ) 69 | : ScalarRender( 70 | info, 71 | scalarVersion, 72 | { 73 | spec: { 74 | ...scalarConfig.spec, 75 | url: specPath 76 | }, 77 | ...scalarConfig, 78 | // so we can showcase the elysia theme 79 | // @ts-expect-error 80 | _integration: 'elysiajs' 81 | } satisfies ReferenceConfiguration, 82 | scalarCDN 83 | ), 84 | { 85 | headers: { 86 | 'content-type': 'text/html; charset=utf8' 87 | } 88 | } 89 | ) 90 | 91 | app.get(path, page, { 92 | detail: { 93 | hide: true 94 | } 95 | }).get( 96 | specPath, 97 | function openAPISchema() { 98 | // @ts-expect-error Private property 99 | const routes = app.getGlobalRoutes() as InternalRoute[] 100 | 101 | if (routes.length !== totalRoutes) { 102 | const ALLOWED_METHODS = [ 103 | 'GET', 104 | 'PUT', 105 | 'POST', 106 | 'DELETE', 107 | 'OPTIONS', 108 | 'HEAD', 109 | 'PATCH', 110 | 'TRACE' 111 | ] 112 | totalRoutes = routes.length 113 | 114 | // forEach create a clone of a route (can't use for-of) 115 | routes.forEach((route: InternalRoute) => { 116 | if (route.hooks?.detail?.hide === true) return 117 | if (excludeMethods.includes(route.method)) return 118 | if ( 119 | ALLOWED_METHODS.includes(route.method) === false && 120 | route.method !== 'ALL' 121 | ) 122 | return 123 | 124 | if (route.method === 'ALL') 125 | ALLOWED_METHODS.forEach((method) => { 126 | registerSchemaPath({ 127 | schema, 128 | hook: route.hooks, 129 | method, 130 | path: route.path, 131 | // @ts-ignore 132 | models: app.getGlobalDefinitions?.().type, 133 | contentType: route.hooks.type 134 | }) 135 | }) 136 | else 137 | registerSchemaPath({ 138 | schema, 139 | hook: route.hooks, 140 | method: route.method, 141 | path: route.path, 142 | // @ts-ignore 143 | models: app.getGlobalDefinitions?.().type, 144 | contentType: route.hooks.type 145 | }) 146 | }) 147 | } 148 | 149 | return { 150 | openapi: '3.0.3', 151 | ...{ 152 | ...documentation, 153 | tags: documentation.tags?.filter( 154 | (tag) => !excludeTags?.includes(tag?.name) 155 | ), 156 | info: { 157 | title: 'Elysia Documentation', 158 | description: 'Development documentation', 159 | version: '0.0.0', 160 | ...documentation.info 161 | } 162 | }, 163 | paths: { 164 | ...filterPaths(schema, { 165 | excludeStaticFile, 166 | exclude: Array.isArray(exclude) ? exclude : [exclude] 167 | }), 168 | ...documentation.paths 169 | }, 170 | components: { 171 | ...documentation.components, 172 | schemas: { 173 | // @ts-ignore 174 | ...app.getGlobalDefinitions?.().type, 175 | ...documentation.components?.schemas 176 | } 177 | } 178 | } satisfies OpenAPIV3.Document 179 | }, 180 | { 181 | detail: { 182 | hide: true 183 | } 184 | } 185 | ) 186 | 187 | return app 188 | } 189 | 190 | export type { ElysiaSwaggerConfig } 191 | export default swagger 192 | -------------------------------------------------------------------------------- /src/scalar/index.ts: -------------------------------------------------------------------------------- 1 | import { elysiajsTheme } from '@scalar/themes' 2 | import type { OpenAPIV3 } from 'openapi-types' 3 | import type { ReferenceConfiguration } from '@scalar/types' 4 | 5 | export const ScalarRender = ( 6 | info: OpenAPIV3.InfoObject, 7 | version: string, 8 | config: ReferenceConfiguration, 9 | cdn: string 10 | ) => ` 11 | 12 | 13 | ${info.title} 14 | 18 | 22 | 23 | 26 | 31 | 34 | 35 | 36 | 42 | 47 | 48 | ` 49 | -------------------------------------------------------------------------------- /src/swagger/index.ts: -------------------------------------------------------------------------------- 1 | import { OpenAPIV3 } from 'openapi-types'; 2 | 3 | type DateTimeSchema = { 4 | type: 'string'; 5 | format: 'date-time'; 6 | default?: string; 7 | }; 8 | 9 | type SchemaObject = OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject; 10 | 11 | function isSchemaObject(schema: SchemaObject): schema is OpenAPIV3.SchemaObject { 12 | return 'type' in schema || 'properties' in schema || 'items' in schema; 13 | } 14 | 15 | function isDateTimeProperty(key: string, schema: OpenAPIV3.SchemaObject): boolean { 16 | return (key === 'createdAt' || key === 'updatedAt') && 17 | 'anyOf' in schema && 18 | Array.isArray(schema.anyOf); 19 | } 20 | 21 | function transformDateProperties(schema: SchemaObject): SchemaObject { 22 | if (!isSchemaObject(schema) || typeof schema !== 'object' || schema === null) { 23 | return schema; 24 | } 25 | 26 | const newSchema: OpenAPIV3.SchemaObject = { ...schema }; 27 | 28 | Object.entries(newSchema).forEach(([key, value]) => { 29 | if (isSchemaObject(value)) { 30 | if (isDateTimeProperty(key, value)) { 31 | const dateTimeFormat = value.anyOf?.find((item): item is OpenAPIV3.SchemaObject => 32 | isSchemaObject(item) && item.format === 'date-time' 33 | ); 34 | if (dateTimeFormat) { 35 | const dateTimeSchema: DateTimeSchema = { 36 | type: 'string', 37 | format: 'date-time', 38 | default: dateTimeFormat.default 39 | }; 40 | (newSchema as Record)[key] = dateTimeSchema; 41 | } 42 | } else { 43 | (newSchema as Record)[key] = transformDateProperties(value); 44 | } 45 | } 46 | }); 47 | 48 | return newSchema; 49 | } 50 | 51 | export const SwaggerUIRender = ( 52 | info: OpenAPIV3.InfoObject, 53 | version: string, 54 | theme: 55 | | string 56 | | { 57 | light: string 58 | dark: string 59 | }, 60 | stringifiedSwaggerOptions: string, 61 | autoDarkMode?: boolean 62 | ): string => { 63 | const swaggerOptions: OpenAPIV3.Document = JSON.parse(stringifiedSwaggerOptions); 64 | 65 | if (swaggerOptions.components && swaggerOptions.components.schemas) { 66 | swaggerOptions.components.schemas = Object.fromEntries( 67 | Object.entries(swaggerOptions.components.schemas).map(([key, schema]) => [ 68 | key, 69 | transformDateProperties(schema) 70 | ]) 71 | ); 72 | } 73 | 74 | const transformedStringifiedSwaggerOptions = JSON.stringify(swaggerOptions); 75 | 76 | return ` 77 | 78 | 79 | 80 | 81 | ${info.title} 82 | 86 | 90 | ${ 91 | autoDarkMode && typeof theme === 'string' 92 | ? ` 93 | ` 108 | : '' 109 | } 110 | ${ 111 | typeof theme === 'string' 112 | ? `` 113 | : ` 114 | ` 115 | } 116 | 117 | 118 |
119 | 120 | 125 | 126 | `; 127 | }; 128 | -------------------------------------------------------------------------------- /src/swagger/types.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Swagger UI type because swagger-ui doesn't export an interface so here's copy paste 3 | * 4 | * @see swagger-ui/index.d.ts 5 | **/ 6 | export interface SwaggerUIOptions { 7 | // Core 8 | 9 | /** 10 | * URL to fetch external configuration document from. 11 | */ 12 | configUrl?: string | undefined 13 | /** 14 | * REQUIRED if domNode is not provided. The ID of a DOM element inside which SwaggerUI will put its user interface. 15 | */ 16 | dom_id?: string | undefined 17 | /** 18 | * A JavaScript object describing the OpenAPI definition. When used, the url parameter will not be parsed. This is useful for testing manually-generated definitions without hosting them 19 | */ 20 | spec?: { [propName: string]: any } | undefined 21 | /** 22 | * The URL pointing to API definition (normally swagger.json or swagger.yaml). Will be ignored if urls or spec is used. 23 | */ 24 | url?: string | undefined 25 | /** 26 | * An array of API definition objects ([{url: "", name: ""},{url: "", name: ""}]) 27 | * used by Topbar plugin. When used and Topbar plugin is enabled, the url parameter will not be parsed. 28 | * Names and URLs must be unique among all items in this array, since they're used as identifiers. 29 | */ 30 | urls?: 31 | | Array<{ 32 | url: string 33 | name: string 34 | }> 35 | | undefined 36 | 37 | // Plugin system 38 | 39 | /** 40 | * The name of a component available via the plugin system to use as the top-level layout 41 | * for Swagger UI. 42 | */ 43 | layout?: string | undefined 44 | /** 45 | * A Javascript object to configure plugin integration and behaviors 46 | */ 47 | pluginsOptions?: PluginsOptions 48 | /** 49 | * An array of plugin functions to use in Swagger UI. 50 | */ 51 | plugins?: SwaggerUIPlugin[] | undefined 52 | /** 53 | * An array of presets to use in Swagger UI. 54 | * Usually, you'll want to include ApisPreset if you use this option. 55 | */ 56 | presets?: SwaggerUIPlugin[] | undefined 57 | 58 | // Display 59 | 60 | /** 61 | * If set to true, enables deep linking for tags and operations. 62 | * See the Deep Linking documentation for more information. 63 | */ 64 | deepLinking?: boolean | undefined 65 | /** 66 | * Controls the display of operationId in operations list. The default is false. 67 | */ 68 | displayOperationId?: boolean | undefined 69 | /** 70 | * The default expansion depth for models (set to -1 completely hide the models). 71 | */ 72 | defaultModelsExpandDepth?: number | undefined 73 | /** 74 | * The default expansion depth for the model on the model-example section. 75 | */ 76 | defaultModelExpandDepth?: number | undefined 77 | /** 78 | * Controls how the model is shown when the API is first rendered. 79 | * (The user can always switch the rendering for a given model by clicking the 80 | * 'Model' and 'Example Value' links.) 81 | */ 82 | defaultModelRendering?: 'example' | 'model' | undefined 83 | /** 84 | * Controls the display of the request duration (in milliseconds) for "Try it out" requests. 85 | */ 86 | displayRequestDuration?: boolean | undefined 87 | /** 88 | * Controls the default expansion setting for the operations and tags. 89 | * It can be 'list' (expands only the tags), 'full' (expands the tags and operations) 90 | * or 'none' (expands nothing). 91 | */ 92 | docExpansion?: 'list' | 'full' | 'none' | undefined 93 | /** 94 | * If set, enables filtering. 95 | * The top bar will show an edit box that you can use to filter the tagged operations that are shown. 96 | * Can be Boolean to enable or disable, or a string, in which case filtering will be enabled 97 | * using that string as the filter expression. 98 | * Filtering is case sensitive matching the filter expression anywhere inside the tag. 99 | */ 100 | filter?: boolean | string | undefined 101 | /** 102 | * If set, limits the number of tagged operations displayed to at most this many. 103 | * The default is to show all operations. 104 | */ 105 | maxDisplayedTags?: number | undefined 106 | /** 107 | * Apply a sort to the operation list of each API. 108 | * It can be 'alpha' (sort by paths alphanumerically), 109 | * 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). 110 | * Default is the order returned by the server unchanged. 111 | */ 112 | operationsSorter?: SorterLike | undefined 113 | /** 114 | * Controls the display of vendor extension (x-) fields and values for Operations, 115 | * Parameters, Responses, and Schema. 116 | */ 117 | showExtensions?: boolean | undefined 118 | /** 119 | * Controls the display of extensions (pattern, maxLength, minLength, maximum, minimum) fields 120 | * and values for Parameters. 121 | */ 122 | showCommonExtensions?: boolean | undefined 123 | /** 124 | * Apply a sort to the tag list of each API. 125 | * It can be 'alpha' (sort by paths alphanumerically) 126 | * or a function (see Array.prototype.sort() to learn how to write a sort function). 127 | * Two tag name strings are passed to the sorter for each pass. 128 | * Default is the order determined by Swagger UI. 129 | */ 130 | tagsSorter?: SorterLike | undefined 131 | /** 132 | * When enabled, sanitizer will leave style, class and data-* attributes untouched 133 | * on all HTML Elements declared inside markdown strings. 134 | * This parameter is Deprecated and will be removed in 4.0.0. 135 | * @deprecated 136 | */ 137 | useUnsafeMarkdown?: boolean | undefined 138 | /** 139 | * Provides a mechanism to be notified when Swagger UI has finished rendering a newly provided definition. 140 | */ 141 | onComplete?: (() => any) | undefined 142 | /** 143 | * Set to false to deactivate syntax highlighting of payloads and cURL command, 144 | * can be otherwise an object with the activate and theme properties. 145 | */ 146 | syntaxHighlight?: 147 | | false 148 | | { 149 | /** 150 | * Whether syntax highlighting should be activated or not. 151 | */ 152 | activate?: boolean | undefined 153 | /** 154 | * Highlight.js syntax coloring theme to use. (Only these 6 styles are available.) 155 | */ 156 | theme?: 157 | | 'agate' 158 | | 'arta' 159 | | 'idea' 160 | | 'monokai' 161 | | 'nord' 162 | | 'obsidian' 163 | | 'tomorrow-night' 164 | | undefined 165 | } 166 | | undefined 167 | /** 168 | * Controls whether the "Try it out" section should be enabled by default. 169 | */ 170 | tryItOutEnabled?: boolean | undefined 171 | /** 172 | * This is the default configuration section for the the requestSnippets plugin. 173 | */ 174 | requestSnippets?: 175 | | { 176 | generators?: 177 | | { 178 | [genName: string]: { 179 | title: string 180 | syntax: string 181 | } 182 | } 183 | | undefined 184 | defaultExpanded?: boolean | undefined 185 | /** 186 | * e.g. only show curl bash = ["curl_bash"] 187 | */ 188 | languagesMask?: string[] | undefined 189 | } 190 | | undefined 191 | 192 | // Network 193 | 194 | /** 195 | * OAuth redirect URL. 196 | */ 197 | oauth2RedirectUrl?: string | undefined 198 | /** 199 | * MUST be a function. Function to intercept remote definition, 200 | * "Try it out", and OAuth 2.0 requests. 201 | * Accepts one argument requestInterceptor(request) and must return the modified request, 202 | * or a Promise that resolves to the modified request. 203 | */ 204 | requestInterceptor?: 205 | | ((a: Request) => Request | Promise) 206 | | undefined 207 | /** 208 | * MUST be a function. Function to intercept remote definition, 209 | * "Try it out", and OAuth 2.0 responses. 210 | * Accepts one argument responseInterceptor(response) and must return the modified response, 211 | * or a Promise that resolves to the modified response. 212 | */ 213 | responseInterceptor?: 214 | | ((a: Response) => Response | Promise) 215 | | undefined 216 | /** 217 | * If set to true, uses the mutated request returned from a requestInterceptor 218 | * to produce the curl command in the UI, otherwise the request 219 | * beforethe requestInterceptor was applied is used. 220 | */ 221 | showMutatedRequest?: boolean | undefined 222 | /** 223 | * List of HTTP methods that have the "Try it out" feature enabled. 224 | * An empty array disables "Try it out" for all operations. 225 | * This does not filter the operations from the display. 226 | */ 227 | supportedSubmitMethods?: SupportedHTTPMethods[] | undefined 228 | /** 229 | * By default, Swagger UI attempts to validate specs against swagger.io's online validator. 230 | * You can use this parameter to set a different validator URL, 231 | * for example for locally deployed validators (Validator Badge). 232 | * Setting it to either none, 127.0.0.1 or localhost will disable validation. 233 | */ 234 | validatorUrl?: string | undefined 235 | /** 236 | * If set to true, enables passing credentials, as defined in the Fetch standard, 237 | * in CORS requests that are sent by the browser. 238 | * Note that Swagger UI cannot currently set cookies cross-domain (see swagger-js#1163) 239 | * - as a result, you will have to rely on browser-supplied 240 | * cookies (which this setting enables sending) that Swagger UI cannot control. 241 | */ 242 | withCredentials?: boolean | undefined 243 | 244 | // Macros 245 | 246 | /** 247 | * Function to set default values to each property in model. 248 | * Accepts one argument modelPropertyMacro(property), property is immutable 249 | */ 250 | modelPropertyMacro?: ((propName: Readonly) => any) | undefined 251 | /** 252 | * Function to set default value to parameters. 253 | * Accepts two arguments parameterMacro(operation, parameter). 254 | * Operation and parameter are objects passed for context, both remain immutable 255 | */ 256 | parameterMacro?: 257 | | ((operation: Readonly, parameter: Readonly) => any) 258 | | undefined 259 | 260 | // Authorization 261 | 262 | /** 263 | * If set to true, it persists authorization data and it would not be lost on browser close/refresh 264 | */ 265 | persistAuthorization?: boolean | undefined 266 | } 267 | interface PluginsOptions { 268 | /** 269 | * Control behavior of plugins when targeting the same component with wrapComponent.
270 | * - `legacy` (default) : last plugin takes precedence over the others
271 | * - `chain` : chain wrapComponents when targeting the same core component, 272 | * allowing multiple plugins to wrap the same component 273 | * @default 'legacy' 274 | */ 275 | pluginLoadType?: PluginLoadType 276 | } 277 | 278 | type PluginLoadType = 'legacy' | 'chain' 279 | 280 | type SupportedHTTPMethods = 281 | | 'get' 282 | | 'put' 283 | | 'post' 284 | | 'delete' 285 | | 'options' 286 | | 'head' 287 | | 'patch' 288 | | 'trace' 289 | 290 | type SorterLike = 291 | | 'alpha' 292 | | 'method' 293 | | { 294 | (name1: string, name2: string): number 295 | } 296 | 297 | interface Request { 298 | [prop: string]: any 299 | } 300 | 301 | interface Response { 302 | [prop: string]: any 303 | } 304 | 305 | /** 306 | * See https://swagger.io/docs/open-source-tools/swagger-ui/customization/plugin-api/ 307 | */ 308 | interface SwaggerUIPlugin { 309 | (system: any): { 310 | statePlugins?: 311 | | { 312 | [stateKey: string]: { 313 | actions?: Indexable | undefined 314 | reducers?: Indexable | undefined 315 | selectors?: Indexable | undefined 316 | wrapActions?: Indexable | undefined 317 | wrapSelectors?: Indexable | undefined 318 | } 319 | } 320 | | undefined 321 | components?: Indexable | undefined 322 | wrapComponents?: Indexable | undefined 323 | rootInjects?: Indexable | undefined 324 | afterLoad?: ((system: any) => any) | undefined 325 | fn?: Indexable | undefined 326 | } 327 | } 328 | 329 | interface Indexable { 330 | [index: string]: any 331 | } 332 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { OpenAPIV3 } from 'openapi-types' 2 | import type { ReferenceConfiguration } from '@scalar/types' 3 | import type { SwaggerUIOptions } from './swagger/types' 4 | 5 | export interface ElysiaSwaggerConfig { 6 | /** 7 | * Customize Swagger config, refers to Swagger 2.0 config 8 | * 9 | * @see https://swagger.io/specification/v2/ 10 | */ 11 | documentation?: Omit< 12 | Partial, 13 | | 'x-express-openapi-additional-middleware' 14 | | 'x-express-openapi-validation-strict' 15 | > 16 | /** 17 | * Choose your provider, Scalar or Swagger UI 18 | * 19 | * @default 'scalar' 20 | * @see https://github.com/scalar/scalar 21 | * @see https://github.com/swagger-api/swagger-ui 22 | */ 23 | provider?: 'scalar' | 'swagger-ui' 24 | /** 25 | * Version to use for Scalar cdn bundle 26 | * 27 | * @default 'latest' 28 | * @see https://github.com/scalar/scalar 29 | */ 30 | scalarVersion?: string 31 | /** 32 | * Optional override to specifying the path for the Scalar bundle 33 | * 34 | * Custom URL or path to locally hosted Scalar bundle 35 | * 36 | * Lease blank to use default jsdeliver.net CDN 37 | * 38 | * @default '' 39 | * @example 'https://unpkg.com/@scalar/api-reference@1.13.10/dist/browser/standalone.js' 40 | * @example '/public/standalone.js' 41 | * @see https://github.com/scalar/scalar 42 | */ 43 | scalarCDN?: string 44 | /** 45 | * Scalar configuration to customize scalar 46 | *' 47 | * @see https://github.com/scalar/scalar/blob/main/documentation/configuration.md 48 | */ 49 | scalarConfig?: ReferenceConfiguration 50 | /** 51 | * Version to use for swagger cdn bundle 52 | * 53 | * @see unpkg.com/swagger-ui-dist 54 | * 55 | * @default 4.18.2 56 | */ 57 | version?: string 58 | /** 59 | * Determine if Swagger should exclude static files. 60 | * 61 | * @default true 62 | */ 63 | excludeStaticFile?: boolean 64 | /** 65 | * The endpoint to expose OpenAPI Documentation 66 | * 67 | * @default '/swagger' 68 | */ 69 | path?: Path 70 | /** 71 | * The endpoint to expose OpenAPI JSON specification 72 | * 73 | * @default '/${path}/json' 74 | */ 75 | specPath?: string 76 | /** 77 | * Paths to exclude from Swagger endpoint 78 | * 79 | * @default [] 80 | */ 81 | exclude?: string | RegExp | (string | RegExp)[] 82 | /** 83 | * Options to send to SwaggerUIBundle 84 | * Currently, options that are defined as functions such as requestInterceptor 85 | * and onComplete are not supported. 86 | */ 87 | swaggerOptions?: Omit< 88 | Partial, 89 | | 'dom_id' 90 | | 'dom_node' 91 | | 'spec' 92 | | 'url' 93 | | 'urls' 94 | | 'layout' 95 | | 'pluginsOptions' 96 | | 'plugins' 97 | | 'presets' 98 | | 'onComplete' 99 | | 'requestInterceptor' 100 | | 'responseInterceptor' 101 | | 'modelPropertyMacro' 102 | | 'parameterMacro' 103 | > 104 | /** 105 | * Custom Swagger CSS 106 | */ 107 | theme?: 108 | | string 109 | | { 110 | light: string 111 | dark: string 112 | } 113 | /** 114 | * Using poor man dark mode 😭 115 | */ 116 | autoDarkMode?: boolean 117 | 118 | /** 119 | * Exclude methods from Swagger 120 | */ 121 | excludeMethods?: string[] 122 | 123 | /** 124 | * Exclude tags from Swagger or Scalar 125 | */ 126 | excludeTags?: string[] 127 | } 128 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/ban-ts-comment */ 2 | /* eslint-disable @typescript-eslint/no-unused-vars */ 3 | import { normalize } from 'pathe' 4 | import { replaceSchemaType, t, type HTTPMethod, type LocalHook } from 'elysia' 5 | 6 | import { Kind, type TSchema } from '@sinclair/typebox' 7 | import type { OpenAPIV3 } from 'openapi-types' 8 | 9 | export const toOpenAPIPath = (path: string) => 10 | path 11 | .split('/') 12 | .map((x) => { 13 | if (x.startsWith(':')) { 14 | x = x.slice(1, x.length) 15 | if (x.endsWith('?')) x = x.slice(0, -1) 16 | x = `{${x}}` 17 | } 18 | 19 | return x 20 | }) 21 | .join('/') 22 | 23 | export const mapProperties = ( 24 | name: string, 25 | schema: TSchema | string | undefined, 26 | models: Record 27 | ) => { 28 | if (schema === undefined) return [] 29 | 30 | if (typeof schema === 'string') 31 | if (schema in models) schema = models[schema] 32 | else throw new Error(`Can't find model ${schema}`) 33 | 34 | return Object.entries(schema?.properties ?? []).map(([key, value]) => { 35 | const { 36 | type: valueType = undefined, 37 | description, 38 | examples, 39 | ...schemaKeywords 40 | } = value as any 41 | return { 42 | // @ts-ignore 43 | description, 44 | examples, 45 | schema: { type: valueType, ...schemaKeywords }, 46 | in: name, 47 | name: key, 48 | // @ts-ignore 49 | required: schema!.required?.includes(key) ?? false 50 | } 51 | }) 52 | } 53 | 54 | const mapTypesResponse = ( 55 | types: string[], 56 | schema: 57 | | string 58 | | { 59 | type: string 60 | properties: Object 61 | required: string[] 62 | } 63 | ) => { 64 | if ( 65 | typeof schema === 'object' && 66 | ['void', 'undefined', 'null'].includes(schema.type) 67 | ) 68 | return 69 | 70 | const responses: Record = {} 71 | 72 | for (const type of types) { 73 | responses[type] = { 74 | schema: 75 | typeof schema === 'string' 76 | ? { 77 | $ref: `#/components/schemas/${schema}` 78 | } 79 | : '$ref' in schema && 80 | Kind in schema && 81 | schema[Kind] === 'Ref' 82 | ? { 83 | ...schema, 84 | $ref: `#/components/schemas/${schema.$ref}` 85 | } 86 | : replaceSchemaType( 87 | { ...(schema as any) }, 88 | { 89 | from: t.Ref(''), 90 | // @ts-expect-error 91 | to: ({ $ref, ...options }) => { 92 | if ( 93 | !$ref.startsWith( 94 | '#/components/schemas/' 95 | ) 96 | ) 97 | return t.Ref( 98 | `#/components/schemas/${$ref}`, 99 | options 100 | ) 101 | 102 | return t.Ref($ref, options) 103 | } 104 | } 105 | ) 106 | } 107 | } 108 | 109 | return responses 110 | } 111 | 112 | export const capitalize = (word: string) => 113 | word.charAt(0).toUpperCase() + word.slice(1) 114 | 115 | export const generateOperationId = (method: string, paths: string) => { 116 | let operationId = method.toLowerCase() 117 | 118 | if (paths === '/') return operationId + 'Index' 119 | 120 | for (const path of paths.split('/')) { 121 | if (path.charCodeAt(0) === 123) { 122 | operationId += 'By' + capitalize(path.slice(1, -1)) 123 | } else { 124 | operationId += capitalize(path) 125 | } 126 | } 127 | 128 | return operationId 129 | } 130 | 131 | const cloneHook = (hook: T) => { 132 | if (!hook) return 133 | if (typeof hook === 'string') return hook 134 | if (Array.isArray(hook)) return [...hook] 135 | return { ...hook } 136 | } 137 | 138 | export const registerSchemaPath = ({ 139 | schema, 140 | path, 141 | method, 142 | hook, 143 | models 144 | }: { 145 | schema: Partial 146 | contentType?: string | string[] 147 | path: string 148 | method: HTTPMethod 149 | hook?: LocalHook 150 | models: Record 151 | }) => { 152 | hook = cloneHook(hook) 153 | 154 | if (hook.parse && !Array.isArray(hook.parse)) hook.parse = [hook.parse] 155 | 156 | let contentType = (hook.parse as unknown[]) 157 | ?.map((x) => { 158 | switch (typeof x) { 159 | case 'string': 160 | return x 161 | 162 | case 'object': 163 | if ( 164 | x && 165 | typeof (x as { fn: string | Function })?.fn !== 'string' 166 | ) 167 | return 168 | 169 | switch ((x as { fn: string | Function })?.fn) { 170 | case 'json': 171 | case 'application/json': 172 | return 'application/json' 173 | 174 | case 'text': 175 | case 'text/plain': 176 | return 'text/plain' 177 | 178 | case 'urlencoded': 179 | case 'application/x-www-form-urlencoded': 180 | return 'application/x-www-form-urlencoded' 181 | 182 | case 'arrayBuffer': 183 | case 'application/octet-stream': 184 | return 'application/octet-stream' 185 | 186 | case 'formdata': 187 | case 'multipart/form-data': 188 | return 'multipart/form-data' 189 | } 190 | } 191 | }) 192 | .filter((x) => x !== undefined) 193 | 194 | if (!contentType || contentType.length === 0) 195 | contentType = ['application/json', 'multipart/form-data', 'text/plain'] 196 | 197 | path = toOpenAPIPath(path) 198 | 199 | const contentTypes = 200 | typeof contentType === 'string' 201 | ? [contentType] 202 | : (contentType ?? ['application/json']) 203 | 204 | const bodySchema = cloneHook(hook?.body) 205 | const paramsSchema = cloneHook(hook?.params) 206 | const headerSchema = cloneHook(hook?.headers) 207 | const querySchema = cloneHook(hook?.query) 208 | let responseSchema: OpenAPIV3.ResponsesObject = cloneHook(hook?.response) 209 | 210 | if (typeof responseSchema === 'object') { 211 | if (Kind in responseSchema) { 212 | const { 213 | type, 214 | properties, 215 | required, 216 | additionalProperties, 217 | patternProperties, 218 | $ref, 219 | ...rest 220 | } = responseSchema as typeof responseSchema & { 221 | type: string 222 | properties: Object 223 | required: string[] 224 | } 225 | 226 | responseSchema = { 227 | '200': { 228 | ...rest, 229 | description: rest.description as any, 230 | content: mapTypesResponse( 231 | contentTypes, 232 | type === 'object' || type === 'array' 233 | ? ({ 234 | type, 235 | properties, 236 | patternProperties, 237 | items: responseSchema.items, 238 | required 239 | } as any) 240 | : responseSchema 241 | ) 242 | } 243 | } 244 | } else { 245 | Object.entries(responseSchema as Record).forEach( 246 | ([key, value]) => { 247 | if (typeof value === 'string') { 248 | if (!models[value]) return 249 | 250 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 251 | const { 252 | type, 253 | properties, 254 | required, 255 | additionalProperties: _1, 256 | patternProperties: _2, 257 | ...rest 258 | } = models[value] as TSchema & { 259 | type: string 260 | properties: Object 261 | required: string[] 262 | } 263 | 264 | responseSchema[key] = { 265 | ...rest, 266 | description: rest.description as any, 267 | content: mapTypesResponse(contentTypes, value) 268 | } 269 | } else { 270 | const { 271 | type, 272 | properties, 273 | required, 274 | additionalProperties, 275 | patternProperties, 276 | ...rest 277 | } = value as typeof value & { 278 | type: string 279 | properties: Object 280 | required: string[] 281 | } 282 | 283 | responseSchema[key] = { 284 | ...rest, 285 | description: rest.description as any, 286 | content: mapTypesResponse( 287 | contentTypes, 288 | type === 'object' || type === 'array' 289 | ? ({ 290 | type, 291 | properties, 292 | patternProperties, 293 | items: value.items, 294 | required 295 | } as any) 296 | : value 297 | ) 298 | } 299 | } 300 | } 301 | ) 302 | } 303 | } else if (typeof responseSchema === 'string') { 304 | if (!(responseSchema in models)) return 305 | 306 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 307 | const { 308 | type, 309 | properties, 310 | required, 311 | $ref, 312 | additionalProperties: _1, 313 | patternProperties: _2, 314 | ...rest 315 | } = models[responseSchema] as TSchema & { 316 | type: string 317 | properties: Object 318 | required: string[] 319 | } 320 | 321 | responseSchema = { 322 | // @ts-ignore 323 | '200': { 324 | ...rest, 325 | content: mapTypesResponse(contentTypes, responseSchema) 326 | } 327 | } 328 | } 329 | 330 | const parameters = [ 331 | ...mapProperties('header', headerSchema, models), 332 | ...mapProperties('path', paramsSchema, models), 333 | ...mapProperties('query', querySchema, models) 334 | ] 335 | 336 | schema[path] = { 337 | ...(schema[path] ? schema[path] : {}), 338 | [method.toLowerCase()]: { 339 | ...((headerSchema || paramsSchema || querySchema || bodySchema 340 | ? ({ parameters } as any) 341 | : {}) satisfies OpenAPIV3.ParameterObject), 342 | ...(responseSchema 343 | ? { 344 | responses: responseSchema 345 | } 346 | : {}), 347 | operationId: 348 | hook?.detail?.operationId ?? generateOperationId(method, path), 349 | ...hook?.detail, 350 | ...(bodySchema 351 | ? { 352 | requestBody: { 353 | required: true, 354 | content: mapTypesResponse( 355 | contentTypes, 356 | typeof bodySchema === 'string' 357 | ? { 358 | $ref: `#/components/schemas/${bodySchema}` 359 | } 360 | : (bodySchema as any) 361 | ) 362 | } 363 | } 364 | : null) 365 | } satisfies OpenAPIV3.OperationObject 366 | } 367 | } 368 | 369 | export const filterPaths = ( 370 | paths: Record, 371 | { 372 | excludeStaticFile = true, 373 | exclude = [] 374 | }: { 375 | excludeStaticFile: boolean 376 | exclude: (string | RegExp)[] 377 | } 378 | ) => { 379 | const newPaths: Record = {} 380 | 381 | for (const [key, value] of Object.entries(paths)) 382 | if ( 383 | !exclude.some((x) => { 384 | if (typeof x === 'string') return key === x 385 | 386 | return x.test(key) 387 | }) && 388 | !key.includes('*') && 389 | (excludeStaticFile ? !key.includes('.') : true) 390 | ) { 391 | Object.keys(value).forEach((method) => { 392 | const schema = value[method] 393 | 394 | if (key.includes('{')) { 395 | if (!schema.parameters) schema.parameters = [] 396 | 397 | schema.parameters = [ 398 | ...key 399 | .split('/') 400 | .filter( 401 | (x) => 402 | x.startsWith('{') && 403 | !schema.parameters.find( 404 | (params: Record) => 405 | params.in === 'path' && 406 | params.name === 407 | x.slice(1, x.length - 1) 408 | ) 409 | ) 410 | .map((x) => ({ 411 | schema: { type: 'string' }, 412 | in: 'path', 413 | name: x.slice(1, x.length - 1), 414 | required: true 415 | })), 416 | ...schema.parameters 417 | ] 418 | } 419 | 420 | if (!schema.responses) 421 | schema.responses = { 422 | 200: {} 423 | } 424 | }) 425 | 426 | newPaths[key] = value 427 | } 428 | 429 | return newPaths 430 | } 431 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { Elysia, t } from 'elysia' 2 | import SwaggerParser from '@apidevtools/swagger-parser' 3 | import { swagger } from '../src' 4 | 5 | import { describe, expect, it } from 'bun:test' 6 | import { fail } from 'assert' 7 | 8 | const req = (path: string) => new Request(`http://localhost${path}`) 9 | 10 | describe('Swagger', () => { 11 | it('show Swagger page', async () => { 12 | const app = new Elysia().use(swagger()) 13 | 14 | await app.modules 15 | 16 | const res = await app.handle(req('/swagger')) 17 | expect(res.status).toBe(200) 18 | }) 19 | 20 | it('returns a valid Swagger/OpenAPI json config', async () => { 21 | const app = new Elysia().use(swagger()) 22 | 23 | await app.modules 24 | 25 | const res = await app.handle(req('/swagger/json')).then((x) => x.json()) 26 | expect(res.openapi).toBe('3.0.3') 27 | await SwaggerParser.validate(res).catch((err) => fail(err)) 28 | }) 29 | 30 | it('use custom Swagger version', async () => { 31 | const app = new Elysia().use( 32 | swagger({ 33 | provider: 'swagger-ui', 34 | version: '4.5.0' 35 | }) 36 | ) 37 | 38 | await app.modules 39 | 40 | const res = await app.handle(req('/swagger')).then((x) => x.text()) 41 | expect( 42 | res.includes( 43 | 'https://unpkg.com/swagger-ui-dist@4.5.0/swagger-ui-bundle.js' 44 | ) 45 | ).toBe(true) 46 | }) 47 | 48 | it('follow title and description with Swagger-UI provider', async () => { 49 | const app = new Elysia().use( 50 | swagger({ 51 | version: '4.5.0', 52 | provider: 'swagger-ui', 53 | documentation: { 54 | info: { 55 | title: 'Elysia Documentation', 56 | description: 'Herrscher of Human', 57 | version: '1.0.0' 58 | } 59 | } 60 | }) 61 | ) 62 | 63 | await app.modules 64 | 65 | const res = await app.handle(req('/swagger')).then((x) => x.text()) 66 | 67 | expect(res.includes('Elysia Documentation')).toBe(true) 68 | expect( 69 | res.includes( 70 | `` 74 | ) 75 | ).toBe(true) 76 | }) 77 | 78 | it('follow title and description with Scalar provider', async () => { 79 | const app = new Elysia().use( 80 | swagger({ 81 | version: '4.5.0', 82 | provider: 'scalar', 83 | documentation: { 84 | info: { 85 | title: 'Elysia Documentation', 86 | description: 'Herrscher of Human', 87 | version: '1.0.0' 88 | } 89 | } 90 | }) 91 | ) 92 | 93 | await app.modules 94 | 95 | const res = await app.handle(req('/swagger')).then((x) => x.text()) 96 | 97 | expect(res.includes('Elysia Documentation')).toBe(true) 98 | expect( 99 | res.includes( 100 | `` 104 | ) 105 | ).toBe(true) 106 | }) 107 | 108 | it('use custom path', async () => { 109 | const app = new Elysia().use( 110 | swagger({ 111 | path: '/v2/swagger' 112 | }) 113 | ) 114 | 115 | await app.modules 116 | 117 | const res = await app.handle(req('/v2/swagger')) 118 | expect(res.status).toBe(200) 119 | 120 | const resJson = await app.handle(req('/v2/swagger/json')) 121 | expect(resJson.status).toBe(200) 122 | }) 123 | 124 | it('Swagger UI options', async () => { 125 | const app = new Elysia().use( 126 | swagger({ 127 | provider: 'swagger-ui', 128 | swaggerOptions: { 129 | persistAuthorization: true 130 | } 131 | }) 132 | ) 133 | 134 | await app.modules 135 | 136 | const res = await app.handle(req('/swagger')).then((x) => x.text()) 137 | const expected = `"persistAuthorization":true` 138 | 139 | expect(res.trim().includes(expected.trim())).toBe(true) 140 | }) 141 | 142 | it('should not return content response when using Void type', async () => { 143 | const app = new Elysia().use(swagger()).get('/void', () => {}, { 144 | response: { 145 | 204: t.Void({ 146 | description: 'Void response' 147 | }) 148 | } 149 | }) 150 | 151 | await app.modules 152 | 153 | const res = await app.handle(req('/swagger/json')) 154 | expect(res.status).toBe(200) 155 | const response = await res.json() 156 | expect(response.paths['/void'].get.responses['204'].description).toBe( 157 | 'Void response' 158 | ) 159 | expect( 160 | response.paths['/void'].get.responses['204'].content 161 | ).toBeUndefined() 162 | }) 163 | 164 | it('should not return content response when using Undefined type', async () => { 165 | const app = new Elysia() 166 | .use(swagger()) 167 | .get('/undefined', () => undefined, { 168 | response: { 169 | 204: t.Undefined({ 170 | description: 'Undefined response' 171 | }) 172 | } 173 | }) 174 | 175 | await app.modules 176 | 177 | const res = await app.handle(req('/swagger/json')) 178 | expect(res.status).toBe(200) 179 | const response = await res.json() 180 | expect( 181 | response.paths['/undefined'].get.responses['204'].description 182 | ).toBe('Undefined response') 183 | expect( 184 | response.paths['/undefined'].get.responses['204'].content 185 | ).toBeUndefined() 186 | }) 187 | 188 | it('should not return content response when using Null type', async () => { 189 | const app = new Elysia().use(swagger()).get('/null', () => null, { 190 | response: { 191 | 204: t.Null({ 192 | description: 'Null response' 193 | }) 194 | } 195 | }) 196 | 197 | await app.modules 198 | 199 | const res = await app.handle(req('/swagger/json')) 200 | expect(res.status).toBe(200) 201 | const response = await res.json() 202 | expect(response.paths['/null'].get.responses['204'].description).toBe( 203 | 'Null response' 204 | ) 205 | expect( 206 | response.paths['/null'].get.responses['204'].content 207 | ).toBeUndefined() 208 | }) 209 | 210 | it('should set the required field to true when a request body is present', async () => { 211 | const app = new Elysia().use(swagger()).post('/post', () => {}, { 212 | body: t.Object({ name: t.String() }) 213 | }) 214 | 215 | await app.modules 216 | 217 | const res = await app.handle(req('/swagger/json')) 218 | expect(res.status).toBe(200) 219 | const response = await res.json() 220 | expect(response.paths['/post'].post.requestBody.required).toBe(true) 221 | }) 222 | 223 | it('resolve optional param to param', async () => { 224 | const app = new Elysia().use(swagger()).get('/id/:id?', () => {}) 225 | 226 | await app.modules 227 | 228 | const res = await app.handle(req('/swagger/json')) 229 | expect(res.status).toBe(200) 230 | const response = await res.json() 231 | expect(response.paths).toContainKey('/id/{id}') 232 | }) 233 | 234 | it('should hide routes with hide = true from paths', async () => { 235 | const app = new Elysia().use(swagger()) 236 | .get("/public", "omg") 237 | .guard({ 238 | detail: { 239 | hide: true 240 | } 241 | }) 242 | .get("/hidden", "ok") 243 | 244 | await app.modules 245 | 246 | const res = await app.handle(req('/swagger/json')) 247 | expect(res.status).toBe(200) 248 | const response = await res.json() 249 | expect(response.paths['/public']).not.toBeUndefined(); 250 | expect(response.paths['/hidden']).toBeUndefined(); 251 | }) 252 | 253 | it('should expand .all routes', async () => { 254 | const app = new Elysia().use(swagger()) 255 | .all("/all", "woah") 256 | 257 | await app.modules 258 | 259 | const res = await app.handle(req('/swagger/json')) 260 | expect(res.status).toBe(200) 261 | const response = await res.json() 262 | expect(Object.keys(response.paths['/all'])).toBeArrayOfSize(8) 263 | }) 264 | 265 | it('should hide routes that are invalid', async () => { 266 | const app = new Elysia().use(swagger()) 267 | .get("/valid", "ok") 268 | .route("LOCK", "/invalid", "nope") 269 | 270 | await app.modules 271 | 272 | const res = await app.handle(req('/swagger/json')) 273 | expect(res.status).toBe(200) 274 | const response = await res.json() 275 | expect(response.paths['/valid']).not.toBeUndefined(); 276 | expect(response.paths['/invalid']).toBeUndefined(); 277 | 278 | }) 279 | }) 280 | -------------------------------------------------------------------------------- /test/node/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json -------------------------------------------------------------------------------- /test/node/cjs/index.js: -------------------------------------------------------------------------------- 1 | if ('Bun' in globalThis) { 2 | throw new Error('❌ Use Node.js to run this test!'); 3 | } 4 | 5 | const { swagger } = require('@elysiajs/swagger'); 6 | 7 | if (typeof swagger !== 'function') { 8 | throw new Error('❌ CommonJS Node.js failed'); 9 | } 10 | 11 | console.log('✅ CommonJS Node.js works!'); 12 | -------------------------------------------------------------------------------- /test/node/cjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "commonjs", 3 | "dependencies": { 4 | "@elysiajs/swagger": "../../.." 5 | } 6 | } -------------------------------------------------------------------------------- /test/node/esm/index.js: -------------------------------------------------------------------------------- 1 | if ('Bun' in globalThis) { 2 | throw new Error('❌ Use Node.js to run this test!'); 3 | } 4 | 5 | import { swagger } from '@elysiajs/swagger'; 6 | 7 | if (typeof swagger !== 'function') { 8 | throw new Error('❌ ESM Node.js failed'); 9 | } 10 | 11 | console.log('✅ ESM Node.js works!'); 12 | -------------------------------------------------------------------------------- /test/node/esm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "dependencies": { 4 | "@elysiajs/swagger": "../../.." 5 | } 6 | } -------------------------------------------------------------------------------- /test/validate-schema.test.ts: -------------------------------------------------------------------------------- 1 | import { Elysia, t } from 'elysia' 2 | import SwaggerParser from '@apidevtools/swagger-parser' 3 | import { swagger } from '../src' 4 | 5 | import { it } from 'bun:test' 6 | import { fail } from 'assert' 7 | 8 | const req = (path: string) => new Request(`http://localhost${path}`) 9 | 10 | it('returns a valid Swagger/OpenAPI json config for many routes', async () => { 11 | const app = new Elysia() 12 | .use(swagger()) 13 | .get('/', () => 'hi', { 14 | response: t.String({ description: 'sample description' }) 15 | }) 16 | .get('/unpath/:id', ({ params: { id } }) => id, { 17 | response: t.String({ description: 'sample description' }) 18 | }) 19 | .get( 20 | '/unpath/:id/:name/:age', 21 | ({ params: { id, name } }) => `${id} ${name}`, 22 | { 23 | type: 'json', 24 | response: t.String({ description: 'sample description' }), 25 | params: t.Object({ id: t.String(), name: t.String() }) 26 | } 27 | ) 28 | .post( 29 | '/json/:id', 30 | ({ body, params: { id }, query: { name, email, birthday } }) => ({ 31 | ...body, 32 | id, 33 | name, 34 | email, 35 | birthday 36 | }), 37 | { 38 | params: t.Object({ 39 | id: t.String() 40 | }), 41 | query: t.Object({ 42 | name: t.String(), 43 | email: t.String({ 44 | description: 'sample email description', 45 | format: 'email' 46 | }), 47 | birthday: t.String({ 48 | description: 'sample birthday description', 49 | pattern: '\\d{4}-\\d{2}-\\d{2}', 50 | minLength: 10, 51 | maxLength: 10 52 | }), 53 | 54 | }), 55 | body: t.Object({ 56 | username: t.String(), 57 | password: t.String() 58 | }), 59 | response: t.Object( 60 | { 61 | username: t.String(), 62 | password: t.String(), 63 | id: t.String(), 64 | name: t.String(), 65 | email: t.String({ 66 | description: 'sample email description', 67 | format: 'email' 68 | }), 69 | birthday: t.String({ 70 | description: 'sample birthday description', 71 | pattern: '\\d{4}-\\d{2}-\\d{2}', 72 | minLength: 10, 73 | maxLength: 10 74 | }), 75 | }, 76 | { description: 'sample description 3' } 77 | ) 78 | } 79 | ) 80 | .route('LOCK', '/lock', () => 'locked') 81 | 82 | await app.modules 83 | 84 | const res = await app.handle(req('/swagger/json')).then((x) => x.json()) 85 | await SwaggerParser.validate(res).catch((err) => fail(err)) 86 | }) 87 | -------------------------------------------------------------------------------- /tsconfig.dts.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "preserveSymlinks": true, 4 | /* Visit https://aka.ms/tsconfig to read more about this file */ 5 | 6 | /* Projects */ 7 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 8 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 9 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 10 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 11 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 12 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 13 | 14 | /* Language and Environment */ 15 | "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 16 | "lib": ["ESNext"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 17 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 18 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 19 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 20 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 21 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 22 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 23 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 24 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 25 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 26 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 27 | 28 | /* Modules */ 29 | "module": "ES2022", /* Specify what module code is generated. */ 30 | "rootDir": "./src", /* Specify the root folder within your source files. */ 31 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 32 | // "baseUrl": "./src", /* Specify the base directory to resolve non-relative module names. */ 33 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 34 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 35 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 36 | // "types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */ 37 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 38 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 39 | "resolveJsonModule": true, /* Enable importing .json files. */ 40 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 41 | 42 | /* JavaScript Support */ 43 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 44 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 45 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 46 | 47 | /* Emit */ 48 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 49 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 50 | "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 51 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 52 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 53 | "outDir": "./dist", /* Specify an output folder for all emitted files. */ 54 | // "removeComments": true, /* Disable emitting comments. */ 55 | // "noEmit": true, /* Disable emitting files from a compilation. */ 56 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 57 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 58 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 59 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 62 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 63 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 64 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 65 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 66 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 67 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 68 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 69 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 70 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 71 | 72 | /* Interop Constraints */ 73 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 74 | "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 75 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 76 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 77 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 78 | 79 | /* Type Checking */ 80 | "strict": true, /* Enable all strict type-checking options. */ 81 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 82 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 83 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 84 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 85 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 86 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 87 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 88 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 89 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 90 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 91 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 92 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 93 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 94 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 95 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 96 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 97 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 98 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 99 | 100 | /* Completeness */ 101 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 102 | "skipLibCheck": true, /* Skip type checking all .d.ts files. */ 103 | }, 104 | "exclude": ["node_modules", "test", "example", "dist", "build.ts"] 105 | // "include": ["src/**/*"] 106 | } 107 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | "lib": ["ESNext", "DOM", "ScriptHost"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ 22 | // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ 26 | 27 | /* Modules */ 28 | "module": "ES2022", /* Specify what module code is generated. */ 29 | // "rootDir": "./src", /* Specify the root folder within your source files. */ 30 | "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 31 | // "baseUrl": "./src", /* Specify the base directory to resolve non-relative module names. */ 32 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 33 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 34 | // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 37 | // "resolveJsonModule": true, /* Enable importing .json files. */ 38 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 39 | 40 | /* JavaScript Support */ 41 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 42 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 43 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 44 | 45 | /* Emit */ 46 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 47 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 48 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 49 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 50 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ 51 | // "outDir": "./dist", /* Specify an output folder for all emitted files. */ 52 | // "removeComments": true, /* Disable emitting comments. */ 53 | "noEmit": true, /* Disable emitting files from a compilation. */ 54 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 55 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 56 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 57 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 59 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 60 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 61 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 62 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 63 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 64 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 65 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 66 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 67 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 68 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 69 | 70 | /* Interop Constraints */ 71 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 72 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 73 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 74 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 75 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 76 | 77 | /* Type Checking */ 78 | "strict": true, /* Enable all strict type-checking options. */ 79 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 80 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 81 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 82 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 83 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 84 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 85 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 86 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 87 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 88 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 89 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 90 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 91 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 92 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 93 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 94 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 95 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 96 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 97 | 98 | /* Completeness */ 99 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 100 | "skipLibCheck": true, /* Skip type checking all .d.ts files. */ 101 | }, 102 | // "include": ["src/**/*"] 103 | } 104 | --------------------------------------------------------------------------------