├── .eslintrc.js ├── .github ├── FUNDING.yaml ├── ISSUE_TEMPLATE │ ├── 2-bug-report.yml │ ├── 3-feature-request.yml │ └── config.yml ├── dependabot.yml └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── benchmarks ├── array.ts ├── large-manual.ts ├── large.ts ├── medium-manual.ts ├── medium.ts ├── message.ts ├── multiple-queries.ts ├── quote.ts ├── small-manual.ts ├── small.ts ├── small2.ts └── utils.ts ├── build.ts ├── bun.lock ├── example └── index.ts ├── package.json ├── src └── index.ts ├── test ├── array.test.ts ├── default.test.ts ├── index.test.ts ├── merge-intersection.test.ts ├── node │ ├── .gitignore │ ├── cjs │ │ ├── index.js │ │ └── package.json │ └── esm │ │ ├── index.js │ │ └── package.json ├── record.test.ts ├── ref.test.ts ├── sample.test.ts ├── sanitize-auto.test.ts ├── sanitize-manual.test.ts ├── sanitize-throw.test.ts ├── tuple.test.ts └── utils.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/FUNDING.yaml: -------------------------------------------------------------------------------- 1 | github: SaltyAom -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-bug-report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug Report 2 | description: Report an issue that should be fixed 3 | labels: [bug] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for submitting a bug report. It helps make Elysia.JS better. 9 | 10 | If you need help or support using Elysia.JS, and are not reporting a bug, please 11 | head over to Q&A discussions [Discussions](https://github.com/elysiajs/elysia/discussions/categories/q-a), where you can ask questions in the Q&A forum. 12 | 13 | Make sure you are running the version of Elysia.JS and Bun.Sh 14 | The bug you are experiencing may already have been fixed. 15 | 16 | Please try to include as much information as possible. 17 | 18 | - type: input 19 | attributes: 20 | label: What version of Elysia is running? 21 | description: Copy the output of `Elysia --revision` 22 | - type: input 23 | attributes: 24 | label: What platform is your computer? 25 | description: | 26 | For MacOS and Linux: copy the output of `uname -mprs` 27 | For Windows: copy the output of `"$([Environment]::OSVersion | ForEach-Object VersionString) $(if ([Environment]::Is64BitOperatingSystem) { "x64" } else { "x86" })"` in the PowerShell console 28 | - type: textarea 29 | attributes: 30 | label: What steps can reproduce the bug? 31 | description: Explain the bug and provide a code snippet that can reproduce it. 32 | validations: 33 | required: true 34 | - type: textarea 35 | attributes: 36 | label: What is the expected behavior? 37 | description: If possible, please provide text instead of a screenshot. 38 | - type: textarea 39 | attributes: 40 | label: What do you see instead? 41 | description: If possible, please provide text instead of a screenshot. 42 | - type: textarea 43 | attributes: 44 | label: Additional information 45 | description: Is there anything else you think we should know? 46 | - type: input 47 | attributes: 48 | label: Have you try removing the `node_modules` and `bun.lockb` and try again yet? 49 | description: rm -rf node_modules && bun.lockb 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-feature-request.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature Request 2 | description: Suggest an idea, feature, or enhancement 3 | labels: [enhancement] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | Thank you for submitting an idea. It helps make Elysia.JS better. 9 | 10 | If you want to discuss Elysia.JS, or learn how others are using Elysia.JS, please 11 | head to our [Discord](https://discord.com/invite/y7kH46ZE) server, where you can chat among the community. 12 | - type: textarea 13 | attributes: 14 | label: What is the problem this feature would solve? 15 | validations: 16 | required: true 17 | - type: textarea 18 | attributes: 19 | label: What is the feature you are proposing to solve the problem? 20 | validations: 21 | required: true 22 | - type: textarea 23 | attributes: 24 | label: What alternatives have you considered? 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: 📗 Documentation Issue 4 | url: https://github.com/elysiajs/documentation/issues/new/choose 5 | about: Head over to our Documentation repository! 6 | - name: 💬 Ask a Question 7 | url: https://discord.gg/eaFJ2KDJck 8 | about: Head over to our Discord! 9 | -------------------------------------------------------------------------------- /.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: Build and Test 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 -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | .gitignore 4 | .prettierrc 5 | .cjs.swcrc 6 | .es.swcrc 7 | bun.lockb 8 | bun.lock 9 | 10 | node_modules 11 | tsconfig.json 12 | pnpm-lock.yaml 13 | jest.config.js 14 | nodemon.json 15 | benchmarks 16 | 17 | example 18 | tests 19 | test 20 | CHANGELOG.md 21 | .eslintrc.js 22 | tsconfig.cjs.json 23 | tsconfig.esm.json 24 | tsconfig.dts.json 25 | 26 | build.ts 27 | src 28 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "tabWidth": 4, 4 | "semi": false, 5 | "singleQuote": true, 6 | "trailingComma": "none" 7 | } 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.5 - 22 Apr 2025 2 | Improvement: 3 | - add `schema.trusted` for string 4 | - improve string placement when using `t.String({ trusted: true })` and `sanitize: manual` 5 | 6 | # 0.1.4 - 27 Mar 2025 7 | Improvement: 8 | - improve array performance by avoiding unnecessary closure reference 9 | 10 | # 0.1.3 - 14 Mar 2025 11 | Bug fix: 12 | - support `t.Module`, `t.Ref` 13 | 14 | # 0.1.2 - 4 Mar 2025 15 | Bug fix: 16 | - handle primitive type when array is root 17 | 18 | # 0.1.1 - 4 Mar 2025 19 | Feature: 20 | - support Record 21 | 22 | Improvement: 23 | - add Tuple test case 24 | 25 | # 0.1.0 - 5 Feb 2025 26 | Feature: 27 | - replace `arrayItems.join('",\"')` in favour of inline `joinStringArray` to improve performance 28 | - add `sanitize` option for handling unsafe character 29 | - new behavior is `sanitize`, previously is equivalent to `manual` 30 | - support inline a literal value 31 | 32 | # 0.0.2 - 4 Feb 2025 33 | Feature: 34 | - support integer, bigint, date, datetime 35 | - support `default` value for optional, and nullable on primitive type 36 | 37 | Improvement: 38 | - refactor properties instruction generation 39 | - flatten optional properties to speed up runtime performance in Bun 40 | - remove negate where possible in runtime 41 | - use stringified null to prevent `toString()` call 42 | 43 | Bug fix: 44 | - `integer` is using `JSON.stringify` 45 | 46 | # 0.0.1 - 3 Feb 2025 47 | Bug fix: 48 | - separate optional comma flag between closure 49 | 50 | # 0.0.0 - 3 Feb 2025 51 | Feature: 52 | - initial release 53 | -------------------------------------------------------------------------------- /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 | # JSON Accelerator 2 | 3 | Accelerate JSON stringification by providing OpenAPI/TypeBox model. 4 | 5 | By providing model ahead of time, the library will generate a function that will serialize the object into a JSON string. 6 | 7 | ``` 8 | $ npx tsx benchmarks/medium-manual.ts 9 | 10 | clk: ~3.02 GHz 11 | cpu: Apple M1 Max 12 | runtime: node 22.6.0 (arm64-darwin) 13 | 14 | summary 15 | JSON Accelerator 16 | 2.12x faster than JSON Stingify 17 | 2.66x faster than Fast Json Stringify 18 | ``` 19 | 20 | ## Installation 21 | 22 | ```bash 23 | # Using either one of the package manager 24 | npm install json-accelerator 25 | yarn add json-accelerator 26 | pnpm add json-accelerator 27 | bun add json-accelerator 28 | ``` 29 | 30 | ## Usage 31 | 32 | It is designed to be used with [TypeBox](https://github.com/sinclairzx81/typebox) but an OpenAPI schema should also work. 33 | 34 | ```typescript 35 | import { Type as t } from '@sinclair/typebox' 36 | import { createAccelerator } from 'json-accelerator' 37 | 38 | const shape = t.Object({ 39 | name: t.String(), 40 | id: t.Number() 41 | }) 42 | 43 | const value = { 44 | id: 0, 45 | name: 'saltyaom' 46 | } satisfies typeof shape.static 47 | 48 | const encode = createAccelerator(shape) 49 | 50 | console.log(encode(value)) // {"id":0,"name":"saltyaom"} 51 | ``` 52 | 53 | ## Caveat 54 | 55 | This library **WILL NOT** check for the type validity of the schema, it is expected that the schema is **always** correct. 56 | 57 | This can be achieved by checking the input validity with TypeBox before passing it to the accelerator. 58 | 59 | ```typescript 60 | import { Type as t } from '@sinclair/typebox' 61 | import { TypeCompiler } from '@sinclair/typebox/compiler' 62 | import { createAccelerator } from 'json-accelerator' 63 | 64 | const shape = t.Object({ 65 | name: t.String(), 66 | id: t.Number() 67 | }) 68 | 69 | const value = { 70 | id: 0, 71 | name: 'saltyaom' 72 | } 73 | 74 | const guard = TypeCompiler.Compile(shape) 75 | const encode = createAccelerator(shape) 76 | 77 | if (guard.Check(value)) encode(value) 78 | ``` 79 | 80 | If the shape is incorrect, the output will try to corece the value into an expected model but if failed the error will be thrown. 81 | 82 | ## Options 83 | 84 | This section is used to configure the behavior of the encoder. 85 | 86 | `Options` can be passed as a second argument to `createAccelerator`. 87 | 88 | ```ts 89 | createAccelerator(shape, { 90 | unsafe: 'throw' 91 | }) 92 | ``` 93 | 94 | ## Unsafe 95 | 96 | If unsafe character is found, how should the encoder handle it? 97 | 98 | This value only applied to string field. 99 | 100 | - `'auto'`: Sanitize the string and continue encoding 101 | - `'manual'`: Ignore the unsafe character, this implied that end user should specify fields that should be sanitized manually 102 | - `'throw'`: Throw an error 103 | 104 | The default behavior is `auto`. 105 | 106 | ### format sanitize 107 | 108 | Since this library is designed for a controlled environment (eg. Restful API), most fields are controlled by end user which doesn't include unsafe characters for JSON encoding. 109 | 110 | We can improve performance by specifying a `sanitize: 'manual'` and provide a field that should be sanitized manually. 111 | 112 | We can add `sanitize: true` to a schema which is an uncontrolled field submit by user that might contains unsafe characters. 113 | 114 | When a field is marked as `sanitize`, the encoder will sanitize the string and continue encoding regardless of the `unsafe` configuration. 115 | 116 | ```ts 117 | import { Type as t } from '@sinclair/typebox' 118 | import { createAccelerator } from 'json-accelerator' 119 | 120 | const shape = t.Object({ 121 | name: t.String(), 122 | id: t.Number(), 123 | unknown: t.String({ sanitize: true }) 124 | }) 125 | 126 | const value = { 127 | id: 0, 128 | name: 'saltyaom', 129 | unknown: `hello\nworld` 130 | } satisfies typeof shape.static 131 | 132 | const encode = createAccelerator(shape, { 133 | sanitize: 'manual' 134 | }) 135 | 136 | console.log(encode(value)) // {"id":0,"name":"saltyaom","unknown":"hello\\nworld"} 137 | ``` 138 | 139 | This allows us to speed up a hardcode 140 | -------------------------------------------------------------------------------- /benchmarks/array.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Object({ 6 | ids: t.Array(t.Number()), 7 | names: t.Array(t.String()), 8 | games: t.Array( 9 | t.Object({ 10 | name: t.String(), 11 | tags: t.Array(t.String()) 12 | }) 13 | ) 14 | }), 15 | { 16 | ids: [1, 2, 3], 17 | names: ['SaltyAom', 'SaltyAom', 'SaltyAom'], 18 | games: [ 19 | { 20 | name: 'MiSide', 21 | tags: ['Psychological Horror', 'Cute', 'Dating Sim'] 22 | }, 23 | { 24 | name: 'Strinova', 25 | tags: ['Free to Play', 'Anime', 'Third-Person Shooter'] 26 | }, 27 | { 28 | name: "Tom Clancy's Rainbow Six Siege", 29 | tags: ['FPS', 'Multiplayer', 'Tactical'] 30 | } 31 | ] 32 | } 33 | ) 34 | -------------------------------------------------------------------------------- /benchmarks/large-manual.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * *-manual.ts is where end user specifiy which fields should be sanitized manually 3 | **/ 4 | 5 | import { t } from 'elysia' 6 | import { benchmark } from './utils' 7 | 8 | benchmark( 9 | t.Array( 10 | t.Object({ 11 | id: t.Number(), 12 | name: t.String(), 13 | bio: t.String({ 14 | sanitize: true 15 | }), 16 | user: t.Object({ 17 | name: t.String(), 18 | password: t.String(), 19 | email: t.Optional(t.String({ format: 'email' })), 20 | age: t.Optional(t.Number()), 21 | avatar: t.Optional(t.String({ format: 'uri' })), 22 | cover: t.Optional(t.String({ format: 'uri' })) 23 | }), 24 | playing: t.Optional(t.String()), 25 | wishlist: t.Optional(t.Array(t.Number())), 26 | games: t.Array( 27 | t.Object({ 28 | id: t.Number(), 29 | name: t.String(), 30 | hoursPlay: t.Optional(t.Number({ default: 0 })), 31 | tags: t.Array( 32 | t.Object({ 33 | name: t.String(), 34 | count: t.Number() 35 | }) 36 | ) 37 | }) 38 | ), 39 | metadata: t.Intersect([ 40 | t.Object({ 41 | alias: t.String() 42 | }), 43 | t.Object({ 44 | country: t.Nullable(t.String()), 45 | region: t.Optional(t.String()) 46 | }) 47 | ]), 48 | social: t.Optional( 49 | t.Object({ 50 | facebook: t.Optional(t.String()), 51 | twitter: t.Optional(t.String()), 52 | youtube: t.Optional(t.String()) 53 | }) 54 | ) 55 | }) 56 | ), 57 | [ 58 | { 59 | id: 1, 60 | name: 'SaltyAom', 61 | bio: 'I like train\n', 62 | user: { 63 | name: 'SaltyAom', 64 | password: '123456', 65 | avatar: 'https://avatars.githubusercontent.com/u/35027979?v=4', 66 | cover: 'https://saltyaom.com/cosplay/pekomama.webp' 67 | }, 68 | playing: 'Strinova', 69 | wishlist: [4_154_456, 2_345_345], 70 | games: [ 71 | { 72 | id: 4_154_456, 73 | name: 'MiSide', 74 | hoursPlay: 17, 75 | tags: [ 76 | { name: 'Psychological Horror', count: 236_432 }, 77 | { name: 'Cute', count: 495_439 }, 78 | { name: 'Dating Sim', count: 395_532 } 79 | ] 80 | }, 81 | { 82 | id: 4_356_345, 83 | name: 'Strinova', 84 | hoursPlay: 365, 85 | tags: [ 86 | { name: 'Free to Play', count: 205_593 }, 87 | { name: 'Anime', count: 504_304 }, 88 | { name: 'Third-Person Shooter', count: 395_532 } 89 | ] 90 | }, 91 | { 92 | id: 2_345_345, 93 | name: "Tom Clancy's Rainbow Six Siege", 94 | hoursPlay: 287, 95 | tags: [ 96 | { name: 'FPS', count: 855_324 }, 97 | { name: 'Multiplayer', count: 456_567 }, 98 | { name: 'Tactical', count: 544_467 } 99 | ] 100 | } 101 | ], 102 | metadata: { 103 | alias: 'SaltyAom', 104 | country: 'Thailand', 105 | region: 'Asia' 106 | }, 107 | social: { 108 | twitter: 'SaltyAom' 109 | } 110 | }, 111 | { 112 | id: 2, 113 | name: 'VLost', 114 | bio: 'ไม่พี่คืองี้\n', 115 | user: { 116 | name: 'nattapon_kub', 117 | password: '123456' 118 | }, 119 | games: [ 120 | { 121 | id: 4_154_456, 122 | name: 'MiSide', 123 | hoursPlay: 17, 124 | tags: [ 125 | { name: 'Psychological Horror', count: 236_432 }, 126 | { name: 'Cute', count: 495_439 }, 127 | { name: 'Dating Sim', count: 395_532 } 128 | ] 129 | }, 130 | { 131 | id: 4_356_345, 132 | name: 'Strinova', 133 | hoursPlay: 365, 134 | tags: [ 135 | { name: 'Free to Play', count: 205_593 }, 136 | { name: 'Anime', count: 504_304 }, 137 | { name: 'Third-Person Shooter', count: 395_532 } 138 | ] 139 | } 140 | ], 141 | metadata: { 142 | alias: 'vlost', 143 | country: 'Thailand' 144 | } 145 | }, 146 | { 147 | id: 2, 148 | name: 'eika', 149 | bio: 'こんにちわ!', 150 | user: { 151 | name: 'ei_ka', 152 | password: '123456' 153 | }, 154 | games: [ 155 | { 156 | id: 4_356_345, 157 | name: 'Strinova', 158 | hoursPlay: 365, 159 | tags: [ 160 | { name: 'Free to Play', count: 205_593 }, 161 | { name: 'Anime', count: 504_304 }, 162 | { name: 'Third-Person Shooter', count: 395_532 } 163 | ] 164 | } 165 | ], 166 | metadata: { 167 | alias: 'eika', 168 | country: 'Japan' 169 | } 170 | } 171 | ], 172 | { 173 | sanitize: 'manual' 174 | } 175 | ) 176 | -------------------------------------------------------------------------------- /benchmarks/large.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Array( 6 | t.Object({ 7 | id: t.Number(), 8 | name: t.String(), 9 | bio: t.String(), 10 | user: t.Object({ 11 | name: t.String(), 12 | password: t.String(), 13 | email: t.Optional(t.String()), 14 | age: t.Optional(t.Number()), 15 | avatar: t.Optional(t.String()), 16 | cover: t.Optional(t.String()) 17 | }), 18 | playing: t.Optional(t.String()), 19 | wishlist: t.Optional(t.Array(t.Number())), 20 | games: t.Array( 21 | t.Object({ 22 | id: t.Number(), 23 | name: t.String(), 24 | hoursPlay: t.Optional(t.Number({ default: 0 })), 25 | tags: t.Array( 26 | t.Object({ 27 | name: t.String(), 28 | count: t.Number() 29 | }) 30 | ) 31 | }) 32 | ), 33 | metadata: t.Intersect([ 34 | t.Object({ 35 | alias: t.String() 36 | }), 37 | t.Object({ 38 | country: t.Nullable(t.String()), 39 | region: t.Optional(t.String()) 40 | }) 41 | ]), 42 | social: t.Optional( 43 | t.Object({ 44 | facebook: t.Optional(t.String()), 45 | twitter: t.Optional(t.String()), 46 | youtube: t.Optional(t.String()) 47 | }) 48 | ) 49 | }) 50 | ), 51 | [ 52 | { 53 | id: 1, 54 | name: 'SaltyAom', 55 | bio: 'I like train', 56 | user: { 57 | name: 'SaltyAom', 58 | password: '123456', 59 | avatar: 'https://avatars.githubusercontent.com/u/35027979?v=4', 60 | cover: 'https://saltyaom.com/cosplay/pekomama.webp' 61 | }, 62 | playing: 'Strinova', 63 | wishlist: [4_154_456, 2_345_345], 64 | games: [ 65 | { 66 | id: 4_154_456, 67 | name: 'MiSide', 68 | hoursPlay: 17, 69 | tags: [ 70 | { name: 'Psychological Horror', count: 236_432 }, 71 | { name: 'Cute', count: 495_439 }, 72 | { name: 'Dating Sim', count: 395_532 } 73 | ] 74 | }, 75 | { 76 | id: 4_356_345, 77 | name: 'Strinova', 78 | hoursPlay: 365, 79 | tags: [ 80 | { name: 'Free to Play', count: 205_593 }, 81 | { name: 'Anime', count: 504_304 }, 82 | { name: 'Third-Person Shooter', count: 395_532 } 83 | ] 84 | }, 85 | { 86 | id: 2_345_345, 87 | name: "Tom Clancy's Rainbow Six Siege", 88 | hoursPlay: 287, 89 | tags: [ 90 | { name: 'FPS', count: 855_324 }, 91 | { name: 'Multiplayer', count: 456_567 }, 92 | { name: 'Tactical', count: 544_467 } 93 | ] 94 | } 95 | ], 96 | metadata: { 97 | alias: 'SaltyAom', 98 | country: 'Thailand', 99 | region: 'Asia' 100 | }, 101 | social: { 102 | twitter: 'SaltyAom' 103 | } 104 | }, 105 | { 106 | id: 2, 107 | name: 'VLost', 108 | bio: 'ไม่พี่คืองี้', 109 | user: { 110 | name: 'nattapon_kub', 111 | password: '123456' 112 | }, 113 | games: [ 114 | { 115 | id: 4_154_456, 116 | name: 'MiSide', 117 | hoursPlay: 17, 118 | tags: [ 119 | { name: 'Psychological Horror', count: 236_432 }, 120 | { name: 'Cute', count: 495_439 }, 121 | { name: 'Dating Sim', count: 395_532 } 122 | ] 123 | }, 124 | { 125 | id: 4_356_345, 126 | name: 'Strinova', 127 | hoursPlay: 365, 128 | tags: [ 129 | { name: 'Free to Play', count: 205_593 }, 130 | { name: 'Anime', count: 504_304 }, 131 | { name: 'Third-Person Shooter', count: 395_532 } 132 | ] 133 | } 134 | ], 135 | metadata: { 136 | alias: 'vlost', 137 | country: 'Thailand' 138 | } 139 | }, 140 | { 141 | id: 2, 142 | name: 'eika', 143 | bio: 'こんにちわ!', 144 | user: { 145 | name: 'ei_ka', 146 | password: '123456' 147 | }, 148 | games: [ 149 | { 150 | id: 4_356_345, 151 | name: 'Strinova', 152 | hoursPlay: 365, 153 | tags: [ 154 | { name: 'Free to Play', count: 205_593 }, 155 | { name: 'Anime', count: 504_304 }, 156 | { name: 'Third-Person Shooter', count: 395_532 } 157 | ] 158 | } 159 | ], 160 | metadata: { 161 | alias: 'eika', 162 | country: 'Japan' 163 | } 164 | } 165 | ] 166 | ) 167 | -------------------------------------------------------------------------------- /benchmarks/medium-manual.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * *-manual.ts is where end user specifiy which fields should be sanitized manually 3 | **/ 4 | 5 | import { t } from 'elysia' 6 | import { benchmark } from './utils' 7 | 8 | benchmark( 9 | t.Object({ 10 | id: t.Number(), 11 | name: t.Literal('SaltyAom'), 12 | bio: t.String({ 13 | sanitize: true 14 | }), 15 | user: t.Object({ 16 | name: t.String(), 17 | password: t.String() 18 | }), 19 | playing: t.Optional(t.String()), 20 | games: t.Array( 21 | t.Object({ 22 | name: t.String(), 23 | hoursPlay: t.Number({ default: 0 }), 24 | tags: t.Array(t.String()) 25 | }) 26 | ), 27 | metadata: t.Intersect([ 28 | t.Object({ 29 | alias: t.String() 30 | }), 31 | t.Object({ 32 | country: t.Nullable(t.String()) 33 | }) 34 | ]), 35 | social: t.Optional( 36 | t.Object({ 37 | facebook: t.Optional(t.String()), 38 | twitter: t.Optional(t.String()), 39 | youtube: t.Optional(t.String()) 40 | }) 41 | ) 42 | }), 43 | { 44 | id: 1, 45 | name: 'SaltyAom', 46 | bio: 'I like train\n', 47 | user: { 48 | name: 'SaltyAom', 49 | password: '123456' 50 | }, 51 | games: [ 52 | { 53 | name: 'MiSide', 54 | hoursPlay: 17, 55 | tags: ['Psychological Horror', 'Cute', 'Dating Sim'] 56 | }, 57 | { 58 | name: 'Strinova', 59 | hoursPlay: 365, 60 | tags: ['Free to Play', 'Anime', 'Third-Person Shooter'] 61 | }, 62 | { 63 | name: "Tom Clancy's Rainbow Six Siege", 64 | hoursPlay: 287, 65 | tags: ['FPS', 'Multiplayer', 'Tactical'] 66 | } 67 | ], 68 | metadata: { 69 | alias: 'SaltyAom', 70 | country: 'Thailand' 71 | }, 72 | social: { 73 | twitter: 'SaltyAom' 74 | } 75 | }, 76 | { 77 | sanitize: 'manual' 78 | } 79 | ) 80 | -------------------------------------------------------------------------------- /benchmarks/medium.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Object({ 6 | id: t.Number(), 7 | name: t.Literal('SaltyAom'), 8 | bio: t.String({ 9 | sanitize: true 10 | }), 11 | user: t.Object({ 12 | name: t.String(), 13 | password: t.String() 14 | }), 15 | playing: t.Optional(t.String()), 16 | games: t.Array( 17 | t.Object({ 18 | name: t.String(), 19 | hoursPlay: t.Number({ default: 0 }), 20 | tags: t.Array(t.String()) 21 | }) 22 | ), 23 | metadata: t.Intersect([ 24 | t.Object({ 25 | alias: t.String() 26 | }), 27 | t.Object({ 28 | country: t.Nullable(t.String()) 29 | }) 30 | ]), 31 | social: t.Optional( 32 | t.Object({ 33 | facebook: t.Optional(t.String()), 34 | twitter: t.Optional(t.String()), 35 | youtube: t.Optional(t.String()) 36 | }) 37 | ) 38 | }), 39 | { 40 | id: 1, 41 | name: 'SaltyAom', 42 | bio: 'I like train\nhere', 43 | user: { 44 | name: 'SaltyAom', 45 | password: '123456' 46 | }, 47 | games: [ 48 | { 49 | name: 'MiSide', 50 | hoursPlay: 17, 51 | tags: ['Psychological Horror', 'Cute', 'Dating Sim'] 52 | }, 53 | { 54 | name: 'Strinova', 55 | hoursPlay: 365, 56 | tags: ['Free to Play', 'Anime', 'Third-Person Shooter'] 57 | }, 58 | { 59 | name: "Tom Clancy's Rainbow Six Siege", 60 | hoursPlay: 287, 61 | tags: ['FPS', 'Multiplayer', 'Tactical'] 62 | } 63 | ], 64 | metadata: { 65 | alias: 'SaltyAom', 66 | country: 'Thailand' 67 | }, 68 | social: { 69 | twitter: 'SaltyAom' 70 | } 71 | } 72 | ) 73 | -------------------------------------------------------------------------------- /benchmarks/message.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Object({ 6 | message: t.String({ 7 | trusted: true 8 | }) 9 | }), 10 | { message: 'Hello, World!' as const } 11 | ) 12 | -------------------------------------------------------------------------------- /benchmarks/multiple-queries.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Array( 6 | t.Object({ 7 | id: t.Number(), 8 | randomNumber: t.Number() 9 | }) 10 | ), 11 | [ 12 | { id: 4174, randomNumber: 331 }, 13 | { id: 51, randomNumber: 6544 }, 14 | { id: 4462, randomNumber: 952 }, 15 | { id: 2221, randomNumber: 532 }, 16 | { id: 9276, randomNumber: 3097 }, 17 | { id: 3056, randomNumber: 7293 }, 18 | { id: 6964, randomNumber: 620 }, 19 | { id: 675, randomNumber: 6601 }, 20 | { id: 8414, randomNumber: 6569 }, 21 | { id: 2753, randomNumber: 4065 } 22 | ] 23 | ) 24 | -------------------------------------------------------------------------------- /benchmarks/quote.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Object({ 6 | id: t.String({ 7 | format: 'input' 8 | }), 9 | name: t.String() 10 | }), 11 | { 12 | id: '\n', 13 | name: 'SaltyAom' 14 | } 15 | ) 16 | -------------------------------------------------------------------------------- /benchmarks/small-manual.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * *-manual.ts is where end user specifiy which fields should be sanitized manually 3 | **/ 4 | 5 | import { t } from 'elysia' 6 | import { benchmark } from './utils' 7 | 8 | benchmark( 9 | t.Object({ 10 | id: t.Number(), 11 | name: t.String(), 12 | bio: t.String({ 13 | sanitize: true 14 | }), 15 | metadata: t.Object({ 16 | alias: t.String(), 17 | country: t.String() 18 | }) 19 | }), 20 | { 21 | id: 1, 22 | name: 'SaltyAom', 23 | bio: 'I like train\n', 24 | metadata: { 25 | alias: 'SaltyAom', 26 | country: 'Thailand' 27 | } 28 | }, 29 | { 30 | sanitize: 'manual' 31 | } 32 | ) 33 | -------------------------------------------------------------------------------- /benchmarks/small.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Object({ 6 | id: t.Number(), 7 | name: t.String(), 8 | bio: t.String(), 9 | metadata: t.Object({ 10 | alias: t.String(), 11 | country: t.String() 12 | }) 13 | }), 14 | { 15 | id: 1, 16 | name: 'SaltyAom', 17 | bio: 'I like train', 18 | metadata: { 19 | alias: 'SaltyAom', 20 | country: 'Thailand' 21 | } 22 | } 23 | ) 24 | -------------------------------------------------------------------------------- /benchmarks/small2.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { benchmark } from './utils' 3 | 4 | benchmark( 5 | t.Array( 6 | t.Object({ 7 | name: t.String(), 8 | pwd: t.String(), 9 | id: t.Array(t.Number()) 10 | }) 11 | ), 12 | [ 13 | { 14 | name: 'SaltyAom', 15 | pwd: 'password', 16 | id: [1, 2, 3] 17 | }, 18 | { 19 | name: 'JohnDoe', 20 | pwd: 'password', 21 | id: [4, 5, 6] 22 | }, 23 | { 24 | name: 'JaneDoe', 25 | pwd: 'password', 26 | id: [7, 8, 9] 27 | } 28 | ] 29 | ) 30 | -------------------------------------------------------------------------------- /benchmarks/utils.ts: -------------------------------------------------------------------------------- 1 | import { bench, run, barplot, summary, compact } from 'mitata' 2 | 3 | import { createAccelerator } from '../src' 4 | import { TypeCompiler } from '@sinclair/typebox/compiler' 5 | import fastJson from 'fast-json-stringify' 6 | 7 | import type { TAnySchema } from '@sinclair/typebox' 8 | 9 | export const benchmark = ( 10 | model: T, 11 | value: T['static'], 12 | options?: Parameters[1] 13 | ) => { 14 | const fastJsonStringify = fastJson(model) 15 | const encode = createAccelerator(model, options) 16 | 17 | if (process.env.DEBUG) { 18 | console.log(encode.toString()) 19 | } 20 | 21 | if (encode(value) !== JSON.stringify(value)) { 22 | console.log(encode(value)) 23 | console.log('---') 24 | console.log(encode.toString()) 25 | throw new Error('Invalid result') 26 | } 27 | 28 | compact(() => { 29 | barplot(() => { 30 | summary(() => { 31 | bench('JSON Stingify', () => { 32 | return JSON.stringify(value) 33 | }) 34 | 35 | bench('Fast Json Stringify', () => { 36 | return fastJsonStringify(value) 37 | }) 38 | 39 | bench('JSON Accelerator', () => { 40 | return encode(value) 41 | }) 42 | 43 | const validator = TypeCompiler.Compile(model) 44 | 45 | bench('JSON Accelerator w/ validation', () => { 46 | validator.Check(value) 47 | 48 | return encode(value) 49 | }) 50 | }) 51 | }) 52 | }) 53 | 54 | run() 55 | } 56 | -------------------------------------------------------------------------------- /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": "json-accelerator", 6 | "devDependencies": { 7 | "@types/bun": "1.2.2", 8 | "elysia": "^1.2.11", 9 | "eslint": "9.6.0", 10 | "fast-json-stringify": "^6.0.1", 11 | "mitata": "^1.0.33", 12 | "tsup": "^8.1.0", 13 | "tsx": "^4.19.2", 14 | "typescript": "^5.5.3", 15 | }, 16 | "peerDependencies": { 17 | "@sinclair/typebox": "^0.34.31", 18 | }, 19 | "optionalPeers": [ 20 | "@sinclair/typebox", 21 | ], 22 | }, 23 | }, 24 | "packages": { 25 | "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ=="], 26 | 27 | "@esbuild/android-arm": ["@esbuild/android-arm@0.25.1", "", { "os": "android", "cpu": "arm" }, "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q=="], 28 | 29 | "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.1", "", { "os": "android", "cpu": "arm64" }, "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA=="], 30 | 31 | "@esbuild/android-x64": ["@esbuild/android-x64@0.25.1", "", { "os": "android", "cpu": "x64" }, "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw=="], 32 | 33 | "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ=="], 34 | 35 | "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA=="], 36 | 37 | "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A=="], 38 | 39 | "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww=="], 40 | 41 | "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.1", "", { "os": "linux", "cpu": "arm" }, "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ=="], 42 | 43 | "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ=="], 44 | 45 | "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.1", "", { "os": "linux", "cpu": "ia32" }, "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ=="], 46 | 47 | "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg=="], 48 | 49 | "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg=="], 50 | 51 | "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg=="], 52 | 53 | "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.1", "", { "os": "linux", "cpu": "none" }, "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ=="], 54 | 55 | "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ=="], 56 | 57 | "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.1", "", { "os": "linux", "cpu": "x64" }, "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA=="], 58 | 59 | "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.1", "", { "os": "none", "cpu": "arm64" }, "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g=="], 60 | 61 | "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.1", "", { "os": "none", "cpu": "x64" }, "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA=="], 62 | 63 | "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.1", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg=="], 64 | 65 | "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw=="], 66 | 67 | "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.1", "", { "os": "sunos", "cpu": "x64" }, "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg=="], 68 | 69 | "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ=="], 70 | 71 | "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A=="], 72 | 73 | "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.1", "", { "os": "win32", "cpu": "x64" }, "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg=="], 74 | 75 | "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.5.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w=="], 76 | 77 | "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], 78 | 79 | "@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=="], 80 | 81 | "@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=="], 82 | 83 | "@eslint/js": ["@eslint/js@9.6.0", "", {}, "sha512-D9B0/3vNg44ZeWbYMpBoXqNP4j6eQD5vNwIlGAuFRRzK/WtT/jvDQW3Bi9kkf3PMDMlM7Yi+73VLUsn5bJcl8A=="], 84 | 85 | "@eslint/object-schema": ["@eslint/object-schema@2.1.6", "", {}, "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA=="], 86 | 87 | "@fastify/merge-json-schemas": ["@fastify/merge-json-schemas@0.2.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A=="], 88 | 89 | "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], 90 | 91 | "@humanwhocodes/retry": ["@humanwhocodes/retry@0.3.1", "", {}, "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA=="], 92 | 93 | "@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=="], 94 | 95 | "@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=="], 96 | 97 | "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 98 | 99 | "@jridgewell/set-array": ["@jridgewell/set-array@1.2.1", "", {}, "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="], 100 | 101 | "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], 102 | 103 | "@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=="], 104 | 105 | "@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=="], 106 | 107 | "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], 108 | 109 | "@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=="], 110 | 111 | "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], 112 | 113 | "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.37.0", "", { "os": "android", "cpu": "arm" }, "sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ=="], 114 | 115 | "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.37.0", "", { "os": "android", "cpu": "arm64" }, "sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA=="], 116 | 117 | "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.37.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA=="], 118 | 119 | "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.37.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ=="], 120 | 121 | "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.37.0", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA=="], 122 | 123 | "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.37.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA=="], 124 | 125 | "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w=="], 126 | 127 | "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.37.0", "", { "os": "linux", "cpu": "arm" }, "sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag=="], 128 | 129 | "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA=="], 130 | 131 | "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.37.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ=="], 132 | 133 | "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA=="], 134 | 135 | "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.37.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ=="], 136 | 137 | "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw=="], 138 | 139 | "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.37.0", "", { "os": "linux", "cpu": "none" }, "sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA=="], 140 | 141 | "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.37.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A=="], 142 | 143 | "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ=="], 144 | 145 | "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.37.0", "", { "os": "linux", "cpu": "x64" }, "sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w=="], 146 | 147 | "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.37.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg=="], 148 | 149 | "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.37.0", "", { "os": "win32", "cpu": "ia32" }, "sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA=="], 150 | 151 | "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.37.0", "", { "os": "win32", "cpu": "x64" }, "sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA=="], 152 | 153 | "@sinclair/typebox": ["@sinclair/typebox@0.34.31", "", {}, "sha512-qQ71T9DsITbX3dVCrcBERbs11YuSMg3wZPnT472JhqhWGPdiLgyvihJXU8m+ADJtJvRdjATIiACJD22dEknBrQ=="], 154 | 155 | "@types/bun": ["@types/bun@1.2.2", "", { "dependencies": { "bun-types": "1.2.2" } }, "sha512-tr74gdku+AEDN5ergNiBnplr7hpDp3V1h7fqI2GcR/rsUaM39jpSeKH0TFibRvU0KwniRx5POgaYnaXbk0hU+w=="], 156 | 157 | "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], 158 | 159 | "@types/node": ["@types/node@22.13.14", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w=="], 160 | 161 | "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="], 162 | 163 | "acorn": ["acorn@8.14.1", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg=="], 164 | 165 | "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], 166 | 167 | "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=="], 168 | 169 | "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], 170 | 171 | "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 172 | 173 | "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 174 | 175 | "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], 176 | 177 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], 178 | 179 | "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], 180 | 181 | "brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="], 182 | 183 | "bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="], 184 | 185 | "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="], 186 | 187 | "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], 188 | 189 | "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], 190 | 191 | "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 192 | 193 | "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], 194 | 195 | "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 196 | 197 | "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 198 | 199 | "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], 200 | 201 | "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], 202 | 203 | "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], 204 | 205 | "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], 206 | 207 | "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], 208 | 209 | "debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="], 210 | 211 | "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], 212 | 213 | "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], 214 | 215 | "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], 216 | 217 | "elysia": ["elysia@1.2.25", "", { "dependencies": { "@sinclair/typebox": "^0.34.27", "cookie": "^1.0.2", "memoirist": "^0.3.0", "openapi-types": "^12.1.3" }, "peerDependencies": { "typescript": ">= 5.0.0" }, "optionalPeers": ["typescript"] }, "sha512-WsdQpORJvb4uszzeqYT0lg97knw1iBW1NTzJ1Jm57tiHg+DfAotlWXYbjmvQ039ssV0fYELDHinLLoUazZkEHg=="], 218 | 219 | "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], 220 | 221 | "esbuild": ["esbuild@0.25.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", "@esbuild/android-arm64": "0.25.1", "@esbuild/android-x64": "0.25.1", "@esbuild/darwin-arm64": "0.25.1", "@esbuild/darwin-x64": "0.25.1", "@esbuild/freebsd-arm64": "0.25.1", "@esbuild/freebsd-x64": "0.25.1", "@esbuild/linux-arm": "0.25.1", "@esbuild/linux-arm64": "0.25.1", "@esbuild/linux-ia32": "0.25.1", "@esbuild/linux-loong64": "0.25.1", "@esbuild/linux-mips64el": "0.25.1", "@esbuild/linux-ppc64": "0.25.1", "@esbuild/linux-riscv64": "0.25.1", "@esbuild/linux-s390x": "0.25.1", "@esbuild/linux-x64": "0.25.1", "@esbuild/netbsd-arm64": "0.25.1", "@esbuild/netbsd-x64": "0.25.1", "@esbuild/openbsd-arm64": "0.25.1", "@esbuild/openbsd-x64": "0.25.1", "@esbuild/sunos-x64": "0.25.1", "@esbuild/win32-arm64": "0.25.1", "@esbuild/win32-ia32": "0.25.1", "@esbuild/win32-x64": "0.25.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ=="], 222 | 223 | "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], 224 | 225 | "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=="], 226 | 227 | "eslint-scope": ["eslint-scope@8.3.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ=="], 228 | 229 | "eslint-visitor-keys": ["eslint-visitor-keys@4.2.0", "", {}, "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw=="], 230 | 231 | "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=="], 232 | 233 | "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], 234 | 235 | "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], 236 | 237 | "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], 238 | 239 | "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], 240 | 241 | "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], 242 | 243 | "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], 244 | 245 | "fast-json-stringify": ["fast-json-stringify@6.0.1", "", { "dependencies": { "@fastify/merge-json-schemas": "^0.2.0", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0", "json-schema-ref-resolver": "^2.0.0", "rfdc": "^1.2.0" } }, "sha512-s7SJE83QKBZwg54dIbD5rCtzOBVD43V1ReWXXYqBgwCwHLYAAT0RQc/FmrQglXqWPpz6omtryJQOau5jI4Nrvg=="], 246 | 247 | "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], 248 | 249 | "fast-uri": ["fast-uri@3.0.6", "", {}, "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw=="], 250 | 251 | "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], 252 | 253 | "fdir": ["fdir@6.4.3", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw=="], 254 | 255 | "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], 256 | 257 | "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], 258 | 259 | "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], 260 | 261 | "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], 262 | 263 | "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], 264 | 265 | "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 266 | 267 | "get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="], 268 | 269 | "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=="], 270 | 271 | "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], 272 | 273 | "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], 274 | 275 | "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], 276 | 277 | "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], 278 | 279 | "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], 280 | 281 | "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], 282 | 283 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 284 | 285 | "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], 286 | 287 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 288 | 289 | "is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="], 290 | 291 | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 292 | 293 | "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], 294 | 295 | "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], 296 | 297 | "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], 298 | 299 | "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], 300 | 301 | "json-schema-ref-resolver": ["json-schema-ref-resolver@2.0.1", "", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-HG0SIB9X4J8bwbxCbnd5FfPEbcXAJYTi1pBJeP/QPON+w8ovSME8iRG+ElHNxZNX2Qh6eYn1GdzJFS4cDFfx0Q=="], 302 | 303 | "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], 304 | 305 | "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], 306 | 307 | "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], 308 | 309 | "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], 310 | 311 | "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], 312 | 313 | "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], 314 | 315 | "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="], 316 | 317 | "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], 318 | 319 | "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], 320 | 321 | "lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="], 322 | 323 | "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], 324 | 325 | "memoirist": ["memoirist@0.3.0", "", {}, "sha512-wR+4chMgVPq+T6OOsk40u9Wlpw1Pjx66NMNiYxCQQ4EUJ7jDs3D9kTCeKdBOkvAiqXlHLVJlvYL01PvIJ1MPNg=="], 326 | 327 | "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], 328 | 329 | "minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="], 330 | 331 | "mitata": ["mitata@1.0.34", "", {}, "sha512-Mc3zrtNBKIMeHSCQ0XqRLo1vbdIx1wvFV9c8NJAiyho6AjNfMY8bVhbS12bwciUdd1t4rj8099CH3N3NFahaUA=="], 332 | 333 | "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 334 | 335 | "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=="], 336 | 337 | "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], 338 | 339 | "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], 340 | 341 | "openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], 342 | 343 | "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=="], 344 | 345 | "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], 346 | 347 | "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], 348 | 349 | "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], 350 | 351 | "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], 352 | 353 | "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], 354 | 355 | "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], 356 | 357 | "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=="], 358 | 359 | "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 360 | 361 | "picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="], 362 | 363 | "pirates": ["pirates@4.0.6", "", {}, "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg=="], 364 | 365 | "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=="], 366 | 367 | "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], 368 | 369 | "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], 370 | 371 | "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], 372 | 373 | "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], 374 | 375 | "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], 376 | 377 | "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], 378 | 379 | "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], 380 | 381 | "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], 382 | 383 | "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], 384 | 385 | "rollup": ["rollup@4.37.0", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.37.0", "@rollup/rollup-android-arm64": "4.37.0", "@rollup/rollup-darwin-arm64": "4.37.0", "@rollup/rollup-darwin-x64": "4.37.0", "@rollup/rollup-freebsd-arm64": "4.37.0", "@rollup/rollup-freebsd-x64": "4.37.0", "@rollup/rollup-linux-arm-gnueabihf": "4.37.0", "@rollup/rollup-linux-arm-musleabihf": "4.37.0", "@rollup/rollup-linux-arm64-gnu": "4.37.0", "@rollup/rollup-linux-arm64-musl": "4.37.0", "@rollup/rollup-linux-loongarch64-gnu": "4.37.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-gnu": "4.37.0", "@rollup/rollup-linux-riscv64-musl": "4.37.0", "@rollup/rollup-linux-s390x-gnu": "4.37.0", "@rollup/rollup-linux-x64-gnu": "4.37.0", "@rollup/rollup-linux-x64-musl": "4.37.0", "@rollup/rollup-win32-arm64-msvc": "4.37.0", "@rollup/rollup-win32-ia32-msvc": "4.37.0", "@rollup/rollup-win32-x64-msvc": "4.37.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg=="], 386 | 387 | "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], 388 | 389 | "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], 390 | 391 | "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], 392 | 393 | "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], 394 | 395 | "source-map": ["source-map@0.8.0-beta.0", "", { "dependencies": { "whatwg-url": "^7.0.0" } }, "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="], 396 | 397 | "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=="], 398 | 399 | "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=="], 400 | 401 | "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 402 | 403 | "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 404 | 405 | "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], 406 | 407 | "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=="], 408 | 409 | "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 410 | 411 | "text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], 412 | 413 | "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], 414 | 415 | "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], 416 | 417 | "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], 418 | 419 | "tinyglobby": ["tinyglobby@0.2.12", "", { "dependencies": { "fdir": "^6.4.3", "picomatch": "^4.0.2" } }, "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww=="], 420 | 421 | "tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="], 422 | 423 | "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], 424 | 425 | "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], 426 | 427 | "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=="], 428 | 429 | "tsx": ["tsx@4.19.3", "", { "dependencies": { "esbuild": "~0.25.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ=="], 430 | 431 | "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], 432 | 433 | "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], 434 | 435 | "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], 436 | 437 | "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], 438 | 439 | "webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], 440 | 441 | "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=="], 442 | 443 | "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], 444 | 445 | "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], 446 | 447 | "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=="], 448 | 449 | "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=="], 450 | 451 | "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], 452 | 453 | "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 454 | 455 | "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], 456 | 457 | "ajv-formats/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=="], 458 | 459 | "fast-json-stringify/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=="], 460 | 461 | "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], 462 | 463 | "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], 464 | 465 | "string-width/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], 466 | 467 | "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 468 | 469 | "wrap-ansi/ansi-styles": ["ansi-styles@6.2.1", "", {}, "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug=="], 470 | 471 | "wrap-ansi/strip-ansi": ["strip-ansi@7.1.0", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ=="], 472 | 473 | "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=="], 474 | 475 | "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], 476 | 477 | "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 478 | 479 | "fast-json-stringify/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 480 | 481 | "glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], 482 | 483 | "string-width/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], 484 | 485 | "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 486 | 487 | "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="], 488 | } 489 | } 490 | -------------------------------------------------------------------------------- /example/index.ts: -------------------------------------------------------------------------------- 1 | import { t } from 'elysia' 2 | import { createAccelerator } from '../src/index' 3 | 4 | const shape = t.Object({ 5 | message: t.String({ 6 | trusted: true 7 | }) 8 | }) 9 | 10 | const value = { 11 | message: 'a' 12 | } satisfies typeof shape.static 13 | 14 | const mirror = createAccelerator(shape) 15 | 16 | console.log(mirror(value)) 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-accelerator", 3 | "version": "0.1.5", 4 | "description": "Speed up JSON stringification by providing OpenAPI/TypeBox model", 5 | "license": "MIT", 6 | "scripts": { 7 | "dev": "bun run --watch example/index.ts", 8 | "test": "bun test && npm run test:node", 9 | "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", 10 | "build": "bun build.ts", 11 | "release": "npm run build && npm run test && npm publish --access public" 12 | }, 13 | "peerDependencies": { 14 | "@sinclair/typebox": ">= 0.34.0" 15 | }, 16 | "peerDependenciesMeta": { 17 | "@sinclair/typebox": { 18 | "optional": true 19 | } 20 | }, 21 | "devDependencies": { 22 | "@types/bun": "1.2.2", 23 | "elysia": "^1.2.11", 24 | "eslint": "9.6.0", 25 | "fast-json-stringify": "^6.0.1", 26 | "mitata": "^1.0.33", 27 | "tsup": "^8.1.0", 28 | "tsx": "^4.19.2", 29 | "typescript": "^5.5.3" 30 | }, 31 | "main": "./dist/cjs/index.js", 32 | "module": "./dist/index.mjs", 33 | "types": "./dist/index.d.ts", 34 | "exports": { 35 | "./package.json": "./package.json", 36 | ".": { 37 | "types": "./dist/index.d.ts", 38 | "import": "./dist/index.mjs", 39 | "require": "./dist/cjs/index.js" 40 | } 41 | }, 42 | "keywords": [ 43 | "elysia", 44 | "json", 45 | "stringify", 46 | "accelerator" 47 | ], 48 | "repository": { 49 | "type": "git", 50 | "url": "https://github.com/elysiajs/json-accelerator" 51 | }, 52 | "author": { 53 | "name": "saltyAom", 54 | "url": "https://github.com/SaltyAom", 55 | "email": "saltyaom@gmail.com" 56 | }, 57 | "homepage": "https://github.com/elysiajs/json-accelerator", 58 | "bugs": "https://github.com/elysiajs/json-accelerator/issues" 59 | } 60 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type { TAnySchema, TRecord } from '@sinclair/typebox' 2 | 3 | const Kind = Symbol.for('TypeBox.Kind') 4 | const OptionalKind = Symbol.for('TypeBox.Optional') 5 | 6 | const isSpecialProperty = (name: string) => /(\ |-|\t|\n)/.test(name) 7 | 8 | const joinProperty = (v1: string, v2: string | number) => { 9 | if (typeof v2 === 'number') return `${v1}[${v2}]` 10 | 11 | if (isSpecialProperty(v2)) return `${v1}["${v2}"]` 12 | 13 | return `${v1}.${v2}` 14 | } 15 | 16 | const encodeProperty = (v: string) => `"${v}"` 17 | 18 | const isInteger = (schema: TAnySchema) => { 19 | if (!schema.anyOf || (Kind in schema && schema[Kind] !== 'Union')) 20 | return false 21 | 22 | let hasIntegerFormat = false 23 | let hasNumberType = false 24 | 25 | for (const type of schema.anyOf) { 26 | if (type.type === 'null' || type.type === 'undefined') { 27 | continue 28 | } 29 | 30 | if ( 31 | !hasIntegerFormat && 32 | type.type === 'string' && 33 | type.format === 'integer' 34 | ) { 35 | hasIntegerFormat = true 36 | continue 37 | } 38 | 39 | if ( 40 | !hasNumberType && 41 | (type.type === 'number' || type.type === 'integer') 42 | ) { 43 | hasNumberType = true 44 | continue 45 | } 46 | 47 | return false 48 | } 49 | 50 | return hasIntegerFormat && hasNumberType 51 | } 52 | 53 | const getMetadata = (schema: TAnySchema) => { 54 | let isNullable = false 55 | let isUndefinable = false 56 | let newSchema 57 | 58 | if (!schema.anyOf || (Kind in schema && schema[Kind] !== 'Union')) 59 | return { 60 | schema, 61 | isNullable, 62 | isUndefinable 63 | } 64 | 65 | for (const type of schema.anyOf) { 66 | if (type.type === 'null') { 67 | isNullable = true 68 | continue 69 | } 70 | 71 | if (type.type === 'undefined') { 72 | isUndefinable = true 73 | continue 74 | } 75 | 76 | if (!newSchema) { 77 | newSchema = type 78 | continue 79 | } 80 | 81 | return { 82 | schema, 83 | isNullable, 84 | isUndefinable 85 | } 86 | } 87 | 88 | return { 89 | schema: newSchema, 90 | isNullable, 91 | isUndefinable 92 | } 93 | } 94 | 95 | export const mergeObjectIntersection = (schema: TAnySchema): TAnySchema => { 96 | if ( 97 | !schema.allOf || 98 | (Kind in schema && 99 | (schema[Kind] !== 'Intersect' || schema.type !== 'object')) 100 | ) 101 | return schema 102 | 103 | const { allOf, ...newSchema } = schema 104 | newSchema.properties = {} 105 | 106 | if (Kind in newSchema) newSchema[Kind as any] = 'Object' 107 | 108 | for (const type of allOf) { 109 | if (type.type !== 'object') continue 110 | 111 | const { properties, required, type: _, [Kind]: __, ...rest } = type 112 | 113 | if (required) 114 | newSchema.required = newSchema.required 115 | ? newSchema.required.concat(required) 116 | : required 117 | 118 | Object.assign(newSchema, rest) 119 | 120 | for (const property in type.properties) 121 | newSchema.properties[property] = mergeObjectIntersection( 122 | type.properties[property] 123 | ) 124 | } 125 | 126 | return newSchema 127 | } 128 | 129 | const isDateType = (schema: TAnySchema): boolean => { 130 | if (!schema.anyOf || (Kind in schema && schema[Kind] !== 'Union')) 131 | return false 132 | 133 | if (!schema.anyOf) return false 134 | 135 | let hasDateType = false 136 | let hasStringFormatDate = false 137 | let hasNumberType = false 138 | 139 | if (schema.anyOf) 140 | for (const type of schema.anyOf) { 141 | if (!hasDateType && type.type === 'Date') hasDateType = true 142 | 143 | if ( 144 | !hasStringFormatDate && 145 | type.type === 'string' && 146 | (type.format === 'date' || type.format === 'date-time') 147 | ) 148 | hasStringFormatDate = true 149 | 150 | if (!hasNumberType && type.type === 'number') hasNumberType = true 151 | } 152 | 153 | return hasDateType 154 | } 155 | 156 | interface Instruction { 157 | array: number 158 | optional: number 159 | hasString: boolean 160 | properties: string[] 161 | /** 162 | * If unsafe character is found, how should the encoder handle it? 163 | * 164 | * This value only applied to string field. 165 | * 166 | * - 'throw': Throw an error 167 | * - 'ignore': Ignore the unsafe character, this implied that end user should handle it 168 | * - 'sanitize': Sanitize the string and continue encoding 169 | * 170 | * @default 'sanitize' 171 | **/ 172 | sanitize: 'auto' | 'manual' | 'throw' 173 | definitions: Record 174 | } 175 | 176 | const SANITIZE = { 177 | auto: (property: string) => 178 | `re.test(${property})?JSON.stringify(${property}):\`"$\{${property}}"\``, 179 | manual: (property: string) => `${property}`, 180 | throw: (property: string) => 181 | `re.test(${property})?(()=>{throw new Error("Property '${property}' contains invalid characters")})():${property}` 182 | } satisfies Record string> 183 | 184 | const joinStringArray = (p: string) => 185 | `"$\{` + 186 | `((p)=>{` + 187 | `if(p.length===1)return p\n` + 188 | `let ars=''\n` + 189 | `for(let i=0;i { 202 | const child = 203 | schema.patternProperties['^(.*)$'] ?? 204 | schema.patternProperties[Object.keys(schema.patternProperties)[0]] 205 | 206 | if (!child) return property 207 | 208 | const i = instruction.array 209 | instruction.array++ 210 | 211 | return ( 212 | `\${((ar${i}n)=>{` + 213 | `const ar${i}s=Object.keys(ar${i}n);` + 214 | `let ar${i}v='{';` + 215 | `for(let i=0;i { 230 | if (!schema) return '' 231 | 232 | if ( 233 | Kind in schema && 234 | schema[Kind] === 'Import' && 235 | schema.$ref in schema.$defs 236 | ) 237 | return accelerate(schema.$defs[schema.$ref], property, { 238 | ...instruction, 239 | definitions: Object.assign(instruction.definitions, schema.$defs) 240 | }) 241 | 242 | let v = '' 243 | const isRoot = property === 'v' 244 | 245 | const { schema: newSchema, isNullable, isUndefinable } = getMetadata(schema) 246 | schema = newSchema 247 | 248 | // const error = '' // `??(()=>{throw new Error("Property '${property}' is missing")})()` 249 | 250 | const nullableCondition = 251 | isNullable && isUndefinable 252 | ? `${property}===null||${property}===undefined` 253 | : isNullable 254 | ? `${property}===null` 255 | : isUndefinable 256 | ? `${property}===undefined` 257 | : '' 258 | 259 | let sanitize = SANITIZE[instruction.sanitize] 260 | 261 | switch (schema.type) { 262 | case 'string': 263 | if (!schema.const && !schema.trusted) instruction.hasString = true 264 | 265 | // string operation would be repeated multiple time 266 | // it's fine to optimize it to the most optimized way 267 | if ( 268 | instruction.sanitize === 'auto' || 269 | // Elysia specific format, this implied that format might contain unescaped JSON string 270 | schema.sanitize 271 | ) { 272 | sanitize = SANITIZE['auto'] 273 | 274 | // Sanitize use JSON.stringify which wrap double quotes 275 | // this handle the case where the string contains double quotes 276 | // As slice(1,-1) is use several compute and would be called multiple times 277 | // it's not ideal to slice(1, -1) of JSON.stringify 278 | if (nullableCondition) { 279 | if (schema.trusted) 280 | sanitize = (v: string) => 281 | `\`"$\{${SANITIZE['manual'](v)}}"\`` 282 | 283 | v = `\${${nullableCondition}?${schema.const !== undefined ? `'${JSON.stringify(schema.const)}'` : schema.default !== undefined ? `'${JSON.stringify(schema.default)}'` : `'null'`}:${sanitize(property)}}` 284 | } else { 285 | if (schema.const !== undefined) 286 | v = JSON.stringify(schema.const) 287 | else if (schema.trusted) 288 | v = `"\${${SANITIZE['manual'](property)}}"` 289 | else v = `\${${sanitize(property)}}` 290 | } 291 | } else { 292 | // In this case quote is handle outside to improve performance 293 | if (nullableCondition) 294 | v = `\${${nullableCondition}?${schema.const !== undefined ? `'${JSON.stringify(schema.const)}'` : schema.default !== undefined ? `'${JSON.stringify(schema.default)}'` : `'null'`}:\`\\"\${${sanitize(property)}}\\"\`}` 295 | else 296 | v = `${schema.const !== undefined ? `${JSON.stringify(schema.const)}` : `"\${${sanitize(property)}}"`}` 297 | } 298 | 299 | break 300 | 301 | case 'number': 302 | case 'boolean': 303 | case 'bigint': 304 | if (nullableCondition) 305 | v = `\${${property}??${schema.default !== undefined ? schema.default : `'null'`}}` 306 | else v = `\${${property}}` 307 | break 308 | 309 | case 'null': 310 | v = `\${${property}}` 311 | break 312 | 313 | case 'undefined': 314 | break 315 | 316 | case 'object': 317 | if (nullableCondition) v += `\${${nullableCondition}?"null":\`` 318 | 319 | v += '{' 320 | 321 | if (schema.additionalProperties) { 322 | v = `$\{JSON.stringify(${property})}` 323 | break 324 | } 325 | 326 | schema = mergeObjectIntersection(schema) 327 | 328 | let init = true 329 | let hasOptional = false 330 | let op = `op${instruction.optional}` 331 | 332 | if (schema[Kind as any] === 'Record') { 333 | v = handleRecord(schema as TRecord, property, instruction) 334 | 335 | break 336 | } 337 | 338 | if ( 339 | !Object.keys(schema.properties).length && 340 | schema.patternProperties 341 | ) { 342 | v = `$\{JSON.stringify(${property})}` 343 | 344 | break 345 | } 346 | 347 | for (const key in schema.properties) 348 | if (OptionalKind in schema.properties[key]) { 349 | instruction.optional++ 350 | hasOptional = true 351 | break 352 | } 353 | 354 | for (const key in schema.properties) { 355 | const isOptional = OptionalKind in schema.properties[key] 356 | const name = joinProperty(property, key) 357 | const hasShortName = 358 | schema.properties[key].type === 'object' && 359 | !name.startsWith('ar') 360 | 361 | const i = instruction.properties.length 362 | if (hasShortName) instruction.properties.push(name) 363 | 364 | const k = encodeProperty(key) 365 | const p = accelerate( 366 | schema.properties[key], 367 | hasShortName ? `s${i}` : name, 368 | instruction 369 | ) 370 | 371 | const comma = `\${${op}?',':(${op}=true)&&''}` 372 | 373 | let defaultValue = schema.properties[key].default 374 | if (defaultValue !== undefined) { 375 | if (typeof defaultValue === 'string') 376 | defaultValue = `"${defaultValue}"` 377 | 378 | defaultValue = `\`${comma}${k}:${defaultValue}\`` 379 | } else defaultValue = '""' 380 | 381 | v += isOptional 382 | ? `\${(${name}===undefined?${defaultValue}:\`${comma}${k}:${p}\`)}` 383 | : hasOptional 384 | ? `${!init ? ',' : `\${(${op}=true)&&""}`}${k}:${p}` 385 | : `${!init ? ',' : ''}${k}:${p}` 386 | 387 | init = false 388 | } 389 | 390 | v += '}' 391 | 392 | if (nullableCondition) v += `\`}` 393 | 394 | break 395 | 396 | case 'array': 397 | const i = instruction.array 398 | 399 | instruction.array++ 400 | 401 | if (schema.items.type === 'string') { 402 | if (isRoot) v += 'return `' 403 | 404 | if (nullableCondition) 405 | v += `\${${nullableCondition}?"null":${property}.length?\`[${joinStringArray(property)}]\`:"[]"}` 406 | else 407 | v += `\${${property}.length?\`[${joinStringArray(property)}]\`:"[]"}` 408 | 409 | if (isRoot) v += '`' 410 | 411 | break 412 | } 413 | 414 | if ( 415 | schema.items.type === 'number' || 416 | schema.items.type === 'boolean' || 417 | schema.items.type === 'bigint' || 418 | isInteger(schema.items) 419 | ) { 420 | if (isRoot) v += 'return `' 421 | 422 | if (nullableCondition) 423 | v += `\${${nullableCondition}?'"null"':${property}.length?\`[$\{${property}.toString()}]\`:"[]"` 424 | else 425 | v += `\${${property}.length?\`[$\{${property}.toString()}]\`:"[]"}` 426 | 427 | if (isRoot) v += '`' 428 | 429 | break 430 | } 431 | 432 | if (isNullable || isUndefinable) v += `\${!${property}?'"null"':\`` 433 | 434 | if (isRoot) v += `const ar${i}s=${property};` 435 | else v += `\${((ar${i}s)=>{` 436 | 437 | v += 438 | `let ar${i}v='[';` + 439 | `for(let i=0;i( 521 | schema: T, 522 | { 523 | sanitize = 'auto', 524 | definitions = {} 525 | }: Partial> = {} 526 | ): ((v: T['static']) => string) => { 527 | const f = accelerate(schema, 'v', { 528 | array: 0, 529 | optional: 0, 530 | properties: [], 531 | hasString: false, 532 | sanitize, 533 | definitions 534 | }) 535 | 536 | return Function('v', f) as any 537 | } 538 | 539 | export default createAccelerator 540 | 541 | // const shape = t.Object({ 542 | // a: t.Nullable( 543 | // t.Object({ 544 | // a: t.String() 545 | // }) 546 | // ) 547 | // }) 548 | 549 | // const shape = t.Object({ 550 | // a: t.String(), 551 | // social: t.Optional( 552 | // t.Object({ 553 | // facebook: t.Nullable(t.String()), 554 | // twitter: t.Nullable(t.String()), 555 | // youtube: t.Nullable(t.String()) 556 | // }) 557 | // ) 558 | // }) 559 | 560 | // const stringify = createaccelerate(shape) 561 | 562 | // console.log( 563 | // stringify({ 564 | // a: 'a', 565 | // social: { 566 | // a: 'a', 567 | // } 568 | // }) 569 | // ) 570 | -------------------------------------------------------------------------------- /test/array.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | describe('Array', () => { 7 | it('handle string array at root', () => { 8 | const shape = t.Array(t.String()) 9 | 10 | isEqual(shape, ['a', 'b']) 11 | }) 12 | 13 | it('handle number array at root', () => { 14 | const shape = t.Array(t.Number()) 15 | 16 | isEqual(shape, [1, 2]) 17 | }) 18 | 19 | it('handle boolean array at root', () => { 20 | const shape = t.Array(t.Number()) 21 | 22 | isEqual(shape, [true, false]) 23 | }) 24 | 25 | it('handle big int array at root', () => { 26 | const shape = t.Array(t.Number()) 27 | 28 | isEqual(shape, [1n, 2n], [1, 2]) 29 | }) 30 | 31 | it('handle array union at root', () => { 32 | const shape = t.Array(t.Union([t.String(), t.Number()])) 33 | 34 | isEqual(shape, ['a', 'b', 1, 2, 'c']) 35 | }) 36 | 37 | it('handle array object', () => { 38 | const shape = t.Array( 39 | t.Object({ 40 | a: t.String(), 41 | b: t.String() 42 | }) 43 | ) 44 | 45 | isEqual( 46 | shape, 47 | [ 48 | { 49 | a: 'a', 50 | b: 'b' 51 | }, 52 | { 53 | a: 'a', 54 | b: 'b', 55 | c: 'c' 56 | } 57 | ], 58 | [ 59 | { 60 | a: 'a', 61 | b: 'b' 62 | }, 63 | { 64 | a: 'a', 65 | b: 'b' 66 | } 67 | ] 68 | ) 69 | }) 70 | 71 | it('handle array object with optional', () => { 72 | const shape = t.Array( 73 | t.Object({ 74 | a: t.String(), 75 | b: t.Optional(t.String()) 76 | }) 77 | ) 78 | 79 | isEqual( 80 | shape, 81 | [ 82 | { 83 | a: 'a' 84 | }, 85 | { 86 | a: 'a', 87 | b: 'b' 88 | }, 89 | { 90 | a: 'a', 91 | b: 'b', 92 | c: 'c' 93 | } 94 | ], 95 | [ 96 | { a: 'a' }, 97 | { 98 | a: 'a', 99 | b: 'b' 100 | }, 101 | { 102 | a: 'a', 103 | b: 'b' 104 | } 105 | ] 106 | ) 107 | }) 108 | }) 109 | -------------------------------------------------------------------------------- /test/default.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | describe('Default', () => { 7 | it('handle default value for optional string', () => { 8 | const shape = t.Object({ 9 | name: t.String(), 10 | playing: t.Optional(t.String({ default: 'Strinova' })) 11 | }) 12 | 13 | const value = { 14 | name: 'saltyaom' 15 | } satisfies typeof shape.static 16 | 17 | isEqual(shape, value, { 18 | name: 'saltyaom', 19 | playing: 'Strinova' 20 | }) 21 | }) 22 | 23 | it('handle default value for optional number', () => { 24 | const shape = t.Object({ 25 | name: t.String(), 26 | playing: t.Optional(t.Number({ default: 2 })) 27 | }) 28 | 29 | const value = { 30 | name: 'saltyaom' 31 | } satisfies typeof shape.static 32 | 33 | isEqual(shape, value, { 34 | name: 'saltyaom', 35 | playing: 2 36 | }) 37 | }) 38 | 39 | it('handle default value for optional boolean', () => { 40 | const shape = t.Object({ 41 | name: t.String(), 42 | playing: t.Optional(t.Boolean({ default: true })) 43 | }) 44 | 45 | const value = { 46 | name: 'saltyaom' 47 | } satisfies typeof shape.static 48 | 49 | isEqual(shape, value, { 50 | name: 'saltyaom', 51 | playing: true 52 | }) 53 | }) 54 | 55 | it('handle default value for optional integer', () => { 56 | const shape = t.Object({ 57 | name: t.String(), 58 | playing: t.Optional(t.Integer({ default: 2 })) 59 | }) 60 | 61 | const value = { 62 | name: 'saltyaom' 63 | } satisfies typeof shape.static 64 | 65 | isEqual(shape, value, { 66 | name: 'saltyaom', 67 | playing: 2 68 | }) 69 | }) 70 | 71 | it('handle default value for optional bigint', () => { 72 | const shape = t.Object({ 73 | name: t.String(), 74 | playing: t.Optional(t.BigInt({ default: BigInt(2) })) 75 | }) 76 | 77 | const value = { 78 | name: 'saltyaom' 79 | } satisfies typeof shape.static 80 | 81 | isEqual(shape, value, { 82 | name: 'saltyaom', 83 | playing: 2 84 | }) 85 | }) 86 | 87 | it('handle default value for optional date', () => { 88 | const date = new Date() 89 | 90 | const shape = t.Object({ 91 | name: t.String(), 92 | playing: t.Optional(t.Date({ default: date.toISOString() })) 93 | }) 94 | 95 | const value = { 96 | name: 'saltyaom' 97 | } satisfies typeof shape.static 98 | 99 | isEqual(shape, value, { 100 | name: 'saltyaom', 101 | playing: date.toISOString() 102 | }) 103 | }) 104 | 105 | it('handle default value nullable string', () => { 106 | const shape = t.Object({ 107 | name: t.String(), 108 | playing: t.Nullable(t.String({ default: 'Strinova' })) 109 | }) 110 | 111 | const value = { 112 | name: 'saltyaom', 113 | playing: null 114 | } satisfies typeof shape.static 115 | 116 | isEqual(shape, value, { 117 | name: 'saltyaom', 118 | playing: 'Strinova' 119 | }) 120 | }) 121 | 122 | it('handle default value nullable number', () => { 123 | const shape = t.Object({ 124 | name: t.String(), 125 | playing: t.Nullable(t.Number({ default: 2 })) 126 | }) 127 | 128 | const value = { 129 | name: 'saltyaom', 130 | playing: null 131 | } satisfies typeof shape.static 132 | 133 | isEqual(shape, value, { 134 | name: 'saltyaom', 135 | playing: 2 136 | }) 137 | }) 138 | 139 | it('handle default value nullable boolean', () => { 140 | const shape = t.Object({ 141 | name: t.String(), 142 | playing: t.Nullable(t.Boolean({ default: true })) 143 | }) 144 | 145 | const value = { 146 | name: 'saltyaom', 147 | playing: null 148 | } satisfies typeof shape.static 149 | 150 | isEqual(shape, value, { 151 | name: 'saltyaom', 152 | playing: true 153 | }) 154 | }) 155 | 156 | it('handle default value nullable integer', () => { 157 | const shape = t.Object({ 158 | name: t.String(), 159 | playing: t.Nullable(t.Integer({ default: 2 })) 160 | }) 161 | 162 | const value = { 163 | name: 'saltyaom', 164 | playing: null 165 | } satisfies typeof shape.static 166 | 167 | isEqual(shape, value, { 168 | name: 'saltyaom', 169 | playing: 2 170 | }) 171 | }) 172 | 173 | it('handle default value nullable bigint', () => { 174 | const shape = t.Object({ 175 | name: t.String(), 176 | playing: t.Nullable(t.BigInt({ default: BigInt(2) })) 177 | }) 178 | 179 | const value = { 180 | name: 'saltyaom', 181 | playing: null 182 | } satisfies typeof shape.static 183 | 184 | isEqual(shape, value, { 185 | name: 'saltyaom', 186 | playing: 2 187 | }) 188 | }) 189 | 190 | it('handle default value nullable date', () => { 191 | const date = new Date() 192 | 193 | const shape = t.Object({ 194 | name: t.String(), 195 | playing: t.Nullable(t.Date({ default: date.toISOString() })) 196 | }) 197 | 198 | const value = { 199 | name: 'saltyaom', 200 | playing: null 201 | } satisfies typeof shape.static 202 | 203 | isEqual(shape, value, { 204 | name: 'saltyaom', 205 | playing: date.toISOString() 206 | }) 207 | }) 208 | }) 209 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | import { createAccelerator } from '../src' 7 | 8 | describe('Core', () => { 9 | it('handle string', () => { 10 | const shape = t.String() 11 | 12 | const value = 'saltyaom' satisfies typeof shape.static 13 | 14 | isEqual(shape, value) 15 | }) 16 | 17 | it('handle number', () => { 18 | const shape = t.Number() 19 | 20 | const value = 0 satisfies typeof shape.static 21 | 22 | isEqual(shape, value) 23 | }) 24 | 25 | it('handle boolean', () => { 26 | const shape = t.Boolean() 27 | 28 | const value = true satisfies typeof shape.static 29 | 30 | isEqual(shape, value) 31 | }) 32 | 33 | it('handle literal', () => { 34 | const shape = t.Literal('saltyaom') 35 | 36 | const value = 'saltyaom' satisfies typeof shape.static 37 | 38 | isEqual(shape, value) 39 | }) 40 | 41 | it('handle null', () => { 42 | const shape = t.Null() 43 | 44 | const value = null satisfies typeof shape.static 45 | 46 | isEqual(shape, value) 47 | }) 48 | 49 | it('handle undefined', () => { 50 | const shape = t.Undefined() 51 | 52 | const value = undefined satisfies typeof shape.static 53 | 54 | expect(createAccelerator(shape)(value)).toBe('') 55 | }) 56 | 57 | it('handle date', () => { 58 | const shape = t.Date() 59 | 60 | const value = new Date() satisfies typeof shape.static 61 | 62 | expect(createAccelerator(shape)(value)).toBe(`"${value.toISOString()}"`) 63 | }) 64 | 65 | it('handle date timestamp', () => { 66 | const shape = t.Date() 67 | 68 | const value = Date.now() 69 | 70 | isEqual(shape, value) 71 | }) 72 | 73 | it('handle nullable date', () => { 74 | const shape = t.Nullable(t.Date()) 75 | 76 | const value = new Date() satisfies typeof shape.static 77 | expect(createAccelerator(shape)(value)).toBe(`"${value.toISOString()}"`) 78 | 79 | const value2 = null satisfies typeof shape.static 80 | isEqual(shape, value2) 81 | }) 82 | 83 | it('handle nullable date timestamp', () => { 84 | const shape = t.Nullable(t.Date()) 85 | 86 | const value = 2 87 | isEqual(shape, value) 88 | 89 | const value2 = null satisfies typeof shape.static 90 | isEqual(shape, value2) 91 | }) 92 | 93 | it('handle integer', () => { 94 | const shape = t.Integer() 95 | 96 | const value = 2.2 satisfies typeof shape.static 97 | 98 | isEqual(shape, value) 99 | }) 100 | 101 | it('handle bigint', () => { 102 | const shape = t.BigInt() 103 | 104 | const value = BigInt(2) satisfies typeof shape.static 105 | 106 | isEqual(shape, +(value + '')) 107 | }) 108 | 109 | it('handle object', () => { 110 | const shape = t.Object({ 111 | name: t.String(), 112 | id: t.Number() 113 | }) 114 | 115 | const value = { 116 | id: 0, 117 | name: 'saltyaom' 118 | } satisfies typeof shape.static 119 | 120 | isEqual(shape, value) 121 | }) 122 | 123 | it('handle string array', () => { 124 | const shape = t.Object({ 125 | name: t.String(), 126 | games: t.Array(t.String()) 127 | }) 128 | 129 | const value = { 130 | name: 'saltyaom', 131 | games: ['MiSide', 'Strinova'] 132 | } satisfies typeof shape.static 133 | 134 | isEqual(shape, value) 135 | }) 136 | 137 | it('handle number array', () => { 138 | const shape = t.Object({ 139 | name: t.String(), 140 | games: t.Array(t.Number()) 141 | }) 142 | 143 | const value = { 144 | name: 'saltyaom', 145 | games: [1, 2, 3] 146 | } satisfies typeof shape.static 147 | 148 | isEqual(shape, value) 149 | }) 150 | 151 | it('handle boolean array', () => { 152 | const shape = t.Object({ 153 | name: t.String(), 154 | games: t.Array(t.Boolean()) 155 | }) 156 | 157 | const value = { 158 | name: 'saltyaom', 159 | games: [true, false, true] 160 | } satisfies typeof shape.static 161 | 162 | isEqual(shape, value) 163 | }) 164 | 165 | it('handle object array', () => { 166 | const shape = t.Object({ 167 | name: t.String(), 168 | games: t.Array( 169 | t.Object({ 170 | name: t.String(), 171 | hoursPlay: t.Number({ default: 0 }), 172 | tags: t.Array(t.String()) 173 | }) 174 | ) 175 | }) 176 | 177 | const value = { 178 | name: 'saltyaom', 179 | games: [ 180 | { 181 | name: 'MiSide', 182 | hoursPlay: 17, 183 | tags: ['Psychological Horror', 'Cute', 'Dating Sim'] 184 | }, 185 | { 186 | name: 'Strinova', 187 | hoursPlay: 365, 188 | tags: ['Free to Play', 'Anime', 'Third-Person Shooter'] 189 | }, 190 | { 191 | name: "Tom Clancy's Rainbow Six Siege", 192 | hoursPlay: 287, 193 | tags: ['FPS', 'Multiplayer', 'Tactical'] 194 | } 195 | ] 196 | } satisfies typeof shape.static 197 | 198 | isEqual(shape, value) 199 | }) 200 | 201 | it('handle optional', () => { 202 | const shape = t.Object({ 203 | name: t.String(), 204 | playing: t.Optional(t.String()) 205 | }) 206 | 207 | const value = { 208 | name: 'saltyaom' 209 | } satisfies typeof shape.static 210 | 211 | isEqual(shape, value) 212 | }) 213 | 214 | it('handle nullable', () => { 215 | const shape = t.Object({ 216 | name: t.String(), 217 | country: t.Nullable(t.String()) 218 | }) 219 | 220 | const value = { 221 | name: 'saltyaom', 222 | country: null 223 | } satisfies typeof shape.static 224 | 225 | isEqual(shape, value) 226 | }) 227 | 228 | it('handle undefinable', () => { 229 | const shape = t.Object({ 230 | name: t.String(), 231 | country: t.MaybeEmpty(t.String()) 232 | }) 233 | 234 | const value = { 235 | name: 'saltyaom', 236 | // Transform undefined to null 237 | country: null 238 | } satisfies typeof shape.static 239 | 240 | isEqual(shape, value) 241 | }) 242 | 243 | it('handle intersect', () => { 244 | const shape = t.Intersect([ 245 | t.Object({ 246 | name: t.String(), 247 | playing: t.Optional(t.String()) 248 | }), 249 | t.Object({ 250 | country: t.String() 251 | }) 252 | ]) 253 | 254 | const value = { 255 | name: 'saltyaom', 256 | country: 'Thailand' 257 | } satisfies typeof shape.static 258 | 259 | isEqual(shape, value) 260 | }) 261 | 262 | it('handle union', () => { 263 | const shape = t.Union([ 264 | t.Object({ 265 | name: t.String(), 266 | playing: t.Optional(t.String()) 267 | }), 268 | t.Object({ 269 | country: t.String() 270 | }) 271 | ]) 272 | 273 | const value = { 274 | name: 'saltyaom', 275 | playing: 'MiSide' 276 | } satisfies typeof shape.static 277 | 278 | isEqual(shape, value) 279 | }) 280 | 281 | it('handle union with nullable', () => { 282 | const shape = t.Union([ 283 | t.Object({ 284 | name: t.String(), 285 | playing: t.Optional(t.String()) 286 | }), 287 | t.Object({ 288 | country: t.Nullable(t.String()) 289 | }) 290 | ]) 291 | 292 | const value = { 293 | country: null 294 | } satisfies typeof shape.static 295 | 296 | isEqual(shape, value) 297 | }) 298 | 299 | it('handle additionalProperties', () => { 300 | const shape = t.Object( 301 | { 302 | name: t.String(), 303 | playing: t.Optional(t.String()) 304 | }, 305 | { 306 | additionalProperties: true 307 | } 308 | ) 309 | 310 | const value = { 311 | name: 'saltyaom', 312 | playing: 'Strinova' 313 | } satisfies typeof shape.static 314 | 315 | isEqual(shape, value) 316 | }) 317 | 318 | it('handle nullable array', () => { 319 | const shape = t.Object({ 320 | name: t.String(), 321 | games: t.Nullable(t.Array(t.String())) 322 | }) 323 | 324 | const value = { 325 | name: 'saltyaom', 326 | games: null 327 | } satisfies typeof shape.static 328 | 329 | isEqual(shape, value) 330 | }) 331 | 332 | it('handle nullable object', () => { 333 | const shape = t.Object({ 334 | name: t.String(), 335 | metadata: t.Nullable( 336 | t.Object({ 337 | alias: t.String() 338 | }) 339 | ) 340 | }) 341 | 342 | const value = { 343 | name: 'saltyaom', 344 | metadata: null 345 | } satisfies typeof shape.static 346 | 347 | isEqual(shape, value) 348 | }) 349 | }) 350 | -------------------------------------------------------------------------------- /test/merge-intersection.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'bun:test' 2 | 3 | import { Type as t } from '@sinclair/typebox' 4 | 5 | import { mergeObjectIntersection } from '../src' 6 | 7 | describe('Merge Object Intersection', () => { 8 | it('work', () => { 9 | expect( 10 | mergeObjectIntersection( 11 | t.Intersect([ 12 | t.Object({ 13 | a: t.String() 14 | }), 15 | t.Object({ 16 | b: t.String() 17 | }) 18 | ]) 19 | ) 20 | ).toEqual( 21 | t.Object({ 22 | a: t.String(), 23 | b: t.String() 24 | }) 25 | ) 26 | }) 27 | 28 | it('handle nested intersection', () => { 29 | expect( 30 | mergeObjectIntersection( 31 | t.Intersect([ 32 | t.Object({ 33 | a: t.String() 34 | }), 35 | t.Object({ 36 | b: t.Intersect([ 37 | t.Object({ 38 | c: t.String() 39 | }), 40 | t.Object({ 41 | d: t.String() 42 | }) 43 | ]) 44 | }) 45 | ]) 46 | ) 47 | ).toEqual( 48 | t.Object({ 49 | a: t.String(), 50 | b: t.Object({ 51 | c: t.String(), 52 | d: t.String() 53 | }) 54 | }) 55 | ) 56 | }) 57 | 58 | it('merge property', () => { 59 | expect( 60 | mergeObjectIntersection( 61 | t.Intersect([ 62 | t.Object( 63 | { 64 | a: t.String() 65 | }, 66 | { 67 | description: 'ok' 68 | } 69 | ), 70 | t.Object( 71 | { 72 | b: t.Number({ 73 | minimum: 0 74 | }) 75 | }, 76 | { 77 | additionalProperties: true 78 | } 79 | ) 80 | ]) 81 | ) 82 | ).toEqual( 83 | t.Object( 84 | { 85 | a: t.String(), 86 | b: t.Number({ 87 | minimum: 0 88 | }) 89 | }, 90 | { 91 | description: 'ok', 92 | additionalProperties: true 93 | } 94 | ) 95 | ) 96 | }) 97 | }) 98 | -------------------------------------------------------------------------------- /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 { createAccelerator } = require('json-accelerator'); 6 | 7 | if (typeof createAccelerator !== '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 | "json-accelerator": "../../.." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /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 { createAccelerator } from 'json-accelerator'; 6 | 7 | if (typeof createAccelerator !== '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 | "json-accelerator": "../../.." 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/record.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | describe('Record', () => { 7 | it('handle record', () => { 8 | const shape = t.Record(t.String(), t.String()) 9 | 10 | const value = { 11 | name: 'saltyaom', 12 | alias: 'saltyaom' 13 | } satisfies typeof shape.static 14 | 15 | isEqual(shape, value) 16 | }) 17 | 18 | it('handle record object', () => { 19 | const shape = t.Record( 20 | t.String(), 21 | t.Object({ 22 | name: t.String(), 23 | age: t.Number() 24 | }) 25 | ) 26 | 27 | const value = { 28 | saltyaom: { 29 | name: 'saltyaom', 30 | age: 23 31 | }, 32 | chiffon: { 33 | name: 'chiffon', 34 | age: 24 35 | } 36 | } satisfies typeof shape.static 37 | 38 | isEqual(shape, value) 39 | }) 40 | 41 | it('handle nested record', () => { 42 | const shape = t.Record(t.String(), t.Record(t.String(), t.Number())) 43 | 44 | const value = { 45 | saltyaom: { 46 | id: 1, 47 | age: 23 48 | }, 49 | chiffon: { 50 | id: 2, 51 | age: 24 52 | } 53 | } satisfies typeof shape.static 54 | 55 | isEqual(shape, value) 56 | }) 57 | 58 | it('handle unknown record', () => { 59 | const shape = t.Object( 60 | {}, 61 | { 62 | patternProperties: { 63 | '^[a-z]+$': t.String() 64 | } 65 | } 66 | ) 67 | 68 | const value = { 69 | name: 'saltyaom', 70 | alias: 'saltyaom', 71 | unknown: { 72 | a: 1, 73 | b: ['a', { hello: 'world' }] 74 | } 75 | } satisfies typeof shape.static 76 | 77 | isEqual(shape, value) 78 | }) 79 | }) 80 | -------------------------------------------------------------------------------- /test/ref.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | import { createAccelerator } from '../src' 7 | 8 | describe('Ref', () => { 9 | it('handle module', () => { 10 | const modules = t.Module({ 11 | object: t.Object({ 12 | name: t.String(), 13 | optional: t.Optional(t.String()) 14 | }) 15 | }) 16 | 17 | const shape = modules.Import('object') 18 | 19 | const value = { 20 | name: 'salt' 21 | } satisfies typeof shape.static 22 | 23 | isEqual(shape, value) 24 | }) 25 | 26 | it('handle nested ref', () => { 27 | const modules = t.Module({ 28 | object: t.Object({ 29 | name: t.String(), 30 | info: t.Ref('info') 31 | }), 32 | info: t.Object({ 33 | id: t.Number(), 34 | name: t.String() 35 | }) 36 | }) 37 | 38 | const shape = modules.Import('object') 39 | 40 | const value = { 41 | name: 'salt', 42 | info: { 43 | id: 123, 44 | name: 'salt' 45 | } 46 | } satisfies typeof shape.static 47 | 48 | isEqual(shape, value) 49 | }) 50 | 51 | it('handle optional ref', () => { 52 | const modules = t.Module({ 53 | object: t.Object({ 54 | name: t.String(), 55 | info: t.Optional(t.Ref('info')) 56 | }), 57 | info: t.Object({ 58 | id: t.Number(), 59 | name: t.String() 60 | }) 61 | }) 62 | 63 | const shape = modules.Import('object') 64 | 65 | const value = { 66 | name: 'salt' 67 | } satisfies typeof shape.static 68 | 69 | isEqual(shape, { 70 | name: 'salt' 71 | }) 72 | 73 | isEqual(shape, { 74 | name: 'salt', 75 | info: { 76 | id: 123, 77 | name: 'salt' 78 | } 79 | }) 80 | }) 81 | 82 | it('handle custom modules', () => { 83 | const definitions = { 84 | object: t.Object({ 85 | name: t.String(), 86 | optional: t.Optional(t.String()) 87 | }) 88 | } 89 | 90 | const shape = definitions.object 91 | 92 | const value = { 93 | name: 'salt' 94 | } satisfies typeof shape.static 95 | 96 | expect( 97 | createAccelerator(shape, { 98 | definitions 99 | })(value) 100 | ).toEqual(JSON.stringify(value)) 101 | }) 102 | }) 103 | -------------------------------------------------------------------------------- /test/sample.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | describe('Sample', () => { 7 | it('Medium', () => { 8 | const shape = t.Object({ 9 | id: t.Number(), 10 | name: t.Literal('SaltyAom'), 11 | bio: t.String(), 12 | user: t.Object({ 13 | name: t.String(), 14 | password: t.String() 15 | }), 16 | playing: t.Optional(t.String()), 17 | games: t.Array( 18 | t.Object({ 19 | name: t.String(), 20 | hoursPlay: t.Number({ default: 0 }), 21 | tags: t.Array(t.String()) 22 | }) 23 | ), 24 | metadata: t.Intersect([ 25 | t.Object({ 26 | alias: t.String() 27 | }), 28 | t.Object({ 29 | country: t.Nullable(t.String()) 30 | }) 31 | ]), 32 | social: t.Optional( 33 | t.Object({ 34 | facebook: t.Optional(t.String()), 35 | twitter: t.Optional(t.String()), 36 | youtube: t.Optional(t.String()) 37 | }) 38 | ) 39 | }) 40 | 41 | const value = { 42 | id: 1, 43 | name: 'SaltyAom', 44 | bio: 'I like train', 45 | user: { 46 | name: 'SaltyAom', 47 | password: '123456' 48 | }, 49 | games: [ 50 | { 51 | name: 'MiSide', 52 | hoursPlay: 17, 53 | tags: ['Psychological Horror', 'Cute', 'Dating Sim'] 54 | }, 55 | { 56 | name: 'Strinova', 57 | hoursPlay: 365, 58 | tags: ['Free to Play', 'Anime', 'Third-Person Shooter'] 59 | }, 60 | { 61 | name: "Tom Clancy's Rainbow Six Siege", 62 | hoursPlay: 287, 63 | tags: ['FPS', 'Multiplayer', 'Tactical'] 64 | } 65 | ], 66 | metadata: { 67 | alias: 'SaltyAom', 68 | country: 'Thailand' 69 | }, 70 | social: { 71 | twitter: 'SaltyAom' 72 | } 73 | } satisfies typeof shape.static 74 | 75 | isEqual(shape, value) 76 | }) 77 | 78 | it('Large', () => { 79 | const shape = t.Array( 80 | t.Object({ 81 | id: t.Number(), 82 | name: t.String(), 83 | bio: t.String(), 84 | user: t.Object({ 85 | name: t.String(), 86 | password: t.String(), 87 | email: t.Optional(t.String({ format: 'email' })), 88 | age: t.Optional(t.Number()), 89 | avatar: t.Optional(t.String({ format: 'uri' })), 90 | cover: t.Optional(t.String({ format: 'uri' })) 91 | }), 92 | playing: t.Optional(t.String()), 93 | wishlist: t.Optional(t.Array(t.Number())), 94 | games: t.Array( 95 | t.Object({ 96 | id: t.Number(), 97 | name: t.String(), 98 | hoursPlay: t.Optional(t.Number({ default: 0 })), 99 | tags: t.Array( 100 | t.Object({ 101 | name: t.String(), 102 | count: t.Number() 103 | }) 104 | ) 105 | }) 106 | ), 107 | metadata: t.Intersect([ 108 | t.Object({ 109 | alias: t.String() 110 | }), 111 | t.Object({ 112 | country: t.Nullable(t.String()), 113 | region: t.Optional(t.String()) 114 | }) 115 | ]), 116 | social: t.Optional( 117 | t.Object({ 118 | facebook: t.Optional(t.String()), 119 | twitter: t.Optional(t.String()), 120 | youtube: t.Optional(t.String()) 121 | }) 122 | ) 123 | }) 124 | ) 125 | 126 | const value = [ 127 | { 128 | id: 1, 129 | name: 'SaltyAom', 130 | bio: 'I like train', 131 | user: { 132 | name: 'SaltyAom', 133 | password: '123456', 134 | avatar: 'https://avatars.githubusercontent.com/u/35027979?v=4', 135 | cover: 'https://saltyaom.com/cosplay/pekomama.webp' 136 | }, 137 | playing: 'Strinova', 138 | wishlist: [4_154_456, 2_345_345], 139 | games: [ 140 | { 141 | id: 4_154_456, 142 | name: 'MiSide', 143 | hoursPlay: 17, 144 | tags: [ 145 | { name: 'Psychological Horror', count: 236_432 }, 146 | { name: 'Cute', count: 495_439 }, 147 | { name: 'Dating Sim', count: 395_532 } 148 | ] 149 | }, 150 | { 151 | id: 4_356_345, 152 | name: 'Strinova', 153 | hoursPlay: 365, 154 | tags: [ 155 | { name: 'Free to Play', count: 205_593 }, 156 | { name: 'Anime', count: 504_304 }, 157 | { name: 'Third-Person Shooter', count: 395_532 } 158 | ] 159 | }, 160 | { 161 | id: 2_345_345, 162 | name: "Tom Clancy's Rainbow Six Siege", 163 | hoursPlay: 287, 164 | tags: [ 165 | { name: 'FPS', count: 855_324 }, 166 | { name: 'Multiplayer', count: 456_567 }, 167 | { name: 'Tactical', count: 544_467 } 168 | ] 169 | } 170 | ], 171 | metadata: { 172 | alias: 'SaltyAom', 173 | country: 'Thailand', 174 | region: 'Asia' 175 | }, 176 | social: { 177 | twitter: 'SaltyAom' 178 | } 179 | }, 180 | { 181 | id: 2, 182 | name: 'VLost', 183 | bio: 'ไม่พี่คืองี้', 184 | user: { 185 | name: 'nattapon_kub', 186 | password: '123456' 187 | }, 188 | games: [ 189 | { 190 | id: 4_154_456, 191 | name: 'MiSide', 192 | hoursPlay: 17, 193 | tags: [ 194 | { name: 'Psychological Horror', count: 236_432 }, 195 | { name: 'Cute', count: 495_439 }, 196 | { name: 'Dating Sim', count: 395_532 } 197 | ] 198 | }, 199 | { 200 | id: 4_356_345, 201 | name: 'Strinova', 202 | hoursPlay: 365, 203 | tags: [ 204 | { name: 'Free to Play', count: 205_593 }, 205 | { name: 'Anime', count: 504_304 }, 206 | { name: 'Third-Person Shooter', count: 395_532 } 207 | ] 208 | } 209 | ], 210 | metadata: { 211 | alias: 'vlost', 212 | country: 'Thailand' 213 | } 214 | }, 215 | { 216 | id: 2, 217 | name: 'eika', 218 | bio: 'こんにちわ!', 219 | user: { 220 | name: 'ei_ka', 221 | password: '123456' 222 | }, 223 | games: [ 224 | { 225 | id: 4_356_345, 226 | name: 'Strinova', 227 | hoursPlay: 365, 228 | tags: [ 229 | { name: 'Free to Play', count: 205_593 }, 230 | { name: 'Anime', count: 504_304 }, 231 | { name: 'Third-Person Shooter', count: 395_532 } 232 | ] 233 | } 234 | ], 235 | metadata: { 236 | alias: 'eika', 237 | country: 'Japan' 238 | } 239 | } 240 | ] satisfies typeof shape.static 241 | 242 | isEqual(shape, value) 243 | }) 244 | }) 245 | -------------------------------------------------------------------------------- /test/sanitize-auto.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | import { createAccelerator } from '../src' 6 | 7 | describe('sanitize auto', () => { 8 | it('sanitize invalid value', () => { 9 | const shape = t.Object({ 10 | a: t.String(), 11 | b: t.String() 12 | }) 13 | 14 | const value = { 15 | a: 'hello', 16 | b: 'hello\nworld' 17 | } satisfies typeof shape.static 18 | 19 | expect(() => 20 | createAccelerator(shape, { 21 | sanitize: 'auto' 22 | })(value) 23 | ).not.toThrow() 24 | 25 | expect(() => 26 | JSON.parse( 27 | createAccelerator(shape, { 28 | sanitize: 'auto' 29 | })(value) 30 | ) 31 | ).not.toThrow() 32 | 33 | expect( 34 | createAccelerator(shape, { 35 | sanitize: 'auto' 36 | })(value) 37 | ).toEqual(`{"a":"hello","b":"hello\\nworld"}`) 38 | }) 39 | 40 | it('create literal value', () => { 41 | const shape = t.Object({ 42 | a: t.String(), 43 | b: t.Literal('SaltyAom') 44 | }) 45 | 46 | const value = { 47 | a: 'hello', 48 | b: 'SaltyAom' 49 | } satisfies typeof shape.static 50 | 51 | expect(() => 52 | createAccelerator(shape, { 53 | sanitize: 'auto' 54 | })(value) 55 | ).not.toThrow() 56 | 57 | isEqual(shape, value) 58 | }) 59 | }) 60 | -------------------------------------------------------------------------------- /test/sanitize-manual.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | import { createAccelerator } from '../src' 7 | 8 | describe('sanitize manual', () => { 9 | it('ignore invalid value', () => { 10 | const shape = t.Object({ 11 | a: t.String(), 12 | b: t.String() 13 | }) 14 | 15 | const value = { 16 | a: 'hello', 17 | b: 'hello\nworld' 18 | } satisfies typeof shape.static 19 | 20 | expect(() => 21 | createAccelerator(shape, { 22 | sanitize: 'manual' 23 | })(value) 24 | ).not.toThrow() 25 | 26 | expect(() => 27 | JSON.parse( 28 | createAccelerator(shape, { 29 | sanitize: 'manual' 30 | })(value) 31 | ) 32 | ).toThrow() 33 | 34 | expect( 35 | createAccelerator(shape, { 36 | sanitize: 'manual' 37 | })(value) 38 | ).toEqual(`{"a":"hello","b":"hello\nworld"}`) 39 | }) 40 | 41 | it('create a literal value', () => { 42 | const shape = t.Object({ 43 | a: t.String(), 44 | b: t.Literal('SaltyAom') 45 | }) 46 | 47 | const value = { 48 | a: 'hello', 49 | b: 'SaltyAom' 50 | } satisfies typeof shape.static 51 | 52 | expect(() => 53 | createAccelerator(shape, { 54 | sanitize: 'manual' 55 | })(value) 56 | ).not.toThrow() 57 | 58 | isEqual(shape, value) 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /test/sanitize-throw.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | import { createAccelerator } from '../src' 7 | 8 | describe('sanitize throw', () => { 9 | it('throw on invalid value', () => { 10 | const shape = t.Object({ 11 | a: t.String(), 12 | b: t.String() 13 | }) 14 | 15 | const value = { 16 | a: 'hello', 17 | b: 'hello\nworld' 18 | } satisfies typeof shape.static 19 | 20 | expect(() => 21 | createAccelerator(shape, { 22 | sanitize: 'throw' 23 | })(value) 24 | ).toThrow() 25 | }) 26 | 27 | it("don't throw on valid value", () => { 28 | const shape = t.Object({ 29 | a: t.String(), 30 | b: t.String() 31 | }) 32 | 33 | const value = { 34 | a: 'hello', 35 | b: 'hello world' 36 | } satisfies typeof shape.static 37 | 38 | expect(() => 39 | createAccelerator(shape, { 40 | sanitize: 'throw' 41 | })(value) 42 | ).not.toThrow() 43 | 44 | isEqual(shape, value) 45 | }) 46 | 47 | it("don't throw on valid value", () => { 48 | const shape = t.Object({ 49 | a: t.String(), 50 | b: t.String({ 51 | sanitize: true 52 | }) 53 | }) 54 | 55 | const value = { 56 | a: 'hello', 57 | b: 'hello world' 58 | } satisfies typeof shape.static 59 | 60 | expect(() => 61 | createAccelerator(shape, { 62 | sanitize: 'throw' 63 | })(value) 64 | ).not.toThrow() 65 | 66 | isEqual(shape, value) 67 | }) 68 | 69 | it('handle sanitize value', () => { 70 | const shape = t.Object({ 71 | a: t.String(), 72 | b: t.String({ 73 | sanitize: true 74 | }) 75 | }) 76 | 77 | const value = { 78 | a: 'hello', 79 | b: 'hello\nworld' 80 | } satisfies typeof shape.static 81 | 82 | expect(() => 83 | createAccelerator(shape, { 84 | sanitize: 'throw' 85 | })(value) 86 | ).not.toThrow() 87 | 88 | isEqual(shape, value) 89 | }) 90 | }) 91 | -------------------------------------------------------------------------------- /test/tuple.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, it } from 'bun:test' 2 | import { isEqual } from './utils' 3 | 4 | import { t } from 'elysia' 5 | 6 | describe('Tuple', () => { 7 | it('handle tuple', () => { 8 | const shape = t.Tuple([t.String(), t.Number()]) 9 | 10 | const value = ['saltyaom', 123] satisfies typeof shape.static 11 | 12 | isEqual(shape, value) 13 | }) 14 | 15 | it('handle tuple object', () => { 16 | const shape = t.Tuple([ 17 | t.String(), 18 | t.Object({ 19 | name: t.String(), 20 | age: t.Number() 21 | }) 22 | ]) 23 | 24 | const value = [ 25 | 'a', 26 | { 27 | name: 'saltyaom', 28 | age: 123 29 | } 30 | ] satisfies typeof shape.static 31 | 32 | isEqual(shape, value) 33 | }) 34 | 35 | it('handle nested tuple', () => { 36 | const shape = t.Tuple([t.String(), t.Tuple([t.String(), t.Number()])]) 37 | 38 | const value = ['a', ['b', 123]] satisfies typeof shape.static 39 | 40 | isEqual(shape, value) 41 | }) 42 | }) 43 | -------------------------------------------------------------------------------- /test/utils.ts: -------------------------------------------------------------------------------- 1 | import { type TAnySchema } from '@sinclair/typebox' 2 | import { createAccelerator } from '../src' 3 | 4 | import { expect } from 'bun:test' 5 | 6 | export const isEqual = (shape: TAnySchema, value: unknown, expected = value) => 7 | expect(JSON.parse(createAccelerator(shape)(value))).toEqual(expected) 8 | -------------------------------------------------------------------------------- /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", "benchmarks"] 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 | // "types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */ 36 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 37 | // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ 38 | // "resolveJsonModule": true, /* Enable importing .json files. */ 39 | // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ 40 | 41 | /* JavaScript Support */ 42 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ 43 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 44 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ 45 | 46 | /* Emit */ 47 | "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 48 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 49 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 50 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 51 | // "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. */ 52 | // "outDir": "./dist", /* Specify an output folder for all emitted files. */ 53 | // "removeComments": true, /* Disable emitting comments. */ 54 | "noEmit": true, /* Disable emitting files from a compilation. */ 55 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 56 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ 57 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 58 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 59 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 60 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 61 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 62 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 63 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 64 | // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ 65 | // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ 66 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 67 | // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ 68 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 69 | // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ 70 | 71 | /* Interop Constraints */ 72 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 73 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 74 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ 75 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 76 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 77 | 78 | /* Type Checking */ 79 | "strict": true, /* Enable all strict type-checking options. */ 80 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ 81 | // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ 82 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 83 | // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ 84 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 85 | // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ 86 | // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ 87 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 88 | // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ 89 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ 90 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 91 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 92 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 93 | // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ 94 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 95 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ 96 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 97 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 98 | 99 | /* Completeness */ 100 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 101 | "skipLibCheck": true, /* Skip type checking all .d.ts files. */ 102 | }, 103 | // "include": ["src/**/*"] 104 | } 105 | --------------------------------------------------------------------------------