├── .editorconfig ├── .github └── workflows │ ├── biome.yml │ ├── lint-pr.yml │ └── release.yml ├── .gitignore ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── biome.json ├── build.ts ├── bun.lock ├── bunfig.toml ├── docs ├── .typedoc │ ├── context │ │ └── sources.js │ └── theme.js ├── .vitepress │ ├── config.ts │ └── theme │ │ ├── custom.css │ │ └── index.ts ├── guide │ └── what-is-kient.md └── index.md ├── example ├── app-token.ts ├── auth.ts ├── get-categories.ts ├── get-channels.ts ├── get-public-key.ts ├── get-users.ts ├── send-chat.ts └── webhooks.ts ├── package.json ├── run-example.ts ├── src ├── api.client.ts ├── api │ ├── api-base.ts │ ├── category │ │ ├── get-categories.ts │ │ └── index.ts │ ├── channel │ │ ├── get-channels.ts │ │ └── index.ts │ ├── chat │ │ ├── index.ts │ │ └── send-chat.ts │ ├── events │ │ ├── get-events.ts │ │ ├── index.ts │ │ ├── subscribe.ts │ │ └── unsubscribe.ts │ ├── misc │ │ ├── get-public-key.ts │ │ └── index.ts │ └── user │ │ ├── get-user.ts │ │ └── index.ts ├── authentication │ ├── app-token.ts │ ├── scopes.ts │ └── user-token.ts ├── events.ts ├── index.ts ├── kient.ts ├── structures │ ├── base-event.ts │ ├── base-user.ts │ ├── base.ts │ ├── category.ts │ ├── channel-follow.ts │ ├── channel-subscription-gift.ts │ ├── channel-subscription.ts │ ├── channel.ts │ ├── chat-message.ts │ ├── chat-user.ts │ ├── chat.ts │ ├── detailed-event-subscription.ts │ ├── event-subscription.ts │ ├── livestream-status.ts │ ├── token.ts │ └── user.ts ├── util │ ├── api-response.ts │ ├── flatten.ts │ └── verify-webhook-signature.ts ├── webhook.handler.ts └── webhook.server.ts ├── tsconfig.json └── typedoc.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | charset = utf-8 7 | indent_style = tab 8 | indent_size = 2 9 | max_line_length = 120 -------------------------------------------------------------------------------- /.github/workflows/biome.yml: -------------------------------------------------------------------------------- 1 | name: Biome CI 2 | 3 | on: [pull_request] 4 | 5 | permissions: 6 | actions: write 7 | contents: read 8 | pull-requests: write 9 | 10 | jobs: 11 | biome: 12 | name: CI 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - uses: biomejs/setup-biome@v2 17 | - run: biome ci . --reporter=github -------------------------------------------------------------------------------- /.github/workflows/lint-pr.yml: -------------------------------------------------------------------------------- 1 | name: "Lint PR" 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | - reopened 10 | 11 | permissions: 12 | pull-requests: read 13 | 14 | jobs: 15 | main: 16 | name: Validate PR title 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: amannn/action-semantic-pull-request@v5 20 | env: 21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Package to npm 2 | on: 3 | release: 4 | types: [published] 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v4 12 | 13 | - name: Setup Bun 14 | uses: oven-sh/setup-bun@v2 15 | 16 | - name: Install dependencies 17 | run: bun install 18 | 19 | - name: Build Kient 20 | run: bun run build 21 | 22 | - name: Publish 23 | run: bun publish --access public 24 | env: 25 | BUN_AUTH_TOKEN: ${{secrets.NPM_PUBLISH_TOKEN}} 26 | NPM_CONFIG_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore 2 | 3 | # Logs 4 | 5 | logs 6 | _.log 7 | npm-debug.log_ 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | .pnpm-debug.log* 12 | 13 | # Caches 14 | 15 | .cache 16 | 17 | # Diagnostic reports (https://nodejs.org/api/report.html) 18 | 19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json 20 | 21 | # Runtime data 22 | 23 | pids 24 | _.pid 25 | _.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | 30 | lib-cov 31 | 32 | # Coverage directory used by tools like istanbul 33 | 34 | coverage 35 | *.lcov 36 | 37 | # nyc test coverage 38 | 39 | .nyc_output 40 | 41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 42 | 43 | .grunt 44 | 45 | # Bower dependency directory (https://bower.io/) 46 | 47 | bower_components 48 | 49 | # node-waf configuration 50 | 51 | .lock-wscript 52 | 53 | # Compiled binary addons (https://nodejs.org/api/addons.html) 54 | 55 | build/Release 56 | 57 | # Dependency directories 58 | 59 | node_modules/ 60 | jspm_packages/ 61 | 62 | # Snowpack dependency directory (https://snowpack.dev/) 63 | 64 | web_modules/ 65 | 66 | # TypeScript cache 67 | 68 | *.tsbuildinfo 69 | 70 | # Optional npm cache directory 71 | 72 | .npm 73 | 74 | # Optional eslint cache 75 | 76 | .eslintcache 77 | 78 | # Optional stylelint cache 79 | 80 | .stylelintcache 81 | 82 | # Microbundle cache 83 | 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | 91 | .node_repl_history 92 | 93 | # Output of 'npm pack' 94 | 95 | *.tgz 96 | 97 | # Yarn Integrity file 98 | 99 | .yarn-integrity 100 | 101 | # dotenv environment variable files 102 | 103 | .env 104 | .env.development.local 105 | .env.test.local 106 | .env.production.local 107 | .env.local 108 | 109 | # parcel-bundler cache (https://parceljs.org/) 110 | 111 | .parcel-cache 112 | 113 | # Next.js build output 114 | 115 | .next 116 | out 117 | 118 | # Nuxt.js build / generate output 119 | 120 | .nuxt 121 | dist 122 | 123 | # Gatsby files 124 | 125 | # Comment in the public line in if your project uses Gatsby and not Next.js 126 | 127 | # https://nextjs.org/blog/next-9-1#public-directory-support 128 | 129 | # public 130 | 131 | # vuepress build output 132 | 133 | .vuepress/dist 134 | 135 | # vuepress v2.x temp and cache directory 136 | 137 | .temp 138 | 139 | # Docusaurus cache and generated files 140 | 141 | .docusaurus 142 | 143 | # Serverless directories 144 | 145 | .serverless/ 146 | 147 | # FuseBox cache 148 | 149 | .fusebox/ 150 | 151 | # DynamoDB Local files 152 | 153 | .dynamodb/ 154 | 155 | # TernJS port file 156 | 157 | .tern-port 158 | 159 | # Stores VSCode versions used for testing VSCode extensions 160 | 161 | .vscode-test 162 | 163 | # yarn v2 164 | 165 | .yarn/cache 166 | .yarn/unplugged 167 | .yarn/build-state.yml 168 | .yarn/install-state.gz 169 | .pnp.* 170 | 171 | # IntelliJ based IDEs 172 | .idea 173 | 174 | # Finder (MacOS) folder config 175 | .DS_Store 176 | 177 | # Vitepress docs 178 | docs/.vitepress/dist 179 | docs/.vitepress/cache 180 | docs/typedoc -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "biomejs.biome" 3 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## v2.3.0 5 | 6 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.2.0...v2.3.0) 7 | 8 | ### 🚀 Enhancements 9 | 10 | - Support getting channels by slug ([#32](https://github.com/zSoulweaver/kient/pull/32)) 11 | - Add livestream status webhook ([8cf7a79](https://github.com/zSoulweaver/kient/commit/8cf7a79)) 12 | - Add chat user identity ([d6b3056](https://github.com/zSoulweaver/kient/commit/d6b3056)) 13 | 14 | ### 🏡 Chore 15 | 16 | - Update webhook example - data structures should really be use `number` type, will get on that later ([6a72f7b](https://github.com/zSoulweaver/kient/commit/6a72f7b)) 17 | 18 | ### ❤️ Contributors 19 | 20 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 21 | - Kody 22 | 23 | ## v2.2.0 24 | 25 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.1.0...v2.2.0) 26 | 27 | ### 💅 Refactors 28 | 29 | - Move webhook verifier to exported utility function ([33a0d28](https://github.com/zSoulweaver/kient/commit/33a0d28)) 30 | 31 | ### 🏡 Chore 32 | 33 | - Add biome to default formatter ([1cf40f3](https://github.com/zSoulweaver/kient/commit/1cf40f3)) 34 | 35 | ### ❤️ Contributors 36 | 37 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 38 | 39 | ## v2.1.0 40 | 41 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-7...v2.1.0) 42 | 43 | ### 🚀 Enhancements 44 | 45 | - Add app tokens ([24b5404](https://github.com/zSoulweaver/kient/commit/24b5404)) 46 | - Add target user to webhook subscriptions ([d7bd0b4](https://github.com/zSoulweaver/kient/commit/d7bd0b4)) 47 | 48 | ### 🏡 Chore 49 | 50 | - Repo fix again? ([a5a41dc](https://github.com/zSoulweaver/kient/commit/a5a41dc)) 51 | - Add release script ([b5d9802](https://github.com/zSoulweaver/kient/commit/b5d9802)) 52 | - Adjust prerelease script name - conflicts with some built in npm script stuff causing release command to have both commands run ([ddfd66e](https://github.com/zSoulweaver/kient/commit/ddfd66e)) 53 | 54 | ### ❤️ Contributors 55 | 56 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 57 | 58 | ## v2.0.1-7 59 | 60 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-6...v2.0.1-7) 61 | 62 | ### 🩹 Fixes 63 | 64 | - Update channel API response ([9131ce9](https://github.com/zSoulweaver/kient/commit/9131ce9)) 65 | 66 | ### 🏡 Chore 67 | 68 | - Possible npm repo fix 2? ([427237c](https://github.com/zSoulweaver/kient/commit/427237c)) 69 | 70 | ### ❤️ Contributors 71 | 72 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 73 | 74 | ## v2.0.1-6 75 | 76 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-5...v2.0.1-6) 77 | 78 | ### 🏡 Chore 79 | 80 | - Improve package.json - Adds NPM keywords - Adds homepage to docs - Maybe fixes repo link on npm? ([eff2d6c](https://github.com/zSoulweaver/kient/commit/eff2d6c)) 81 | - Update package for changelogen ([857e608](https://github.com/zSoulweaver/kient/commit/857e608)) 82 | 83 | ### ❤️ Contributors 84 | 85 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 86 | 87 | ## v2.0.1-5 88 | 89 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-4...v2.0.1-5) 90 | 91 | ### 🚀 Enhancements 92 | 93 | - Add new channel endpoint data ([3f50b31](https://github.com/zSoulweaver/kient/commit/3f50b31)) 94 | 95 | ### 💅 Refactors 96 | 97 | - Improve flatten function - uses grok llm, so could be further issues yet ([79ced64](https://github.com/zSoulweaver/kient/commit/79ced64)) 98 | 99 | ### 📖 Documentation 100 | 101 | - Fix build issue ([64523d4](https://github.com/zSoulweaver/kient/commit/64523d4)) 102 | - Fix build v2 ([b422004](https://github.com/zSoulweaver/kient/commit/b422004)) 103 | 104 | ### ❤️ Contributors 105 | 106 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 107 | 108 | ## v2.0.1-4 109 | 110 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-3...v2.0.1-4) 111 | 112 | ### 🚀 Enhancements 113 | 114 | - Add webhook handling - adds optional internal webhook server - exposes function to handle events externally - adds chat message events ([7771eba](https://github.com/zSoulweaver/kient/commit/7771eba)) 115 | - Add remaining webhook events ([470ed60](https://github.com/zSoulweaver/kient/commit/470ed60)) 116 | - Add subscription id to event and add unsub func ([0dfeebd](https://github.com/zSoulweaver/kient/commit/0dfeebd)) 117 | 118 | ### 💅 Refactors 119 | 120 | - Adjust api responses and structure instances ([cdd2822](https://github.com/zSoulweaver/kient/commit/cdd2822)) 121 | - Restructure event/webhook api ([a62489f](https://github.com/zSoulweaver/kient/commit/a62489f)) 122 | - Rename webhooks to events and align to api design ([3b9d201](https://github.com/zSoulweaver/kient/commit/3b9d201)) 123 | 124 | ### ❤️ Contributors 125 | 126 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 127 | 128 | ## v2.0.1-3 129 | 130 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-2...v2.0.1-3) 131 | 132 | ### 🩹 Fixes 133 | 134 | - Add dist directory to files key in package ([2425f90](https://github.com/zSoulweaver/kient/commit/2425f90)) 135 | 136 | ### ❤️ Contributors 137 | 138 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 139 | 140 | ## v2.0.1-2 141 | 142 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-1...v2.0.1-2) 143 | 144 | ### 🤖 CI 145 | 146 | - Publish fix hopefully ([b7c4ee3](https://github.com/zSoulweaver/kient/commit/b7c4ee3)) 147 | 148 | ### ❤️ Contributors 149 | 150 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 151 | 152 | ## v2.0.1-1 153 | 154 | [compare changes](https://github.com/zSoulweaver/kient/compare/v2.0.1-0...v2.0.1-1) 155 | 156 | ### 🤖 CI 157 | 158 | - Fix copy paste error ([5aff6f2](https://github.com/zSoulweaver/kient/commit/5aff6f2)) 159 | 160 | ### ❤️ Contributors 161 | 162 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 163 | 164 | ## v2.0.1-0 165 | 166 | 167 | ### 🚀 Enhancements 168 | 169 | - Initial commit ([1bbcd0c](https://github.com/zSoulweaver/kient/commit/1bbcd0c)) 170 | - New api beginnings ([67fa520](https://github.com/zSoulweaver/kient/commit/67fa520)) 171 | - Add pusher/ws ([d2ed258](https://github.com/zSoulweaver/kient/commit/d2ed258)) 172 | - Add kient instance to structures ([f983940](https://github.com/zSoulweaver/kient/commit/f983940)) 173 | - Add channel panels ([3dc8146](https://github.com/zSoulweaver/kient/commit/3dc8146)) 174 | - Add channel socials ([6d2a17d](https://github.com/zSoulweaver/kient/commit/6d2a17d)) 175 | - Add channel chatroom ([b19d7fc](https://github.com/zSoulweaver/kient/commit/b19d7fc)) 176 | - Add channel clips ([3626e88](https://github.com/zSoulweaver/kient/commit/3626e88)) 177 | - Initial docs ([3e4d087](https://github.com/zSoulweaver/kient/commit/3e4d087)) 178 | - Add user token authorisation ([3744540](https://github.com/zSoulweaver/kient/commit/3744540)) 179 | - Add category api ([fee7a33](https://github.com/zSoulweaver/kient/commit/fee7a33)) 180 | - Add users api ([85570b6](https://github.com/zSoulweaver/kient/commit/85570b6)) 181 | - Add user api ([3e9ebff](https://github.com/zSoulweaver/kient/commit/3e9ebff)) 182 | - Add channel api ([c4c7794](https://github.com/zSoulweaver/kient/commit/c4c7794)) 183 | - Add chat api ([0f9d0e2](https://github.com/zSoulweaver/kient/commit/0f9d0e2)) 184 | - Add misc api for public key ([e0adc65](https://github.com/zSoulweaver/kient/commit/e0adc65)) 185 | 186 | ### 🩹 Fixes 187 | 188 | - Include example folder in tsconfig ([e63c0be](https://github.com/zSoulweaver/kient/commit/e63c0be)) 189 | - Add channel api functions ([e4dc28c](https://github.com/zSoulweaver/kient/commit/e4dc28c)) 190 | - Prepare typedoc before building docs ([3eafb44](https://github.com/zSoulweaver/kient/commit/3eafb44)) 191 | 192 | ### 💅 Refactors 193 | 194 | - Export kient properly ([c273848](https://github.com/zSoulweaver/kient/commit/c273848)) 195 | - Use classes to expose api funcs ([6bbfceb](https://github.com/zSoulweaver/kient/commit/6bbfceb)) 196 | - Add api client, fix kient options constuctor ([b9a3691](https://github.com/zSoulweaver/kient/commit/b9a3691)) 197 | - Improve type safety ([b324a70](https://github.com/zSoulweaver/kient/commit/b324a70)) 198 | - Better structure classes ([b0e829c](https://github.com/zSoulweaver/kient/commit/b0e829c)) 199 | - Run biome check ([4a88e07](https://github.com/zSoulweaver/kient/commit/4a88e07)) 200 | - Remove deepkit ([9c27683](https://github.com/zSoulweaver/kient/commit/9c27683)) 201 | - Remove deepkit ([953daa1](https://github.com/zSoulweaver/kient/commit/953daa1)) 202 | - Remove old examples ([d0a2423](https://github.com/zSoulweaver/kient/commit/d0a2423)) 203 | - Adjust category folder name ([d87670e](https://github.com/zSoulweaver/kient/commit/d87670e)) 204 | 205 | ### 📖 Documentation 206 | 207 | - Hide data structure constructor ([b12664d](https://github.com/zSoulweaver/kient/commit/b12664d)) 208 | - Better overall theme ([db77334](https://github.com/zSoulweaver/kient/commit/db77334)) 209 | - Fix category example ([f7fe21c](https://github.com/zSoulweaver/kient/commit/f7fe21c)) 210 | - Fix import and some wording ([f033fa9](https://github.com/zSoulweaver/kient/commit/f033fa9)) 211 | - Improve docs somewhat ([7a63a57](https://github.com/zSoulweaver/kient/commit/7a63a57)) 212 | - Fix build issue ([c162d30](https://github.com/zSoulweaver/kient/commit/c162d30)) 213 | - Update readme and add licence ([01a4018](https://github.com/zSoulweaver/kient/commit/01a4018)) 214 | 215 | ### 🏡 Chore 216 | 217 | - Setup biome ([dbe17d2](https://github.com/zSoulweaver/kient/commit/dbe17d2)) 218 | - Let biome handle type imports ([1afdf48](https://github.com/zSoulweaver/kient/commit/1afdf48)) 219 | - Disable biome in node_modules ([beff95e](https://github.com/zSoulweaver/kient/commit/beff95e)) 220 | - Add readme ([06ee723](https://github.com/zSoulweaver/kient/commit/06ee723)) 221 | - Update lockfile ([b1240c2](https://github.com/zSoulweaver/kient/commit/b1240c2)) 222 | - Update biome ([cbc9848](https://github.com/zSoulweaver/kient/commit/cbc9848)) 223 | - Add editorconfig ([f65c3cd](https://github.com/zSoulweaver/kient/commit/f65c3cd)) 224 | - Biome ci ([da1e799](https://github.com/zSoulweaver/kient/commit/da1e799)) 225 | - Add changelogen ([d1183c8](https://github.com/zSoulweaver/kient/commit/d1183c8)) 226 | - Add bun build script ([0a33fa5](https://github.com/zSoulweaver/kient/commit/0a33fa5)) 227 | - Add dist location in package ([6acd4fe](https://github.com/zSoulweaver/kient/commit/6acd4fe)) 228 | - Fix dev script missing watcher ([174084b](https://github.com/zSoulweaver/kient/commit/174084b)) 229 | - Add all scopes to auth example ([7e15d8a](https://github.com/zSoulweaver/kient/commit/7e15d8a)) 230 | - Update repo in package.json ([cf00b0b](https://github.com/zSoulweaver/kient/commit/cf00b0b)) 231 | 232 | ### 🤖 CI 233 | 234 | - Add pr title linter ([6a49f35](https://github.com/zSoulweaver/kient/commit/6a49f35)) 235 | - Add auto release workflow ([f29a7c7](https://github.com/zSoulweaver/kient/commit/f29a7c7)) 236 | 237 | ### ❤️ Contributors 238 | 239 | - ZSoulweaver ([@zSoulweaver](http://github.com/zSoulweaver)) 240 | - Matt ([@zSoulweaver](http://github.com/zSoulweaver)) 241 | 242 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 zSoulweaver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Kient 3 |

4 | 5 |

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

16 | 17 | ## About 18 | 19 | Kient (**K**ick-Cl**ient**) is a versatile TypeScript library designed to simplify interaction with Kick's API and Webhooks. With Kient, you can seamlessly integrate Kick's platform into your projects, making it easier than ever to leverage its capabilities. 20 | 21 | ## Documentation 22 | 23 | Learn how to use Kient and find detailed information on the [website](https://kient.pages.dev/) - Very much WIP. 24 | 25 | ## Installation and Example Usage 26 | 27 | Install Kient with your preferred package manager. 28 | 29 | ```bash 30 | $ bun add kient 31 | ``` 32 | 33 | Import Kient, create a new instance, and interact with API endpoints or listen to WebSocket events. 34 | 35 | ```ts 36 | import { env } from 'bun' 37 | import { Kient } from 'kient' 38 | 39 | // Create a new kient instance 40 | const kient = new Kient() 41 | 42 | // Set the authentication token 43 | kient.setAuthToken(env.KICK_TOKEN as string) 44 | 45 | // Get the currently authorised user 46 | const currentUser = await kient.api.channel.getAuthorisedUser() 47 | // Log the raw output 48 | console.log(currentUser.raw) 49 | 50 | // Retrieve multiple channels by their ID 51 | const multipleUsers = await kient.api.channel.getByIds([1, 2, 3]) 52 | 53 | // Send a chat message to the first channel in the above list as the authenticated user 54 | await kient.api.chat.send({ 55 | type: 'user', 56 | message: 'Message will be send to specified user id below', 57 | userId: multipleUsers[0].id, 58 | }) 59 | ``` 60 | 61 | ## License 62 | 63 | Kient is licensed under the [MIT License](https://github.com/zSoulweaver/kient/blob/master/LICENSE). 64 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", 3 | "files": { 4 | "ignore": ["node_modules"] 5 | }, 6 | "organizeImports": { 7 | "enabled": true 8 | }, 9 | "linter": { 10 | "enabled": true, 11 | "rules": { 12 | "recommended": true 13 | } 14 | }, 15 | "formatter": { 16 | "enabled": true, 17 | "indentStyle": "tab", 18 | "lineWidth": 100 19 | }, 20 | "javascript": { 21 | "formatter": { 22 | "quoteStyle": "single", 23 | "semicolons": "asNeeded" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /build.ts: -------------------------------------------------------------------------------- 1 | import dts from 'bun-plugin-dts' 2 | 3 | await Bun.build({ 4 | entrypoints: ['./src/index.ts'], 5 | outdir: './dist', 6 | target: 'node', 7 | // @ts-expect-error https://bun.sh/docs/bundler#packages 8 | packages: 'external', 9 | plugins: [dts()], 10 | }) 11 | -------------------------------------------------------------------------------- /bun.lock: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1, 3 | "workspaces": { 4 | "": { 5 | "name": "kient", 6 | "dependencies": { 7 | "@kakasoo/deep-strict-types": "^2.0.2", 8 | "defu": "^6.1.4", 9 | "destr": "^2.0.3", 10 | "hono": "^4.7.2", 11 | "nanoid": "^5.1.0", 12 | "ofetch": "^1.3.4", 13 | "pusher-js": "^8.4.0-rc2", 14 | "tseep": "^1.2.2", 15 | }, 16 | "devDependencies": { 17 | "@biomejs/biome": "1.9.4", 18 | "@types/bun": "^1.2.4", 19 | "@types/node": "^22.13.8", 20 | "bun-plugin-dts": "^0.3.0", 21 | "changelogen": "^0.5.7", 22 | "typedoc": "^0.27.9", 23 | "typedoc-plugin-markdown": "^4.4.2", 24 | "typedoc-plugin-missing-exports": "^3.1.0", 25 | "typedoc-vitepress-theme": "^1.1.2", 26 | "vitepress": "^1.6.3", 27 | }, 28 | "peerDependencies": { 29 | "typescript": "^5.6.3", 30 | }, 31 | }, 32 | }, 33 | "packages": { 34 | "@algolia/autocomplete-core": ["@algolia/autocomplete-core@1.17.7", "", { "dependencies": { "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", "@algolia/autocomplete-shared": "1.17.7" } }, "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q=="], 35 | 36 | "@algolia/autocomplete-plugin-algolia-insights": ["@algolia/autocomplete-plugin-algolia-insights@1.17.7", "", { "dependencies": { "@algolia/autocomplete-shared": "1.17.7" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A=="], 37 | 38 | "@algolia/autocomplete-preset-algolia": ["@algolia/autocomplete-preset-algolia@1.17.7", "", { "dependencies": { "@algolia/autocomplete-shared": "1.17.7" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA=="], 39 | 40 | "@algolia/autocomplete-shared": ["@algolia/autocomplete-shared@1.17.7", "", { "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", "algoliasearch": ">= 4.9.1 < 6" } }, "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg=="], 41 | 42 | "@algolia/client-abtesting": ["@algolia/client-abtesting@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-wPOzHYSsW+H97JkBLmnlOdJSpbb9mIiuNPycUCV5DgzSkJFaI/OFxXfZXAh1gqxK+hf0miKue1C9bltjWljrNA=="], 43 | 44 | "@algolia/client-analytics": ["@algolia/client-analytics@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-XE3iduH9lA7iTQacDGofBQyIyIgaX8qbTRRdj1bOCmfzc9b98CoiMwhNwdTifmmMewmN0EhVF3hP8KjKWwX7Yw=="], 45 | 46 | "@algolia/client-common": ["@algolia/client-common@5.20.3", "", {}, "sha512-IYRd/A/R3BXeaQVT2805lZEdWo54v39Lqa7ABOxIYnUvX2vvOMW1AyzCuT0U7Q+uPdD4UW48zksUKRixShcWxA=="], 47 | 48 | "@algolia/client-insights": ["@algolia/client-insights@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-QGc/bmDUBgzB71rDL6kihI2e1Mx6G6PxYO5Ks84iL3tDcIel1aFuxtRF14P8saGgdIe1B6I6QkpkeIddZ6vWQw=="], 49 | 50 | "@algolia/client-personalization": ["@algolia/client-personalization@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-zuM31VNPDJ1LBIwKbYGz/7+CSm+M8EhlljDamTg8AnDilnCpKjBebWZR5Tftv/FdWSro4tnYGOIz1AURQgZ+tQ=="], 51 | 52 | "@algolia/client-query-suggestions": ["@algolia/client-query-suggestions@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-Nn872PuOI8qzi1bxMMhJ0t2AzVBqN01jbymBQOkypvZHrrjZPso3iTpuuLLo9gi3yc/08vaaWTAwJfPhxPwJUw=="], 53 | 54 | "@algolia/client-search": ["@algolia/client-search@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-9+Fm1ahV8/2goSIPIqZnVitV5yHW5E5xTdKy33xnqGd45A9yVv5tTkudWzEXsbfBB47j9Xb3uYPZjAvV5RHbKA=="], 55 | 56 | "@algolia/ingestion": ["@algolia/ingestion@1.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-5GHNTiZ3saLjTNyr6WkP5hzDg2eFFAYWomvPcm9eHWskjzXt8R0IOiW9kkTS6I6hXBwN5H9Zna5mZDSqqJdg+g=="], 57 | 58 | "@algolia/monitoring": ["@algolia/monitoring@1.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-KUWQbTPoRjP37ivXSQ1+lWMfaifCCMzTnEcEnXwAmherS5Tp7us6BAqQDMGOD4E7xyaS2I8pto6WlOzxH+CxmA=="], 59 | 60 | "@algolia/recommend": ["@algolia/recommend@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-oo/gG77xTTTclkrdFem0Kmx5+iSRFiwuRRdxZETDjwzCI7svutdbwBgV/Vy4D4QpYaX4nhY/P43k84uEowCE4Q=="], 61 | 62 | "@algolia/requester-browser-xhr": ["@algolia/requester-browser-xhr@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3" } }, "sha512-BkkW7otbiI/Er1AiEPZs1h7lxbtSO9p09jFhv3/iT8/0Yz0CY79VJ9iq+Wv1+dq/l0OxnMpBy8mozrieGA3mXQ=="], 63 | 64 | "@algolia/requester-fetch": ["@algolia/requester-fetch@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3" } }, "sha512-eAVlXz7UNzTsA1EDr+p0nlIH7WFxo7k3NMxYe8p38DH8YVWLgm2MgOVFUMNg9HCi6ZNOi/A2w/id2ZZ4sKgUOw=="], 65 | 66 | "@algolia/requester-node-http": ["@algolia/requester-node-http@5.20.3", "", { "dependencies": { "@algolia/client-common": "5.20.3" } }, "sha512-FqR3pQPfHfQyX1wgcdK6iyqu86yP76MZd4Pzj1y/YLMj9rRmRCY0E0AffKr//nrOFEwv6uY8BQY4fd9/6b0ZCg=="], 67 | 68 | "@babel/helper-string-parser": ["@babel/helper-string-parser@7.24.8", "", {}, "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ=="], 69 | 70 | "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.24.7", "", {}, "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w=="], 71 | 72 | "@babel/parser": ["@babel/parser@7.25.3", "", { "dependencies": { "@babel/types": "^7.25.2" }, "bin": "./bin/babel-parser.js" }, "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw=="], 73 | 74 | "@babel/types": ["@babel/types@7.25.2", "", { "dependencies": { "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" } }, "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q=="], 75 | 76 | "@biomejs/biome": ["@biomejs/biome@1.9.4", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "1.9.4", "@biomejs/cli-darwin-x64": "1.9.4", "@biomejs/cli-linux-arm64": "1.9.4", "@biomejs/cli-linux-arm64-musl": "1.9.4", "@biomejs/cli-linux-x64": "1.9.4", "@biomejs/cli-linux-x64-musl": "1.9.4", "@biomejs/cli-win32-arm64": "1.9.4", "@biomejs/cli-win32-x64": "1.9.4" }, "bin": { "biome": "bin/biome" } }, "sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog=="], 77 | 78 | "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@1.9.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw=="], 79 | 80 | "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@1.9.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg=="], 81 | 82 | "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g=="], 83 | 84 | "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@1.9.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA=="], 85 | 86 | "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg=="], 87 | 88 | "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@1.9.4", "", { "os": "linux", "cpu": "x64" }, "sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg=="], 89 | 90 | "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@1.9.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg=="], 91 | 92 | "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@1.9.4", "", { "os": "win32", "cpu": "x64" }, "sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA=="], 93 | 94 | "@docsearch/css": ["@docsearch/css@3.8.2", "", {}, "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ=="], 95 | 96 | "@docsearch/js": ["@docsearch/js@3.8.2", "", { "dependencies": { "@docsearch/react": "3.8.2", "preact": "^10.0.0" } }, "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ=="], 97 | 98 | "@docsearch/react": ["@docsearch/react@3.8.2", "", { "dependencies": { "@algolia/autocomplete-core": "1.17.7", "@algolia/autocomplete-preset-algolia": "1.17.7", "@docsearch/css": "3.8.2", "algoliasearch": "^5.14.2" }, "peerDependencies": { "@types/react": ">= 16.8.0 < 19.0.0", "react": ">= 16.8.0 < 19.0.0", "react-dom": ">= 16.8.0 < 19.0.0", "search-insights": ">= 1 < 3" }, "optionalPeers": ["@types/react", "react", "react-dom", "search-insights"] }, "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg=="], 99 | 100 | "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="], 101 | 102 | "@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="], 103 | 104 | "@esbuild/android-arm64": ["@esbuild/android-arm64@0.21.5", "", { "os": "android", "cpu": "arm64" }, "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A=="], 105 | 106 | "@esbuild/android-x64": ["@esbuild/android-x64@0.21.5", "", { "os": "android", "cpu": "x64" }, "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA=="], 107 | 108 | "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.21.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ=="], 109 | 110 | "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.21.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw=="], 111 | 112 | "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.21.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g=="], 113 | 114 | "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.21.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ=="], 115 | 116 | "@esbuild/linux-arm": ["@esbuild/linux-arm@0.21.5", "", { "os": "linux", "cpu": "arm" }, "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA=="], 117 | 118 | "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.21.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q=="], 119 | 120 | "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.21.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg=="], 121 | 122 | "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg=="], 123 | 124 | "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg=="], 125 | 126 | "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.21.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w=="], 127 | 128 | "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.21.5", "", { "os": "linux", "cpu": "none" }, "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA=="], 129 | 130 | "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.21.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A=="], 131 | 132 | "@esbuild/linux-x64": ["@esbuild/linux-x64@0.21.5", "", { "os": "linux", "cpu": "x64" }, "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ=="], 133 | 134 | "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.21.5", "", { "os": "none", "cpu": "x64" }, "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg=="], 135 | 136 | "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.21.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow=="], 137 | 138 | "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.21.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg=="], 139 | 140 | "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.21.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A=="], 141 | 142 | "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.21.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA=="], 143 | 144 | "@esbuild/win32-x64": ["@esbuild/win32-x64@0.21.5", "", { "os": "win32", "cpu": "x64" }, "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw=="], 145 | 146 | "@gerrit0/mini-shiki": ["@gerrit0/mini-shiki@1.27.2", "", { "dependencies": { "@shikijs/engine-oniguruma": "^1.27.2", "@shikijs/types": "^1.27.2", "@shikijs/vscode-textmate": "^10.0.1" } }, "sha512-GeWyHz8ao2gBiUW4OJnQDxXQnFgZQwwQk05t/CVVgNBN7/rK8XZ7xY6YhLVv9tH3VppWWmr9DCl3MwemB/i+Og=="], 147 | 148 | "@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.26", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-NvqRuE+5h/tp4boPlnvfs0alD0CvnRE7oeG9Li5NGmZRx2/rhwlNjW/vEVTyhZcR9zqvRPAVh2GXR+PTEpzV+A=="], 149 | 150 | "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], 151 | 152 | "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="], 153 | 154 | "@kakasoo/deep-strict-types": ["@kakasoo/deep-strict-types@2.0.2", "", { "dependencies": { "@kakasoo/proto-typescript": "^1.28.7" } }, "sha512-UdIQK2gkAiamPZonXfoiTyrtLJ7/pgFIQDJ+o8Frftf0YcRSGkFG8fIYg1uuThW0CNBZSH2dSyaGD9ElfLjZIw=="], 155 | 156 | "@kakasoo/proto-typescript": ["@kakasoo/proto-typescript@1.28.8", "", {}, "sha512-5lbFseSDzrZaQifPyDlFgCnB0duFb3ISi3fU7DGTMnZatIVEBz5rZZX0Wkq6HwsX5TNm0b+2d3s03tmPKh4WWw=="], 157 | 158 | "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.34.9", "", { "os": "android", "cpu": "arm" }, "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA=="], 159 | 160 | "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.34.9", "", { "os": "android", "cpu": "arm64" }, "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg=="], 161 | 162 | "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.34.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ=="], 163 | 164 | "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.34.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q=="], 165 | 166 | "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.34.9", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw=="], 167 | 168 | "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.34.9", "", { "os": "freebsd", "cpu": "x64" }, "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g=="], 169 | 170 | "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.34.9", "", { "os": "linux", "cpu": "arm" }, "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg=="], 171 | 172 | "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.34.9", "", { "os": "linux", "cpu": "arm" }, "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA=="], 173 | 174 | "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.34.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw=="], 175 | 176 | "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.34.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A=="], 177 | 178 | "@rollup/rollup-linux-loongarch64-gnu": ["@rollup/rollup-linux-loongarch64-gnu@4.34.9", "", { "os": "linux", "cpu": "none" }, "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg=="], 179 | 180 | "@rollup/rollup-linux-powerpc64le-gnu": ["@rollup/rollup-linux-powerpc64le-gnu@4.34.9", "", { "os": "linux", "cpu": "ppc64" }, "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA=="], 181 | 182 | "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.34.9", "", { "os": "linux", "cpu": "none" }, "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg=="], 183 | 184 | "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.34.9", "", { "os": "linux", "cpu": "s390x" }, "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ=="], 185 | 186 | "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.34.9", "", { "os": "linux", "cpu": "x64" }, "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A=="], 187 | 188 | "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.34.9", "", { "os": "linux", "cpu": "x64" }, "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA=="], 189 | 190 | "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.34.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q=="], 191 | 192 | "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.34.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w=="], 193 | 194 | "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.34.9", "", { "os": "win32", "cpu": "x64" }, "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw=="], 195 | 196 | "@shikijs/core": ["@shikijs/core@2.5.0", "", { "dependencies": { "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.4" } }, "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg=="], 197 | 198 | "@shikijs/engine-javascript": ["@shikijs/engine-javascript@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^3.1.0" } }, "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w=="], 199 | 200 | "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@1.29.2", "", { "dependencies": { "@shikijs/types": "1.29.2", "@shikijs/vscode-textmate": "^10.0.1" } }, "sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA=="], 201 | 202 | "@shikijs/langs": ["@shikijs/langs@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0" } }, "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w=="], 203 | 204 | "@shikijs/themes": ["@shikijs/themes@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0" } }, "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw=="], 205 | 206 | "@shikijs/transformers": ["@shikijs/transformers@2.5.0", "", { "dependencies": { "@shikijs/core": "2.5.0", "@shikijs/types": "2.5.0" } }, "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg=="], 207 | 208 | "@shikijs/types": ["@shikijs/types@2.5.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw=="], 209 | 210 | "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], 211 | 212 | "@types/bun": ["@types/bun@1.2.4", "", { "dependencies": { "bun-types": "1.2.4" } }, "sha512-QtuV5OMR8/rdKJs213iwXDpfVvnskPXY/S0ZiFbsTjQZycuqPbMW8Gf/XhLfwE5njW8sxI2WjISURXPlHypMFA=="], 213 | 214 | "@types/estree": ["@types/estree@1.0.6", "", {}, "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw=="], 215 | 216 | "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], 217 | 218 | "@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="], 219 | 220 | "@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="], 221 | 222 | "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], 223 | 224 | "@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="], 225 | 226 | "@types/node": ["@types/node@22.13.8", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ=="], 227 | 228 | "@types/unist": ["@types/unist@3.0.2", "", {}, "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ=="], 229 | 230 | "@types/web-bluetooth": ["@types/web-bluetooth@0.0.20", "", {}, "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow=="], 231 | 232 | "@types/ws": ["@types/ws@8.5.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A=="], 233 | 234 | "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], 235 | 236 | "@vitejs/plugin-vue": ["@vitejs/plugin-vue@5.2.1", "", { "peerDependencies": { "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ=="], 237 | 238 | "@vue/compiler-core": ["@vue/compiler-core@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/shared": "3.5.13", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q=="], 239 | 240 | "@vue/compiler-dom": ["@vue/compiler-dom@3.5.13", "", { "dependencies": { "@vue/compiler-core": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA=="], 241 | 242 | "@vue/compiler-sfc": ["@vue/compiler-sfc@3.5.13", "", { "dependencies": { "@babel/parser": "^7.25.3", "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13", "estree-walker": "^2.0.2", "magic-string": "^0.30.11", "postcss": "^8.4.48", "source-map-js": "^1.2.0" } }, "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ=="], 243 | 244 | "@vue/compiler-ssr": ["@vue/compiler-ssr@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA=="], 245 | 246 | "@vue/devtools-api": ["@vue/devtools-api@7.7.2", "", { "dependencies": { "@vue/devtools-kit": "^7.7.2" } }, "sha512-1syn558KhyN+chO5SjlZIwJ8bV/bQ1nOVTG66t2RbG66ZGekyiYNmRO7X9BJCXQqPsFHlnksqvPhce2qpzxFnA=="], 247 | 248 | "@vue/devtools-kit": ["@vue/devtools-kit@7.7.2", "", { "dependencies": { "@vue/devtools-shared": "^7.7.2", "birpc": "^0.2.19", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", "superjson": "^2.2.1" } }, "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ=="], 249 | 250 | "@vue/devtools-shared": ["@vue/devtools-shared@7.7.2", "", { "dependencies": { "rfdc": "^1.4.1" } }, "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA=="], 251 | 252 | "@vue/reactivity": ["@vue/reactivity@3.5.13", "", { "dependencies": { "@vue/shared": "3.5.13" } }, "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg=="], 253 | 254 | "@vue/runtime-core": ["@vue/runtime-core@3.5.13", "", { "dependencies": { "@vue/reactivity": "3.5.13", "@vue/shared": "3.5.13" } }, "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw=="], 255 | 256 | "@vue/runtime-dom": ["@vue/runtime-dom@3.5.13", "", { "dependencies": { "@vue/reactivity": "3.5.13", "@vue/runtime-core": "3.5.13", "@vue/shared": "3.5.13", "csstype": "^3.1.3" } }, "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog=="], 257 | 258 | "@vue/server-renderer": ["@vue/server-renderer@3.5.13", "", { "dependencies": { "@vue/compiler-ssr": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "vue": "3.5.13" } }, "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA=="], 259 | 260 | "@vue/shared": ["@vue/shared@3.5.13", "", {}, "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ=="], 261 | 262 | "@vueuse/core": ["@vueuse/core@12.7.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.20", "@vueuse/metadata": "12.7.0", "@vueuse/shared": "12.7.0", "vue": "^3.5.13" } }, "sha512-jtK5B7YjZXmkGNHjviyGO4s3ZtEhbzSgrbX+s5o+Lr8i2nYqNyHuPVOeTdM1/hZ5Tkxg/KktAuAVDDiHMraMVA=="], 263 | 264 | "@vueuse/integrations": ["@vueuse/integrations@12.7.0", "", { "dependencies": { "@vueuse/core": "12.7.0", "@vueuse/shared": "12.7.0", "vue": "^3.5.13" }, "peerDependencies": { "async-validator": "^4", "axios": "^1", "change-case": "^5", "drauu": "^0.4", "focus-trap": "^7", "fuse.js": "^7", "idb-keyval": "^6", "jwt-decode": "^4", "nprogress": "^0.2", "qrcode": "^1.5", "sortablejs": "^1", "universal-cookie": "^7" }, "optionalPeers": ["async-validator", "axios", "change-case", "drauu", "focus-trap", "fuse.js", "idb-keyval", "jwt-decode", "nprogress", "qrcode", "sortablejs", "universal-cookie"] }, "sha512-IEq7K4bCl7mn3uKJaWtNXnd1CAPaHLUMuyj5K1/k/pVcItt0VONZW8xiGxdIovJcQjkzOHjImhX5t6gija+0/g=="], 265 | 266 | "@vueuse/metadata": ["@vueuse/metadata@12.7.0", "", {}, "sha512-4VvTH9mrjXqFN5LYa5YfqHVRI6j7R00Vy4995Rw7PQxyCL3z0Lli86iN4UemWqixxEvYfRjG+hF9wL8oLOn+3g=="], 267 | 268 | "@vueuse/shared": ["@vueuse/shared@12.7.0", "", { "dependencies": { "vue": "^3.5.13" } }, "sha512-coLlUw2HHKsm7rPN6WqHJQr18WymN4wkA/3ThFaJ4v4gWGWAQQGK+MJxLuJTBs4mojQiazlVWAKNJNpUWGRkNw=="], 269 | 270 | "acorn": ["acorn@8.13.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w=="], 271 | 272 | "algoliasearch": ["algoliasearch@5.20.3", "", { "dependencies": { "@algolia/client-abtesting": "5.20.3", "@algolia/client-analytics": "5.20.3", "@algolia/client-common": "5.20.3", "@algolia/client-insights": "5.20.3", "@algolia/client-personalization": "5.20.3", "@algolia/client-query-suggestions": "5.20.3", "@algolia/client-search": "5.20.3", "@algolia/ingestion": "1.20.3", "@algolia/monitoring": "1.20.3", "@algolia/recommend": "5.20.3", "@algolia/requester-browser-xhr": "5.20.3", "@algolia/requester-fetch": "5.20.3", "@algolia/requester-node-http": "5.20.3" } }, "sha512-iNC6BGvipaalFfDfDnXUje8GUlW5asj0cTMsZJwO/0rhsyLx1L7GZFAY8wW+eQ6AM4Yge2p5GSE5hrBlfSD90Q=="], 273 | 274 | "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], 275 | 276 | "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 277 | 278 | "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], 279 | 280 | "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], 281 | 282 | "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], 283 | 284 | "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], 285 | 286 | "birpc": ["birpc@0.2.19", "", {}, "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ=="], 287 | 288 | "brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="], 289 | 290 | "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], 291 | 292 | "bun-plugin-dts": ["bun-plugin-dts@0.3.0", "", { "dependencies": { "common-path-prefix": "^3.0.0", "dts-bundle-generator": "^9.5.1", "get-tsconfig": "^4.8.1" } }, "sha512-QpiAOKfPcdOToxySOqRY8FwL+brTvyXEHWzrSCRKt4Pv7Z4pnUrhK9tFtM7Ndm7ED09B/0cGXnHJKqmekr/ERw=="], 293 | 294 | "bun-types": ["bun-types@1.2.4", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-nDPymR207ZZEoWD4AavvEaa/KZe/qlrbMSchqpQwovPZCKc7pwMoENjEtHgMKaAjJhy+x6vfqSBA1QU3bJgs0Q=="], 295 | 296 | "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], 297 | 298 | "c12": ["c12@1.11.2", "", { "dependencies": { "chokidar": "^3.6.0", "confbox": "^0.1.7", "defu": "^6.1.4", "dotenv": "^16.4.5", "giget": "^1.2.3", "jiti": "^1.21.6", "mlly": "^1.7.1", "ohash": "^1.1.3", "pathe": "^1.1.2", "perfect-debounce": "^1.0.0", "pkg-types": "^1.2.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "^0.3.4" }, "optionalPeers": ["magicast"] }, "sha512-oBs8a4uvSDO9dm8b7OCFW7+dgtVrwmwnrVXYzLm43ta7ep2jCn/0MhoUFygIWtxhyy6+/MG7/agvpY0U1Iemew=="], 299 | 300 | "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], 301 | 302 | "changelogen": ["changelogen@0.5.7", "", { "dependencies": { "c12": "^1.11.2", "colorette": "^2.0.20", "consola": "^3.2.3", "convert-gitmoji": "^0.1.5", "mri": "^1.2.0", "node-fetch-native": "^1.6.4", "ofetch": "^1.3.4", "open": "^10.1.0", "pathe": "^1.1.2", "pkg-types": "^1.2.0", "scule": "^1.3.0", "semver": "^7.6.3", "std-env": "^3.7.0", "yaml": "^2.5.1" }, "bin": { "changelogen": "dist/cli.mjs" } }, "sha512-cTZXBcJMl3pudE40WENOakXkcVtrbBpbkmSkM20NdRiUqa4+VYRdXdEsgQ0BNQ6JBE2YymTNWtPKVF7UCTN5+g=="], 303 | 304 | "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], 305 | 306 | "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], 307 | 308 | "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], 309 | 310 | "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], 311 | 312 | "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], 313 | 314 | "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], 315 | 316 | "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 317 | 318 | "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 319 | 320 | "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], 321 | 322 | "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], 323 | 324 | "common-path-prefix": ["common-path-prefix@3.0.0", "", {}, "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w=="], 325 | 326 | "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], 327 | 328 | "consola": ["consola@3.2.3", "", {}, "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ=="], 329 | 330 | "convert-gitmoji": ["convert-gitmoji@0.1.5", "", {}, "sha512-4wqOafJdk2tqZC++cjcbGcaJ13BZ3kwldf06PTiAQRAB76Z1KJwZNL1SaRZMi2w1FM9RYTgZ6QErS8NUl/GBmQ=="], 331 | 332 | "copy-anything": ["copy-anything@3.0.5", "", { "dependencies": { "is-what": "^4.1.8" } }, "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w=="], 333 | 334 | "cross-spawn": ["cross-spawn@7.0.3", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="], 335 | 336 | "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], 337 | 338 | "default-browser": ["default-browser@5.2.1", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg=="], 339 | 340 | "default-browser-id": ["default-browser-id@5.0.0", "", {}, "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA=="], 341 | 342 | "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], 343 | 344 | "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], 345 | 346 | "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], 347 | 348 | "destr": ["destr@2.0.3", "", {}, "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ=="], 349 | 350 | "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], 351 | 352 | "dotenv": ["dotenv@16.4.5", "", {}, "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg=="], 353 | 354 | "dts-bundle-generator": ["dts-bundle-generator@9.5.1", "", { "dependencies": { "typescript": ">=5.0.2", "yargs": "^17.6.0" }, "bin": { "dts-bundle-generator": "dist/bin/dts-bundle-generator.js" } }, "sha512-DxpJOb2FNnEyOzMkG11sxO2dmxPjthoVWxfKqWYJ/bI/rT1rvTMktF5EKjAYrRZu6Z6t3NhOUZ0sZ5ZXevOfbA=="], 355 | 356 | "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], 357 | 358 | "emoji-regex-xs": ["emoji-regex-xs@1.0.0", "", {}, "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg=="], 359 | 360 | "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], 361 | 362 | "esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="], 363 | 364 | "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], 365 | 366 | "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], 367 | 368 | "execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], 369 | 370 | "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], 371 | 372 | "focus-trap": ["focus-trap@7.6.4", "", { "dependencies": { "tabbable": "^6.2.0" } }, "sha512-xx560wGBk7seZ6y933idtjJQc1l+ck+pI3sKvhKozdBV1dRZoKhkW5xoCaFv9tQiX5RH1xfSxjuNu6g+lmN/gw=="], 373 | 374 | "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], 375 | 376 | "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 377 | 378 | "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], 379 | 380 | "get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], 381 | 382 | "get-tsconfig": ["get-tsconfig@4.8.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg=="], 383 | 384 | "giget": ["giget@1.2.3", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.2.3", "defu": "^6.1.4", "node-fetch-native": "^1.6.3", "nypm": "^0.3.8", "ohash": "^1.1.3", "pathe": "^1.1.2", "tar": "^6.2.0" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-8EHPljDvs7qKykr6uw8b+lqLiUc/vUg+KVTI0uND4s63TdsZM2Xus3mflvF0DDG9SiM4RlCkFGL+7aAjRmV7KA=="], 385 | 386 | "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], 387 | 388 | "hast-util-to-html": ["hast-util-to-html@9.0.5", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/unist": "^3.0.0", "ccount": "^2.0.0", "comma-separated-tokens": "^2.0.0", "hast-util-whitespace": "^3.0.0", "html-void-elements": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "property-information": "^7.0.0", "space-separated-tokens": "^2.0.0", "stringify-entities": "^4.0.0", "zwitch": "^2.0.4" } }, "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw=="], 389 | 390 | "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "^3.0.0" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], 391 | 392 | "hono": ["hono@4.7.2", "", {}, "sha512-8V5XxoOF6SI12jkHkzX/6aLBMU5GEF5g387EjVSQipS0DlxWgWGSMeEayY3CRBjtTUQYwLHx9JYouWqKzy2Vng=="], 393 | 394 | "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], 395 | 396 | "html-void-elements": ["html-void-elements@3.0.0", "", {}, "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg=="], 397 | 398 | "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], 399 | 400 | "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], 401 | 402 | "is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], 403 | 404 | "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 405 | 406 | "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], 407 | 408 | "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 409 | 410 | "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], 411 | 412 | "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], 413 | 414 | "is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], 415 | 416 | "is-what": ["is-what@4.1.16", "", {}, "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A=="], 417 | 418 | "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], 419 | 420 | "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 421 | 422 | "jiti": ["jiti@1.21.6", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w=="], 423 | 424 | "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "^2.0.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], 425 | 426 | "lunr": ["lunr@2.3.9", "", {}, "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow=="], 427 | 428 | "magic-string": ["magic-string@0.30.11", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A=="], 429 | 430 | "mark.js": ["mark.js@8.11.1", "", {}, "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ=="], 431 | 432 | "markdown-it": ["markdown-it@14.1.0", "", { "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", "linkify-it": "^5.0.0", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg=="], 433 | 434 | "mdast-util-to-hast": ["mdast-util-to-hast@13.2.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "@ungap/structured-clone": "^1.0.0", "devlop": "^1.0.0", "micromark-util-sanitize-uri": "^2.0.0", "trim-lines": "^3.0.0", "unist-util-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" } }, "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA=="], 435 | 436 | "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], 437 | 438 | "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], 439 | 440 | "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], 441 | 442 | "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], 443 | 444 | "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", "micromark-util-symbol": "^2.0.0" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], 445 | 446 | "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], 447 | 448 | "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], 449 | 450 | "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], 451 | 452 | "minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], 453 | 454 | "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], 455 | 456 | "minisearch": ["minisearch@7.1.2", "", {}, "sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA=="], 457 | 458 | "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], 459 | 460 | "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], 461 | 462 | "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], 463 | 464 | "mlly": ["mlly@1.7.2", "", { "dependencies": { "acorn": "^8.12.1", "pathe": "^1.1.2", "pkg-types": "^1.2.0", "ufo": "^1.5.4" } }, "sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA=="], 465 | 466 | "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], 467 | 468 | "nanoid": ["nanoid@5.1.0", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-zDAl/llz8Ue/EblwSYwdxGBYfj46IM1dhjVi8dyp9LQffoIGxJEAHj2oeZ4uNcgycSRcQ83CnfcZqEJzVDLcDw=="], 469 | 470 | "node-fetch-native": ["node-fetch-native@1.6.4", "", {}, "sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ=="], 471 | 472 | "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], 473 | 474 | "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], 475 | 476 | "nypm": ["nypm@0.3.12", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.2.3", "execa": "^8.0.1", "pathe": "^1.1.2", "pkg-types": "^1.2.0", "ufo": "^1.5.4" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA=="], 477 | 478 | "ofetch": ["ofetch@1.3.4", "", { "dependencies": { "destr": "^2.0.3", "node-fetch-native": "^1.6.3", "ufo": "^1.5.3" } }, "sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw=="], 479 | 480 | "ohash": ["ohash@1.1.4", "", {}, "sha512-FlDryZAahJmEF3VR3w1KogSEdWX3WhA5GPakFx4J81kEAiHyLMpdLLElS8n8dfNadMgAne/MywcvmogzscVt4g=="], 481 | 482 | "onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], 483 | 484 | "oniguruma-to-es": ["oniguruma-to-es@3.1.1", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^6.0.1", "regex-recursion": "^6.0.2" } }, "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ=="], 485 | 486 | "open": ["open@10.1.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "is-wsl": "^3.1.0" } }, "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw=="], 487 | 488 | "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], 489 | 490 | "pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], 491 | 492 | "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], 493 | 494 | "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 495 | 496 | "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 497 | 498 | "pkg-types": ["pkg-types@1.2.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.2", "pathe": "^1.1.2" } }, "sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw=="], 499 | 500 | "postcss": ["postcss@8.5.3", "", { "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A=="], 501 | 502 | "preact": ["preact@10.23.1", "", {}, "sha512-O5UdRsNh4vdZaTieWe3XOgSpdMAmkIYBCT3VhQDlKrzyCm8lUYsk0fmVEvoQQifoOjFRTaHZO69ylrzTW2BH+A=="], 503 | 504 | "property-information": ["property-information@7.0.0", "", {}, "sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg=="], 505 | 506 | "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], 507 | 508 | "pusher-js": ["pusher-js@8.4.0-rc2", "", { "dependencies": { "tweetnacl": "^1.0.3" } }, "sha512-d87GjOEEl9QgO5BWmViSqW0LOzPvybvX6WA9zLUstNdB57jVJuR27zHkRnrav2a3+zAMlHbP2Og8wug+rG8T+g=="], 509 | 510 | "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], 511 | 512 | "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], 513 | 514 | "regex": ["regex@6.0.1", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA=="], 515 | 516 | "regex-recursion": ["regex-recursion@6.0.2", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg=="], 517 | 518 | "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], 519 | 520 | "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], 521 | 522 | "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], 523 | 524 | "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], 525 | 526 | "rollup": ["rollup@4.34.9", "", { "dependencies": { "@types/estree": "1.0.6" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.34.9", "@rollup/rollup-android-arm64": "4.34.9", "@rollup/rollup-darwin-arm64": "4.34.9", "@rollup/rollup-darwin-x64": "4.34.9", "@rollup/rollup-freebsd-arm64": "4.34.9", "@rollup/rollup-freebsd-x64": "4.34.9", "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", "@rollup/rollup-linux-arm-musleabihf": "4.34.9", "@rollup/rollup-linux-arm64-gnu": "4.34.9", "@rollup/rollup-linux-arm64-musl": "4.34.9", "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", "@rollup/rollup-linux-riscv64-gnu": "4.34.9", "@rollup/rollup-linux-s390x-gnu": "4.34.9", "@rollup/rollup-linux-x64-gnu": "4.34.9", "@rollup/rollup-linux-x64-musl": "4.34.9", "@rollup/rollup-win32-arm64-msvc": "4.34.9", "@rollup/rollup-win32-ia32-msvc": "4.34.9", "@rollup/rollup-win32-x64-msvc": "4.34.9", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ=="], 527 | 528 | "run-applescript": ["run-applescript@7.0.0", "", {}, "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A=="], 529 | 530 | "scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="], 531 | 532 | "search-insights": ["search-insights@2.15.0", "", {}, "sha512-ch2sPCUDD4sbPQdknVl9ALSi9H7VyoeVbsxznYz6QV55jJ8CI3EtwpO1i84keN4+hF5IeHWIeGvc08530JkVXQ=="], 533 | 534 | "semver": ["semver@7.6.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A=="], 535 | 536 | "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], 537 | 538 | "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], 539 | 540 | "shiki": ["shiki@2.5.0", "", { "dependencies": { "@shikijs/core": "2.5.0", "@shikijs/engine-javascript": "2.5.0", "@shikijs/engine-oniguruma": "2.5.0", "@shikijs/langs": "2.5.0", "@shikijs/themes": "2.5.0", "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ=="], 541 | 542 | "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], 543 | 544 | "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 545 | 546 | "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], 547 | 548 | "speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="], 549 | 550 | "std-env": ["std-env@3.7.0", "", {}, "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg=="], 551 | 552 | "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=="], 553 | 554 | "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], 555 | 556 | "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], 557 | 558 | "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], 559 | 560 | "superjson": ["superjson@2.2.1", "", { "dependencies": { "copy-anything": "^3.0.2" } }, "sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA=="], 561 | 562 | "tabbable": ["tabbable@6.2.0", "", {}, "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="], 563 | 564 | "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], 565 | 566 | "to-fast-properties": ["to-fast-properties@2.0.0", "", {}, "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog=="], 567 | 568 | "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], 569 | 570 | "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], 571 | 572 | "tseep": ["tseep@1.2.2", "", {}, "sha512-GgPFuNx+08UaYBYmJQmuI86ykYa2PUUtfXAYb4MLRHGunSCp8k9N+dbsR4PK1yk4/zV9q4e4PrNg8ymXqGYaYA=="], 573 | 574 | "tweetnacl": ["tweetnacl@1.0.3", "", {}, "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="], 575 | 576 | "typedoc": ["typedoc@0.27.9", "", { "dependencies": { "@gerrit0/mini-shiki": "^1.24.0", "lunr": "^2.3.9", "markdown-it": "^14.1.0", "minimatch": "^9.0.5", "yaml": "^2.6.1" }, "peerDependencies": { "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x" }, "bin": { "typedoc": "bin/typedoc" } }, "sha512-/z585740YHURLl9DN2jCWe6OW7zKYm6VoQ93H0sxZ1cwHQEQrUn5BJrEnkWhfzUdyO+BLGjnKUZ9iz9hKloFDw=="], 577 | 578 | "typedoc-plugin-markdown": ["typedoc-plugin-markdown@4.4.2", "", { "peerDependencies": { "typedoc": "0.27.x" } }, "sha512-kJVkU2Wd+AXQpyL6DlYXXRrfNrHrEIUgiABWH8Z+2Lz5Sq6an4dQ/hfvP75bbokjNDUskOdFlEEm/0fSVyC7eg=="], 579 | 580 | "typedoc-plugin-missing-exports": ["typedoc-plugin-missing-exports@3.1.0", "", { "peerDependencies": { "typedoc": "0.26.x || 0.27.x" } }, "sha512-Sogbaj+qDa21NjB3SlIw4JXSwmcl/WOjwiPNaVEcPhpNG/MiRTtpwV81cT7h1cbu9StpONFPbddYWR0KV/fTWA=="], 581 | 582 | "typedoc-vitepress-theme": ["typedoc-vitepress-theme@1.1.2", "", { "peerDependencies": { "typedoc-plugin-markdown": ">=4.4.0" } }, "sha512-hQvCZRr5uKDqY1bRuY1+eNTNn6d4TE4OP5pnw65Y7WGgajkJW9X1/lVJK2UJpcwCmwkdjw1QIO49H9JQlxWhhw=="], 583 | 584 | "typescript": ["typescript@5.6.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw=="], 585 | 586 | "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], 587 | 588 | "ufo": ["ufo@1.5.3", "", {}, "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw=="], 589 | 590 | "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="], 591 | 592 | "unist-util-is": ["unist-util-is@6.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw=="], 593 | 594 | "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], 595 | 596 | "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "^3.0.0" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], 597 | 598 | "unist-util-visit": ["unist-util-visit@5.0.0", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", "unist-util-visit-parents": "^6.0.0" } }, "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg=="], 599 | 600 | "unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="], 601 | 602 | "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], 603 | 604 | "vfile-message": ["vfile-message@4.0.2", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw=="], 605 | 606 | "vite": ["vite@5.4.14", "", { "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "optionalPeers": ["@types/node", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser"], "bin": { "vite": "bin/vite.js" } }, "sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA=="], 607 | 608 | "vitepress": ["vitepress@1.6.3", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-fCkfdOk8yRZT8GD9BFqusW3+GggWYZ/rYncOfmgcDtP3ualNHCAg+Robxp2/6xfH1WwPHtGpPwv7mbA3qomtBw=="], 609 | 610 | "vue": ["vue@3.5.13", "", { "dependencies": { "@vue/compiler-dom": "3.5.13", "@vue/compiler-sfc": "3.5.13", "@vue/runtime-dom": "3.5.13", "@vue/server-renderer": "3.5.13", "@vue/shared": "3.5.13" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ=="], 611 | 612 | "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], 613 | 614 | "wrap-ansi": ["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=="], 615 | 616 | "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], 617 | 618 | "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], 619 | 620 | "yaml": ["yaml@2.6.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ=="], 621 | 622 | "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], 623 | 624 | "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], 625 | 626 | "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], 627 | 628 | "@gerrit0/mini-shiki/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="], 629 | 630 | "@shikijs/core/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw=="], 631 | 632 | "@shikijs/engine-oniguruma/@shikijs/types": ["@shikijs/types@1.29.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.1", "@types/hast": "^3.0.4" } }, "sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw=="], 633 | 634 | "@types/ws/@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="], 635 | 636 | "@vue/compiler-core/source-map-js": ["source-map-js@1.2.0", "", {}, "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg=="], 637 | 638 | "@vue/compiler-sfc/source-map-js": ["source-map-js@1.2.0", "", {}, "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg=="], 639 | 640 | "bun-types/@types/node": ["@types/node@20.12.14", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg=="], 641 | 642 | "dts-bundle-generator/typescript": ["typescript@5.5.4", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q=="], 643 | 644 | "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], 645 | 646 | "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], 647 | 648 | "mlly/ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="], 649 | 650 | "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], 651 | 652 | "nypm/ufo": ["ufo@1.5.4", "", {}, "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ=="], 653 | 654 | "postcss/nanoid": ["nanoid@3.3.8", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w=="], 655 | 656 | "shiki/@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@2.5.0", "", { "dependencies": { "@shikijs/types": "2.5.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw=="], 657 | 658 | "typedoc/yaml": ["yaml@2.7.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA=="], 659 | 660 | "@types/ws/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], 661 | 662 | "bun-types/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], 663 | } 664 | } 665 | -------------------------------------------------------------------------------- /bunfig.toml: -------------------------------------------------------------------------------- 1 | [install] 2 | peer = true 3 | -------------------------------------------------------------------------------- /docs/.typedoc/context/sources.js: -------------------------------------------------------------------------------- 1 | import { ReflectionKind } from 'typedoc' 2 | // import { link } from 'typedoc-plugin-markdown/dist/libs/markdown/link.js' 3 | // import { escapeChars } from 'typedoc-plugin-markdown/dist/libs/utils/escape-chars.js' 4 | 5 | 6 | /** 7 | * @param {import('typedoc').SignatureReflection} model 8 | */ 9 | export function sources(model) { 10 | 11 | const md = [] 12 | 13 | model.sources?.forEach((source, index) => { 14 | if (index === 0) { 15 | if (source.url) { 16 | const linkHref = link(`${escapeChars(source.fileName)}:${source.line}`, source.url) 17 | if (model.kind === ReflectionKind.Property) { 18 | md.push(linkHref) 19 | } else { 20 | md.push(`${linkHref}`) 21 | } 22 | } else { 23 | const linkHref = `${escapeChars(source.fileName)}:${source.line}` 24 | if (model.kind === ReflectionKind.Property) { 25 | md.push(linkHref) 26 | } else { 27 | md.push(`${linkHref}`) 28 | } 29 | } 30 | } 31 | }) 32 | return md.join('\n\n') 33 | } 34 | 35 | function escapeChars(chars) { 36 | return chars 37 | .replace(/>/g, '\\>') 38 | .replace(/ sources(model, options), 24 | } 25 | 26 | helpers = { 27 | ...this.helpers, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/.vitepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | import typedocSidebar from '../typedoc/typedoc-sidebar.json' 3 | 4 | // https://vitepress.dev/reference/site-config 5 | export default defineConfig({ 6 | title: 'Kient', 7 | description: "Typescript API wrapper for Kick's API", 8 | cleanUrls: true, 9 | themeConfig: { 10 | // https://vitepress.dev/reference/default-theme-config 11 | nav: [ 12 | { text: 'Home', link: '/' }, 13 | { text: 'Guide', link: '/guide/what-is-kient' }, 14 | { text: 'API Reference', link: '/typedoc/' }, 15 | ], 16 | 17 | sidebar: { 18 | '/guide': [ 19 | { 20 | text: 'Introduction', 21 | items: [{ text: 'What is Kient?', link: '/guide/what-is-kient' }], 22 | }, 23 | ], 24 | '/typedoc': typedocSidebar, 25 | }, 26 | 27 | socialLinks: [{ icon: 'github', link: 'https://github.com/zSoulweaver/kient' }], 28 | outline: [2, 3], 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.bunny.net/css?family=fira-code:400|inter:400,700); 2 | 3 | :root { 4 | --vp-font-family-base: 5 | "Chinese Quotes", "Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 6 | --vp-font-family-mono: "Fira Code", ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, 7 | Consolas, "Liberation Mono", "Courier New", monospace; 8 | 9 | --vp-c-brand-1: var(--vp-c-green-1); 10 | --vp-c-brand-2: var(--vp-c-green-2); 11 | --vp-c-brand-3: var(--vp-c-green-3); 12 | --vp-c-brand-soft: var(--vp-c-green-soft); 13 | } 14 | 15 | .source-link, 16 | .source-link > a { 17 | font-size: 0.8rem; 18 | color: var(--vp-c-brand-soft); 19 | } 20 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme-without-fonts' 2 | import './custom.css' 3 | 4 | export default DefaultTheme 5 | -------------------------------------------------------------------------------- /docs/guide/what-is-kient.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: false 3 | --- 4 | 5 | # What is Kient? 6 | Kient is a versatile TypeScript client designed to simplify interaction with Kick's API and Webhooks. With Kient, you can seamlessly integrate Kick's platform into your projects, making it easier than ever to leverage its capabilities. 7 | 8 |
9 | 10 | Wanting to try it out? Skip to [**Getting Started**](./what-is-kient). 11 | 12 |
13 | 14 | ## Key Features 15 | - ✨ **Easy Setup:** Get up and running quickly with Kient's straightforward installation and configuration process. 16 | - 🔌 **API Integration:** Connect to Kick's API endpoints effortlessly with Kient's well-organized methods and utilities. 17 | - 🛠️ **TypeScript Compatibility:** Enjoy type safety and intelligent autocompletion in modern code editors with Kient's TypeScript-first approach. 18 | - 📖 **Comprehensive Documentation**: Explore Kient's full range of features through detailed documentation, complete with examples and guides. 19 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "Kient" 7 | text: "Typescript API wrapper for Kick's API" 8 | actions: 9 | - theme: brand 10 | text: Guide 11 | link: /guide/what-is-kient 12 | - theme: alt 13 | text: TypeDoc API Reference 14 | link: /typedoc 15 | 16 | features: 17 | - icon: ✨ 18 | title: Typescript-First Design 19 | details: Love Typescript? Same—Kient sprinkles in that magic to ensure your app development is a breeze 20 | - icon: 🔧 21 | title: All-In-One Toolkit 22 | details: Possibilities are endless—build that wild idea you’ve been dreaming about 23 | - icon: 📜 24 | title: MIT Freedom 25 | details: No strings attached—hack it, fork it, or flaunt it, it’s all yours! 26 | --- 27 | 28 | -------------------------------------------------------------------------------- /example/app-token.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { KientAppTokenAuthentication } from 'kient' 3 | 4 | const auth = new KientAppTokenAuthentication({ 5 | clientId: env.KICK_CLIENT_ID as string, 6 | clientSecret: env.KICK_CLIENT_SECRET as string, 7 | }) 8 | 9 | const tokenDetails = await auth.generateToken() 10 | console.log(tokenDetails) -------------------------------------------------------------------------------- /example/auth.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { Hono } from 'hono' 3 | import { HTTPException } from 'hono/http-exception' 4 | import { KientUserTokenAuthentication } from 'kient' 5 | 6 | const app = new Hono() 7 | 8 | const auth = new KientUserTokenAuthentication({ 9 | redirectUri: 'http://localhost:3000/callback', 10 | clientId: env.KICK_CLIENT_ID as string, 11 | clientSecret: env.KICK_CLIENT_SECRET as string, 12 | }) 13 | 14 | const url = auth.constructAuthoriseUrl({ 15 | scopes: [ 16 | 'channel:read', 17 | 'channel:write', 18 | 'chat:write', 19 | 'events:subscribe', 20 | 'streamkey:read', 21 | 'user:read', 22 | ], 23 | }) 24 | 25 | console.log(url) 26 | 27 | app.get('/callback', async (c) => { 28 | const code = c.req.query('code') 29 | if (!code) { 30 | throw new HTTPException(400, { message: 'No code found in the url' }) 31 | } 32 | const token = await auth.generateToken({ 33 | code, 34 | codeVerifier: url.verifier, 35 | }) 36 | 37 | return c.body(JSON.stringify(token)) 38 | }) 39 | 40 | Bun.serve({ 41 | fetch: app.fetch, 42 | port: 3000, 43 | }) 44 | -------------------------------------------------------------------------------- /example/get-categories.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { Kient } from 'kient' 3 | 4 | const kient = new Kient() 5 | kient.setAuthToken(env.KICK_TOKEN as string) 6 | const res = await kient.api.category.query('final') 7 | 8 | console.log(res.map((cat) => cat.toJSON())) 9 | -------------------------------------------------------------------------------- /example/get-channels.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { Kient, kientToJSON } from 'kient' 3 | 4 | const kient = new Kient() 5 | kient.setAuthToken(env.KICK_TOKEN as string) 6 | 7 | // const currentUser = await kient.api.channel.getAuthorisedUser() 8 | // console.log(currentUser.toJSON()) 9 | 10 | // const multipleUsers = await kient.api.channel.getByIds([1, 2, 3]) 11 | // console.log(kientToJSON(multipleUsers)) 12 | 13 | const specificUser = await kient.api.channel.getById(676) 14 | console.log(specificUser.toJSON()) 15 | 16 | // const multipleUsersBySlugs = await kient.api.channel.getBySlugs(['kient', 'user1', 'user2']) 17 | // console.log(kientToJSON(multipleUsersBySlugs)) 18 | 19 | // const specificUserBySlug = await kient.api.channel.getBySlug('kient') 20 | // console.log(specificUserBySlug.toJSON()) 21 | -------------------------------------------------------------------------------- /example/get-public-key.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { Kient } from 'kient' 3 | 4 | const kient = new Kient() 5 | kient.setAuthToken(env.KICK_TOKEN as string) 6 | 7 | const publicKey = await kient.api.misc.getPublicKey() 8 | console.log(publicKey) 9 | -------------------------------------------------------------------------------- /example/get-users.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { Kient } from 'kient' 3 | 4 | const kient = new Kient() 5 | kient.setAuthToken(env.KICK_TOKEN as string) 6 | 7 | const currentUser = await kient.api.user.getAuthorisedUser() 8 | console.log(currentUser.toJSON()) 9 | 10 | const multipleUsers = await kient.api.user.getByIds([1, 2, 3]) 11 | console.log(multipleUsers.map((user) => user.toJSON())) 12 | 13 | const specificUser = await kient.api.user.getById(2) 14 | console.log(specificUser.toJSON()) 15 | -------------------------------------------------------------------------------- /example/send-chat.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { Kient } from 'kient' 3 | 4 | const kient = new Kient() 5 | kient.setAuthToken(env.KICK_TOKEN as string) 6 | 7 | const bot = await kient.api.chat.send({ 8 | type: 'bot', 9 | message: 'Message will be send to authenticated user channel', 10 | }) 11 | console.log(bot.toJSON()) 12 | 13 | const user = await kient.api.chat.send({ 14 | type: 'user', 15 | message: 'Message will be send to specified user id', 16 | userId: 2808896, 17 | }) 18 | console.log(user.toJSON()) 19 | -------------------------------------------------------------------------------- /example/webhooks.ts: -------------------------------------------------------------------------------- 1 | import { env } from 'bun' 2 | import { Kient, kientToJSON } from 'kient' 3 | 4 | const kient = new Kient() 5 | kient.setAuthToken(env.KICK_TOKEN as string) 6 | 7 | if (kient.webhookServerFetch) { 8 | Bun.serve({ 9 | fetch: kient.webhookServerFetch, 10 | port: 3000, 11 | }) 12 | } 13 | 14 | const specificUserBySlug = await kient.api.channel.getBySlug('kient') 15 | 16 | const subscription = await kient.api.event.subscribe({ 17 | method: 'webhook', 18 | broadcaster_user_id: Number.parseInt(specificUserBySlug.id), 19 | events: [ 20 | { 21 | name: 'livestream.status.updated', 22 | version: 1, 23 | }, 24 | { 25 | name: 'chat.message.sent', 26 | version: 1, 27 | }, 28 | ], 29 | }) 30 | console.log(kientToJSON(subscription)) 31 | 32 | const subscriptions = await kient.api.event.getSubscriptions() 33 | console.log(subscriptions.map((sub) => sub.toJSON())) 34 | // subscriptions.forEach((sub) => sub.unsubscribe()) 35 | 36 | kient.addListener('KIENT_CHAT_MESSAGE_SENT', (message) => { 37 | console.log('chat message received from', message.sender.username) 38 | console.log(kientToJSON(message)) 39 | }) 40 | 41 | kient.addListener('KIENT_LIVESTREAM_STATUS_UPDATED', (message) => { 42 | console.log(kientToJSON(message)) 43 | }) 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kient", 3 | "version": "2.3.0", 4 | "homepage": "https://kient.pages.dev", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/zSoulweaver/kient.git" 8 | }, 9 | "license": "MIT", 10 | "keywords": [ 11 | "kick", 12 | "api", 13 | "livestream", 14 | "bot" 15 | ], 16 | "type": "module", 17 | "exports": { 18 | ".": { 19 | "types": "./dist/index.d.ts", 20 | "import": "./dist/index.js" 21 | } 22 | }, 23 | "module": "./dist/index.js", 24 | "types": "./dist/index.d.ts", 25 | "files": [ 26 | "dist" 27 | ], 28 | "scripts": { 29 | "build": "bun ./build.ts", 30 | "dev": "bun run --watch --env-file=example/.env run-example.ts", 31 | "docs:prepare": "typedoc", 32 | "docs:dev": "typedoc && vitepress dev docs", 33 | "docs:build": "typedoc && vitepress build docs", 34 | "docs:preview": "vitepress preview docs", 35 | "release": "changelogen --release", 36 | "pre-release": "changelogen --release --prerelease" 37 | }, 38 | "devDependencies": { 39 | "@biomejs/biome": "1.9.4", 40 | "@types/bun": "^1.2.4", 41 | "@types/node": "^22.13.8", 42 | "bun-plugin-dts": "^0.3.0", 43 | "changelogen": "^0.5.7", 44 | "typedoc": "^0.27.9", 45 | "typedoc-plugin-markdown": "^4.4.2", 46 | "typedoc-plugin-missing-exports": "^3.1.0", 47 | "typedoc-vitepress-theme": "^1.1.2", 48 | "vitepress": "^1.6.3" 49 | }, 50 | "peerDependencies": { 51 | "typescript": "^5.6.3" 52 | }, 53 | "dependencies": { 54 | "@kakasoo/deep-strict-types": "^2.0.2", 55 | "defu": "^6.1.4", 56 | "destr": "^2.0.3", 57 | "hono": "^4.7.2", 58 | "nanoid": "^5.1.0", 59 | "ofetch": "^1.3.4", 60 | "pusher-js": "^8.4.0-rc2", 61 | "tseep": "^1.2.2" 62 | } 63 | } -------------------------------------------------------------------------------- /run-example.ts: -------------------------------------------------------------------------------- 1 | import { existsSync } from 'node:fs' 2 | 3 | const args = process.argv.slice(2) 4 | const fileName = args[0] 5 | 6 | if (!fileName) { 7 | console.error('Please provide a file name.') 8 | process.exit(1) 9 | } 10 | 11 | const filePath = `./example/${fileName}.ts` 12 | 13 | if (!existsSync(filePath)) { 14 | console.error(`File not found: ${filePath}`) 15 | process.exit(1) 16 | } 17 | 18 | Bun.spawn(['bun', '--watch', filePath], { 19 | stderr: 'inherit', 20 | stdin: 'inherit', 21 | stdout: 'inherit', 22 | }) 23 | -------------------------------------------------------------------------------- /src/api.client.ts: -------------------------------------------------------------------------------- 1 | import { type $Fetch, type FetchOptions, type ResponseType, ofetch } from 'ofetch' 2 | import type { Kient } from './kient' 3 | 4 | export interface APIClientOptions { 5 | ofetch?: FetchOptions 6 | } 7 | 8 | /** @internal */ 9 | export class APIClient { 10 | private apiFetch: $Fetch 11 | private ofetchOptions: FetchOptions 12 | 13 | constructor( 14 | public kient: Kient, 15 | options?: APIClientOptions, 16 | ) { 17 | this.ofetchOptions = options?.ofetch || {} 18 | this.apiFetch = ofetch.create(this.ofetchOptions) 19 | } 20 | 21 | get fetch() { 22 | return this.apiFetch 23 | } 24 | 25 | setHeaders(headers: Record) { 26 | this.apiFetch = ofetch.create({ 27 | ...this.ofetchOptions, 28 | headers: { 29 | ...this.ofetchOptions.headers, 30 | ...headers, 31 | }, 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/api/api-base.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | 3 | /** @internal */ 4 | export class APIBase { 5 | protected readonly kient: Kient 6 | 7 | constructor(kient: Kient) { 8 | this.kient = kient 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/api/category/get-categories.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import { Category } from '../../structures/category' 3 | import type { APIResponse } from '../../util/api-response' 4 | 5 | export interface CategoryResponse { 6 | id: number 7 | name: string 8 | thumbnail: string 9 | } 10 | 11 | type GetCategoriesResponse = APIResponse 12 | 13 | export async function getCategoriesByQuery(kient: Kient, query: string) { 14 | const response = await kient._apiClient.fetch('/categories', { 15 | query: { 16 | q: query, 17 | }, 18 | }) 19 | 20 | const categoryInstances = [] 21 | for (const categoryData of response.data) { 22 | const category = new Category(kient, categoryData) 23 | categoryInstances.push(category) 24 | } 25 | 26 | return categoryInstances 27 | } 28 | -------------------------------------------------------------------------------- /src/api/category/index.ts: -------------------------------------------------------------------------------- 1 | import { APIBase } from '../api-base' 2 | import { getCategoriesByQuery } from './get-categories' 3 | 4 | /** 5 | * Description placeholder 6 | * 7 | * @group APIs 8 | */ 9 | export class CategoryAPI extends APIBase { 10 | /** 11 | * Returns an array of categories matching search query 12 | * 13 | * @param {string} query Accepts a string that will be matched against the category title 14 | */ 15 | query(query: string) { 16 | return getCategoriesByQuery(this.kient, query) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/api/channel/get-channels.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import type { APIResponse } from '../../util/api-response' 3 | import { Channel } from '../../structures/channel' 4 | 5 | export interface ChannelResponse { 6 | banner_picture: string 7 | broadcaster_user_id: string 8 | category: { 9 | id: number 10 | name: string 11 | thumbnail: string 12 | } 13 | channel_description: string 14 | slug: string 15 | stream: { 16 | key?: string 17 | url?: string 18 | is_live: boolean 19 | is_mature: boolean 20 | language: string 21 | start_time: string 22 | viewer_count: number 23 | } 24 | stream_title: string 25 | } 26 | 27 | type GetChannelResponse = APIResponse 28 | 29 | async function fetchChannels(kient: Kient, params: URLSearchParams): Promise { 30 | const response = await kient._apiClient.fetch(`/channels?${params}`) 31 | 32 | const channelInstances = [] 33 | for (const channelData of response.data) { 34 | const channel = new Channel(kient, { 35 | id: channelData.broadcaster_user_id, 36 | slug: channelData.slug, 37 | bannerPicture: channelData.banner_picture, 38 | channelDescription: channelData.channel_description, 39 | stream: { 40 | category: channelData.category, 41 | isLive: channelData.stream.is_live, 42 | isMature: channelData.stream.is_mature, 43 | language: channelData.stream.language, 44 | startTime: channelData.stream.start_time, 45 | streamTitle: channelData.stream_title, 46 | viewerCount: channelData.stream.viewer_count, 47 | }, 48 | ingest: { 49 | key: channelData.stream.key || '', 50 | url: channelData.stream.url || '', 51 | }, 52 | }) 53 | channelInstances.push(channel) 54 | } 55 | 56 | return channelInstances 57 | } 58 | 59 | export async function getChannelsByID(kient: Kient, ids: number[] = []) { 60 | const params = new URLSearchParams() 61 | for (const id of ids) { 62 | params.append('broadcaster_user_id', id.toString()) 63 | } 64 | return fetchChannels(kient, params) 65 | } 66 | 67 | export async function getChannelsBySlugs(kient: Kient, slugs: string[] = []) { 68 | const params = new URLSearchParams() 69 | for (const slug of slugs) { 70 | params.append('slug', slug) 71 | } 72 | return fetchChannels(kient, params) 73 | } 74 | -------------------------------------------------------------------------------- /src/api/channel/index.ts: -------------------------------------------------------------------------------- 1 | import { APIBase } from '../api-base' 2 | import { getChannelsByID, getChannelsBySlugs } from './get-channels' 3 | 4 | /** 5 | * Description placeholder 6 | * 7 | * @group APIs 8 | */ 9 | export class ChannelAPI extends APIBase { 10 | /** 11 | * Returns an array of channel by an array of user IDs 12 | * 13 | * @param ids Accepts an array of user IDs that will be queried for 14 | */ 15 | getByIds(ids: number[]) { 16 | return getChannelsByID(this.kient, ids) 17 | } 18 | 19 | /** 20 | * Returns a singular channel by ID 21 | * 22 | * @param id Accepts a singular user ID that will be queried for 23 | */ 24 | async getById(id: number) { 25 | return (await getChannelsByID(this.kient, [id]))[0] 26 | } 27 | 28 | /** 29 | * Returns an array of channel by an array of channel slugs 30 | * 31 | * @param slugs Accepts an array of channel slugs that will be queried for 32 | */ 33 | getBySlugs(slugs: string[]) { 34 | return getChannelsBySlugs(this.kient, slugs) 35 | } 36 | 37 | /** 38 | * Returns a singular channel by slug 39 | * 40 | * @param slug Accepts a singular channel slug that will be queried for 41 | */ 42 | async getBySlug(slug: string) { 43 | return (await getChannelsBySlugs(this.kient, [slug]))[0] 44 | } 45 | 46 | /** 47 | * Returns the currently authorised user's channel details 48 | */ 49 | async getAuthorisedUser() { 50 | return (await getChannelsByID(this.kient))[0] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/api/chat/index.ts: -------------------------------------------------------------------------------- 1 | import { APIBase } from '../api-base' 2 | import { sendChat, type SendChatParams } from './send-chat' 3 | 4 | /** 5 | * Description placeholder 6 | * 7 | * @group APIs 8 | */ 9 | export class ChatAPI extends APIBase { 10 | /** 11 | * Send a chat to a channel and returns the status of the message 12 | * 13 | * @param query Accepts and object of the message and how if it's being sent from a bot account 14 | */ 15 | send(params: SendChatParams) { 16 | return sendChat(this.kient, params) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/api/chat/send-chat.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import type { APIResponse } from '../../util/api-response' 3 | import { Chat } from '../../structures/chat' 4 | 5 | interface SendBotChatParams { 6 | message: string 7 | type: 'bot' 8 | } 9 | 10 | interface SendUserChatParams { 11 | message: string 12 | type: 'user' 13 | /** 14 | * The target channel's user ID to send the message to 15 | */ 16 | userId: number 17 | } 18 | 19 | export type SendChatParams = SendUserChatParams | SendBotChatParams 20 | 21 | export interface ChatResponse { 22 | is_sent: boolean 23 | message_id: string 24 | } 25 | 26 | type SendChatResponse = APIResponse 27 | 28 | export async function sendChat(kient: Kient, params: SendChatParams) { 29 | const requestParams: { 30 | content: string 31 | type: 'user' | 'bot' 32 | broadcaster_user_id?: number 33 | } = { 34 | content: params.message, 35 | type: params.type, 36 | } 37 | 38 | if (params.type === 'user') { 39 | requestParams.broadcaster_user_id = params.userId 40 | } 41 | 42 | const response = await kient._apiClient.fetch('/chat', { 43 | method: 'POST', 44 | body: JSON.stringify(requestParams), 45 | }) 46 | 47 | const chat = new Chat(kient, { 48 | id: response.data.message_id, 49 | isSent: response.data.is_sent, 50 | }) 51 | return chat 52 | } 53 | -------------------------------------------------------------------------------- /src/api/events/get-events.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import type { APIResponse } from '../../util/api-response' 3 | import { DetailedEventSubscription } from '../../structures/detailed-event-subscription' 4 | 5 | export interface EventSubscriptionResponse { 6 | app_id: string 7 | broadcaster_user_id: number 8 | created_at: string 9 | event: string 10 | id: string 11 | method: string 12 | updated_at: string 13 | version: number 14 | } 15 | 16 | type GetEventSubscriptionsResponse = APIResponse 17 | 18 | export async function getEventSubscriptions(kient: Kient) { 19 | const response = 20 | await kient._apiClient.fetch('/events/subscriptions') 21 | 22 | const subscriptionInstances = [] 23 | for (const subscription of response.data) { 24 | const subscriptionEvent = new DetailedEventSubscription(kient, { 25 | id: subscription.id, 26 | event: subscription.event, 27 | version: subscription.version, 28 | appId: subscription.app_id, 29 | userId: subscription.broadcaster_user_id, 30 | method: subscription.method, 31 | createdAt: subscription.created_at, 32 | updatedAt: subscription.updated_at, 33 | }) 34 | subscriptionInstances.push(subscriptionEvent) 35 | } 36 | 37 | return subscriptionInstances 38 | } 39 | -------------------------------------------------------------------------------- /src/api/events/index.ts: -------------------------------------------------------------------------------- 1 | import { APIBase } from '../api-base' 2 | import { getEventSubscriptions } from './get-events' 3 | import { subscribeToEvent, type EventSubscriptionParams } from './subscribe' 4 | import { unsubscribeFromEvents } from './unsubscribe' 5 | /** 6 | * Description placeholder 7 | * 8 | * @group APIs 9 | */ 10 | export class EventAPI extends APIBase { 11 | /** 12 | * Returns an array of events that are currently subscribed to 13 | */ 14 | getSubscriptions() { 15 | return getEventSubscriptions(this.kient) 16 | } 17 | 18 | /** 19 | * Subscribes to a specific event and returns details about subscription 20 | */ 21 | subscribe(params: EventSubscriptionParams) { 22 | return subscribeToEvent(this.kient, params) 23 | } 24 | 25 | /** 26 | * Unsubscribes to an array of subscription IDs 27 | */ 28 | unsubscribe(ids: string[]) { 29 | return unsubscribeFromEvents(this.kient, ids) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/api/events/subscribe.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import type { APIResponse } from '../../util/api-response' 3 | import { EventSubscription } from '../../structures/event-subscription' 4 | 5 | export interface EventSubscriptionParams { 6 | method: 'webhook' 7 | broadcaster_user_id?: number 8 | events: Array<{ 9 | name: string 10 | version: number 11 | }> 12 | } 13 | 14 | export interface EventSubscriptionResponse { 15 | subscription_id: string 16 | name: string 17 | version: number 18 | error: string 19 | } 20 | 21 | type SubscribeEventResponse = APIResponse 22 | 23 | export async function subscribeToEvent(kient: Kient, param: EventSubscriptionParams) { 24 | const response = await kient._apiClient.fetch('/events/subscriptions', { 25 | method: 'POST', 26 | body: param, 27 | }) 28 | 29 | const basicSubscriptionInstances = [] 30 | for (const subscription of response.data) { 31 | if (subscription.error) { 32 | throw new Error(subscription.error) 33 | } 34 | const basicSubscription = new EventSubscription(kient, { 35 | id: subscription.subscription_id, 36 | event: subscription.name, 37 | version: subscription.version, 38 | }) 39 | basicSubscriptionInstances.push(basicSubscription) 40 | } 41 | 42 | return basicSubscriptionInstances 43 | } 44 | -------------------------------------------------------------------------------- /src/api/events/unsubscribe.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | 3 | export async function unsubscribeFromEvents(kient: Kient, ids: string[]) { 4 | const params = new URLSearchParams() 5 | for (const id of ids) { 6 | params.append('id', id.toString()) 7 | } 8 | 9 | await kient._apiClient.fetch(`/events/subscriptions?${params}`, { 10 | method: 'DELETE', 11 | }) 12 | } 13 | -------------------------------------------------------------------------------- /src/api/misc/get-public-key.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import type { APIResponse } from '../../util/api-response' 3 | 4 | type GetPublicKeyResponse = APIResponse<{ public_key: string }> 5 | 6 | export async function getPublicKey(kient: Kient) { 7 | const response = await kient._apiClient.fetch('/public-key') 8 | 9 | return response.data.public_key 10 | } 11 | -------------------------------------------------------------------------------- /src/api/misc/index.ts: -------------------------------------------------------------------------------- 1 | import { APIBase } from '../api-base' 2 | import { getPublicKey } from './get-public-key' 3 | 4 | /** 5 | * Description placeholder 6 | * 7 | * @group APIs 8 | */ 9 | export class MiscAPI extends APIBase { 10 | /** 11 | * Returns Kick's current public key 12 | */ 13 | getPublicKey() { 14 | return getPublicKey(this.kient) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/api/user/get-user.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import type { APIResponse } from '../../util/api-response' 3 | import { User } from '../../structures/user' 4 | 5 | export interface UserResponse { 6 | user_id: number 7 | name: string 8 | email: string 9 | profile_picture: string 10 | } 11 | 12 | type GetUsersResponse = APIResponse 13 | 14 | export async function getUsersByID(kient: Kient, ids: number[] = []) { 15 | const params = new URLSearchParams() 16 | for (const id of ids) { 17 | params.append('id', id.toString()) 18 | } 19 | 20 | const response = await kient._apiClient.fetch(`/users?${params}`) 21 | 22 | const userInstances = [] 23 | for (const userData of response.data) { 24 | const category = new User(kient, { 25 | id: userData.user_id, 26 | username: userData.name, 27 | email: userData.email, 28 | profilePicture: userData.profile_picture, 29 | }) 30 | userInstances.push(category) 31 | } 32 | 33 | return userInstances 34 | } 35 | -------------------------------------------------------------------------------- /src/api/user/index.ts: -------------------------------------------------------------------------------- 1 | import { APIBase } from '../api-base' 2 | import { getUsersByID } from './get-user' 3 | 4 | /** 5 | * Description placeholder 6 | * 7 | * @group APIs 8 | */ 9 | export class UserAPI extends APIBase { 10 | /** 11 | * Returns an array of users by an array of IDs 12 | * 13 | * @param ids Accepts an array of user IDs that will be queried for 14 | */ 15 | getByIds(ids: number[]) { 16 | return getUsersByID(this.kient, ids) 17 | } 18 | 19 | /** 20 | * Returns a singular user by ID 21 | * 22 | * @param id Accepts a singular user ID that will be queried for 23 | */ 24 | async getById(id: number) { 25 | return (await getUsersByID(this.kient, [id]))[0] 26 | } 27 | 28 | /** 29 | * Returns the currently authorised user's details 30 | */ 31 | async getAuthorisedUser() { 32 | return (await getUsersByID(this.kient))[0] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/authentication/app-token.ts: -------------------------------------------------------------------------------- 1 | import { ofetch } from 'ofetch' 2 | import { Token } from '../structures/token' 3 | 4 | interface KientAuthenticationParams { 5 | clientId: string 6 | clientSecret: string 7 | } 8 | 9 | interface TokenResponse { 10 | access_token: string 11 | token_type: 'Bearer' 12 | expires_in: number 13 | } 14 | 15 | const KICK_TOKEN_ENDPOINT = 'https://id.kick.com/oauth/token' 16 | 17 | export class KientAppTokenAuthentication { 18 | params: KientAuthenticationParams 19 | 20 | constructor(params: KientAuthenticationParams) { 21 | this.params = params 22 | } 23 | 24 | async generateToken() { 25 | const tokenParams = new URLSearchParams({ 26 | client_id: this.params.clientId, 27 | client_secret: this.params.clientSecret, 28 | grant_type: 'client_credentials', 29 | }) 30 | 31 | const req = await ofetch(KICK_TOKEN_ENDPOINT, { 32 | method: 'POST', 33 | headers: { 34 | 'Content-Type': 'application/x-www-form-urlencoded', 35 | }, 36 | body: tokenParams.toString(), 37 | }) 38 | 39 | console.log(req) 40 | 41 | return new Token({ 42 | accessToken: req.access_token, 43 | tokenType: req.token_type, 44 | expiresIn: req.expires_in, 45 | }) 46 | } 47 | } -------------------------------------------------------------------------------- /src/authentication/scopes.ts: -------------------------------------------------------------------------------- 1 | export const KientScopes = { 2 | UserRead: 'user:read', 3 | ChannelRead: 'channel:read', 4 | ChannelWrite: 'channel:write', 5 | ChatWrite: 'chat:write', 6 | StreamkeyRead: 'streamkey:read', 7 | EventsSubscribe: 'events:subscribe', 8 | } as const 9 | 10 | export type KientScope = (typeof KientScopes)[keyof typeof KientScopes] 11 | -------------------------------------------------------------------------------- /src/authentication/user-token.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid' 2 | import { randomBytes, createHash } from 'node:crypto' 3 | import type { KientScope } from './scopes' 4 | import { ofetch } from 'ofetch' 5 | import { Token } from '../structures/token' 6 | 7 | interface KientUserAuthenticationParams { 8 | clientId: string 9 | clientSecret: string 10 | redirectUri: string 11 | } 12 | 13 | interface KientUserAuthoriseParams { 14 | scopes: KientScope[] 15 | codeVerifier?: string 16 | state?: string 17 | } 18 | 19 | interface KientUserTokenParams { 20 | code: string 21 | codeVerifier: string 22 | } 23 | 24 | interface KientUserRefreshTokenParams { 25 | refreshToken: string 26 | } 27 | 28 | interface KientUserTokenRevoke { 29 | token: string 30 | type: 'access_token' | 'refresh_token' 31 | } 32 | 33 | interface TokenResponse { 34 | access_token: string 35 | token_type: 'Bearer' 36 | refresh_token: string 37 | expires_in: number 38 | scope: string 39 | } 40 | 41 | const KICK_AUTH_ENDPOINT = 'https://id.kick.com/oauth/authorize' 42 | const KICK_TOKEN_ENDPOINT = 'https://id.kick.com/oauth/token' 43 | const KICK_TOKEN_REVOKE = 'https://id.kick.com/oauth/revoke' 44 | 45 | export class KientUserTokenAuthentication { 46 | params: KientUserAuthenticationParams 47 | 48 | constructor(params: KientUserAuthenticationParams) { 49 | this.params = params 50 | } 51 | 52 | constructAuthoriseUrl(params: KientUserAuthoriseParams) { 53 | const state = params.state ?? nanoid() 54 | let verifier = params.codeVerifier 55 | if (!verifier) { 56 | verifier = base64URLEncode(randomBytes(32)) 57 | } 58 | const challenge = base64URLEncode(sha256(verifier)) 59 | 60 | const authParams = new URLSearchParams({ 61 | client_id: this.params.clientId, 62 | redirect_uri: this.params.redirectUri, 63 | response_type: 'code', 64 | scope: params.scopes.join(' '), 65 | code_challenge: challenge, 66 | code_challenge_method: 'S256', 67 | state, 68 | }) 69 | const url = `${KICK_AUTH_ENDPOINT}?${authParams.toString()}` 70 | 71 | return { 72 | url, 73 | state, 74 | verifier, 75 | } 76 | } 77 | 78 | async generateToken(params: KientUserTokenParams) { 79 | const tokenParams = new URLSearchParams({ 80 | code: params.code, 81 | client_id: this.params.clientId, 82 | client_secret: this.params.clientSecret, 83 | redirect_uri: this.params.redirectUri, 84 | grant_type: 'authorization_code', 85 | code_verifier: params.codeVerifier, 86 | }) 87 | 88 | const req = await ofetch(KICK_TOKEN_ENDPOINT, { 89 | method: 'POST', 90 | headers: { 91 | 'Content-Type': 'application/x-www-form-urlencoded', 92 | }, 93 | body: tokenParams.toString(), 94 | }) 95 | 96 | return new Token({ 97 | accessToken: req.access_token, 98 | tokenType: req.token_type, 99 | refreshToken: req.refresh_token, 100 | expiresIn: req.expires_in, 101 | scope: req.scope, 102 | }) 103 | } 104 | 105 | async refeshToken(params: KientUserRefreshTokenParams) { 106 | const refreshParams = new URLSearchParams({ 107 | refresh_token: params.refreshToken, 108 | client_id: this.params.clientId, 109 | client_secret: this.params.clientSecret, 110 | grant_type: 'refresh_token', 111 | }) 112 | 113 | const req = await ofetch(KICK_TOKEN_ENDPOINT, { 114 | method: 'POST', 115 | headers: { 116 | 'Content-Type': 'application/x-www-form-urlencoded', 117 | }, 118 | body: refreshParams.toString(), 119 | }) 120 | 121 | return new Token({ 122 | accessToken: req.access_token, 123 | tokenType: req.token_type, 124 | refreshToken: req.refresh_token, 125 | expiresIn: req.expires_in, 126 | scope: req.scope, 127 | }) 128 | } 129 | 130 | // TODO: Endpoint currently not working 131 | // async revokeToken(params: KientUserTokenRevoke) { 132 | // const revokeParams = new URLSearchParams({ 133 | // token: params.token, 134 | // }) 135 | 136 | // await ofetch(`${KICK_TOKEN_REVOKE}?${revokeParams.toString()}`, { method: 'POST' }) 137 | 138 | // await ofetch(KICK_TOKEN_REVOKE, { 139 | // method: 'POST', 140 | // }) 141 | // } 142 | } 143 | 144 | function base64URLEncode(buffer: Buffer) { 145 | return buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '') 146 | } 147 | 148 | function sha256(buffer: string) { 149 | return createHash('sha256').update(buffer).digest() 150 | } 151 | -------------------------------------------------------------------------------- /src/events.ts: -------------------------------------------------------------------------------- 1 | import { WebhookEvents } from './webhook.handler' 2 | 3 | const KientEvents = { 4 | WebSocketConnected: 'KIENT_WEBSOCKET_CONNECTED', 5 | WebSocketDisconnected: 'KIENT_WEBSOCKET_DISCONNECTED', 6 | } as const 7 | 8 | type CoreEvents = { 9 | [KientEvents.WebSocketConnected]: () => void 10 | [KientEvents.WebSocketDisconnected]: () => void 11 | } 12 | 13 | export const Events = { 14 | Core: KientEvents, 15 | ...WebhookEvents, 16 | } 17 | 18 | export type KientEventEmitters = CoreEvents & WebhookEvents 19 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { Kient } from './kient' 2 | export { KientUserTokenAuthentication } from './authentication/user-token' 3 | export { KientAppTokenAuthentication } from './authentication/app-token' 4 | export { KientScopes } from './authentication/scopes' 5 | export { verifyWebhookSignature } from './util/verify-webhook-signature' 6 | 7 | export { flatten as kientToJSON } from './util/flatten' 8 | -------------------------------------------------------------------------------- /src/kient.ts: -------------------------------------------------------------------------------- 1 | import defu from 'defu' 2 | import { EventEmitter } from 'tseep' 3 | import { APIClient, type APIClientOptions } from './api.client' 4 | import type { KientEventEmitters } from './events' 5 | import { CategoryAPI } from './api/category' 6 | import { UserAPI } from './api/user' 7 | import { ChannelAPI } from './api/channel' 8 | import { ChatAPI } from './api/chat' 9 | import { MiscAPI } from './api/misc' 10 | import { WebhookServer } from './webhook.server' 11 | import { WebhookHandler } from './webhook.handler' 12 | import type { WebhookEvent } from './structures/base-event' 13 | import { EventAPI } from './api/events' 14 | 15 | type DeepPartial = T extends object ? { [P in keyof T]?: DeepPartial } : T 16 | 17 | export interface KientOptions { 18 | apiClient: APIClientOptions 19 | webhookServer: { 20 | enable: boolean 21 | } 22 | } 23 | 24 | const defaultKientOptions: KientOptions = { 25 | apiClient: { 26 | ofetch: { 27 | baseURL: 'https://api.kick.com/public/v1', 28 | }, 29 | }, 30 | webhookServer: { 31 | enable: true, 32 | }, 33 | } 34 | 35 | export class Kient extends EventEmitter { 36 | private readonly kientOptions: KientOptions 37 | private _webhookServer?: WebhookServer 38 | _webhookHandler: WebhookHandler 39 | _apiClient: APIClient 40 | _kickPublicKey?: string 41 | 42 | constructor(options?: DeepPartial) { 43 | super() 44 | this.kientOptions = defu(options as KientOptions, defaultKientOptions) 45 | 46 | if (this.kientOptions.webhookServer.enable) { 47 | this.createWebhookServer() 48 | } 49 | 50 | this._apiClient = new APIClient(this, this.kientOptions.apiClient) 51 | this._webhookHandler = new WebhookHandler(this) 52 | } 53 | 54 | createWebhookServer() { 55 | this._webhookServer = new WebhookServer(this) 56 | } 57 | 58 | async setAuthToken(token: string) { 59 | this._apiClient.setHeaders({ 60 | Authorization: `Bearer ${token}`, 61 | }) 62 | 63 | this._kickPublicKey = await this.api.misc.getPublicKey() 64 | } 65 | 66 | get webhookServerFetch() { 67 | return this._webhookServer?.fetch 68 | } 69 | 70 | handleWebhookEvent(event: WebhookEvent) { 71 | this._webhookHandler.handleEvent(event) 72 | } 73 | 74 | api = { 75 | misc: new MiscAPI(this), 76 | category: new CategoryAPI(this), 77 | user: new UserAPI(this), 78 | channel: new ChannelAPI(this), 79 | chat: new ChatAPI(this), 80 | event: new EventAPI(this), 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/structures/base-event.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | import { Base } from './base' 3 | 4 | export interface WebhookEvent { 5 | messageId: string 6 | subscriptionId: string 7 | timestamp: string 8 | type: string 9 | version: string 10 | body: string 11 | } 12 | 13 | export class EventBase extends Base { 14 | /** 15 | * The information relating the received event 16 | */ 17 | kickEvent: { 18 | /** 19 | * The event's message id 20 | */ 21 | messageId: string 22 | 23 | /** 24 | * The subscription ID associated with the event 25 | */ 26 | subscriptionId: string 27 | 28 | /** 29 | * The event's timestamp 30 | */ 31 | timestamp: Date 32 | } 33 | 34 | /** @internal */ 35 | constructor(kient: Kient, data: WebhookEvent) { 36 | super(kient) 37 | 38 | this.kickEvent = { 39 | messageId: data.messageId, 40 | timestamp: new Date(data.timestamp), 41 | subscriptionId: data.subscriptionId, 42 | } 43 | } 44 | 45 | /** 46 | * The unsubscribes the client from this subscription type using the associated subscription ID in the event 47 | */ 48 | unsubscribe() { 49 | this._kient.api.event.unsubscribe([this.kickEvent.subscriptionId]) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/structures/base-user.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | import { Base } from './base' 4 | 5 | /** 6 | * Data structure of a user account 7 | * 8 | * @group API Structures 9 | */ 10 | export class BaseUser extends Base { 11 | /** 12 | * The user's id 13 | */ 14 | id: number 15 | 16 | /** 17 | * The username of the user 18 | */ 19 | username: string 20 | 21 | /** 22 | * The user's profile picture url 23 | */ 24 | profilePicture: string 25 | 26 | /** @internal */ 27 | constructor(kient: Kient, data: Flattened) { 28 | super(kient) 29 | 30 | this.id = data.id 31 | this.username = data.username 32 | this.profilePicture = data.profilePicture 33 | } 34 | 35 | toJSON() { 36 | return flatten(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/structures/base.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | 3 | export class Base { 4 | protected readonly _kient: Kient 5 | 6 | /** @internal */ 7 | constructor(kient: Kient) { 8 | this._kient = kient 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/structures/category.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | import { Base } from './base' 4 | 5 | /** 6 | * Data structure of a stream category 7 | * 8 | * @group API Structures 9 | */ 10 | export class Category extends Base { 11 | /** 12 | * The category's id 13 | */ 14 | id: number 15 | 16 | /** 17 | * The category's name 18 | */ 19 | name: string 20 | 21 | /** 22 | * The category's thumbnail image url 23 | */ 24 | thumbnail: string 25 | 26 | /** @internal */ 27 | constructor(kient: Kient, data: Flattened) { 28 | super(kient) 29 | 30 | this.id = data.id 31 | this.name = data.name 32 | this.thumbnail = data.thumbnail 33 | } 34 | 35 | toJSON() { 36 | return flatten(this) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/structures/channel-follow.ts: -------------------------------------------------------------------------------- 1 | import destr from 'destr' 2 | import type { Kient } from '../kient' 3 | import { EventBase, type WebhookEvent } from './base-event' 4 | import { ChatUser, type ChatUserData } from './chat-user' 5 | import { flatten } from '../util/flatten' 6 | 7 | export interface ChannelFollowEventData { 8 | broadcaster: ChatUserData 9 | follower: ChatUserData 10 | } 11 | 12 | export class ChannelFollow extends EventBase { 13 | /** 14 | * The channel that has been followed 15 | */ 16 | broadcaster: ChatUser 17 | 18 | /** 19 | * The user who followed the channel 20 | */ 21 | follower: ChatUser 22 | 23 | /** @internal */ 24 | constructor(kient: Kient, data: WebhookEvent) { 25 | super(kient, data) 26 | 27 | const eventBody = destr(data.body) 28 | 29 | this.broadcaster = new ChatUser(kient, ChatUser.constructChatUser(eventBody.broadcaster)) 30 | this.follower = new ChatUser(kient, ChatUser.constructChatUser(eventBody.follower)) 31 | } 32 | 33 | toJSON() { 34 | return flatten(this) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/structures/channel-subscription-gift.ts: -------------------------------------------------------------------------------- 1 | import destr from 'destr' 2 | import type { Kient } from '../kient' 3 | import { EventBase, type WebhookEvent } from './base-event' 4 | import { ChatUser, type ChatUserData } from './chat-user' 5 | import { flatten } from '../util/flatten' 6 | 7 | export interface ChannelSubscriptionGiftEventData { 8 | broadcaster: ChatUserData 9 | gifter: ChatUserData 10 | giftees: ChatUserData[] 11 | created_at: string 12 | } 13 | 14 | export class ChannelSubscriptionGift extends EventBase { 15 | /** 16 | * The user that has been subscribed to 17 | */ 18 | 19 | broadcaster: ChatUser 20 | 21 | /** 22 | * The user that has gifted subscriptions 23 | */ 24 | gifter?: ChatUser 25 | 26 | /** 27 | * An array of users that received a subscription 28 | */ 29 | giftees: ChatUser[] 30 | 31 | /** 32 | * The date the user gifted subscriptions 33 | */ 34 | createdAt: Date 35 | 36 | /** @internal */ 37 | constructor(kient: Kient, data: WebhookEvent) { 38 | super(kient, data) 39 | 40 | const eventBody = destr(data.body) 41 | 42 | this.broadcaster = new ChatUser(kient, ChatUser.constructChatUser(eventBody.broadcaster)) 43 | if (!eventBody.gifter.is_anonymous) { 44 | this.gifter = new ChatUser(kient, ChatUser.constructChatUser(eventBody.gifter)) 45 | } 46 | const gifteeInstances = [] 47 | for (const giftee of eventBody.giftees) { 48 | const gifteeInstance = new ChatUser(kient, ChatUser.constructChatUser(giftee)) 49 | gifteeInstances.push(gifteeInstance) 50 | } 51 | this.giftees = gifteeInstances 52 | this.createdAt = new Date(eventBody.created_at) 53 | } 54 | 55 | toJSON() { 56 | return flatten(this) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/structures/channel-subscription.ts: -------------------------------------------------------------------------------- 1 | import destr from 'destr' 2 | import type { Kient } from '../kient' 3 | import { EventBase, type WebhookEvent } from './base-event' 4 | import { ChatUser, type ChatUserData } from './chat-user' 5 | import { flatten } from '../util/flatten' 6 | 7 | export interface ChannelSubscriptionEventData { 8 | broadcaster: ChatUserData 9 | subscriber: ChatUserData 10 | duration: number 11 | created_at: string 12 | } 13 | 14 | export class ChannelSubscription extends EventBase { 15 | /** 16 | * The user that has been subscribed to 17 | */ 18 | 19 | broadcaster: ChatUser 20 | 21 | /** 22 | * The user that has followed the broadcaster 23 | */ 24 | subscriber: ChatUser 25 | 26 | /** 27 | * How many months they subscribed for consecutively 28 | */ 29 | duration: number 30 | 31 | /** 32 | * The date the user had subscribed to the channel 33 | */ 34 | createdAt: Date 35 | 36 | /** @internal */ 37 | constructor(kient: Kient, data: WebhookEvent) { 38 | super(kient, data) 39 | 40 | const eventBody = destr(data.body) 41 | 42 | this.broadcaster = new ChatUser(kient, ChatUser.constructChatUser(eventBody.broadcaster)) 43 | this.subscriber = new ChatUser(kient, ChatUser.constructChatUser(eventBody.subscriber)) 44 | this.duration = eventBody.duration 45 | this.createdAt = new Date(eventBody.created_at) 46 | } 47 | 48 | toJSON() { 49 | return flatten(this) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/structures/channel.ts: -------------------------------------------------------------------------------- 1 | import type { DeepStrictOmit } from '@kakasoo/deep-strict-types' 2 | import type { Kient } from '../kient' 3 | import { flatten, type Flattened } from '../util/flatten' 4 | import { Base } from './base' 5 | import { Category } from './category' 6 | 7 | type ChannelParams = DeepStrictOmit, 'stream.startTime'> & { 8 | stream: { 9 | startTime: string 10 | } 11 | } 12 | 13 | /** 14 | * Data structure of a user's channel 15 | * 16 | * @group API Structures 17 | */ 18 | export class Channel extends Base { 19 | /** 20 | * The channel owner's user ID 21 | */ 22 | id: string 23 | 24 | /** 25 | * The slug of the channel 26 | */ 27 | slug: string 28 | 29 | /** 30 | * The banner picture url of the channel 31 | */ 32 | bannerPicture: string 33 | 34 | /** 35 | * The description of the channel 36 | */ 37 | channelDescription: string 38 | 39 | /** 40 | * The channel's current stream details 41 | * Note: If the channel is currently not live, this will show data of the most recent broadcast ot live, this will show data of the most recent broadcast ot live, this will show data of the most recent broadcast 42 | */ 43 | stream: { 44 | /** 45 | * The current directory category of the stream 46 | */ 47 | category: Category 48 | 49 | /** 50 | * Indicates if the stream is currently live 51 | */ 52 | isLive: boolean 53 | 54 | /** 55 | * Indicates if the stream is for mature audiences only 56 | */ 57 | isMature: boolean 58 | 59 | /** 60 | * The primary language of the stream 61 | */ 62 | language: string 63 | 64 | /** 65 | * The start time of the stream 66 | */ 67 | startTime: Date 68 | 69 | /** 70 | * The title of the stream 71 | */ 72 | streamTitle: string 73 | 74 | /** 75 | * The viewer count of the stream 76 | */ 77 | viewerCount: number 78 | } 79 | 80 | /** 81 | * The channel's private ingest details 82 | */ 83 | ingest?: { 84 | /** 85 | * The stream key of the channel 86 | */ 87 | key: string 88 | 89 | /** 90 | * The ingest url of the channel 91 | */ 92 | url: string 93 | } 94 | 95 | /** @internal */ 96 | constructor(kient: Kient, data: ChannelParams) { 97 | super(kient) 98 | 99 | this.id = data.id 100 | this.slug = data.slug 101 | this.bannerPicture = data.bannerPicture 102 | this.channelDescription = data.channelDescription 103 | this.stream = { 104 | category: new Category(kient, data.stream.category), 105 | isLive: data.stream.isLive, 106 | isMature: data.stream.isMature, 107 | language: data.stream.language, 108 | startTime: new Date(data.stream.startTime), 109 | streamTitle: data.stream.streamTitle, 110 | viewerCount: data.stream.viewerCount, 111 | } 112 | if (data.ingest?.key && data.ingest.url) { 113 | this.ingest = { 114 | key: data.ingest.key, 115 | url: data.ingest.url, 116 | } 117 | } 118 | } 119 | 120 | toJSON() { 121 | return flatten(this) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/structures/chat-message.ts: -------------------------------------------------------------------------------- 1 | import destr from 'destr' 2 | import type { Kient } from '../kient' 3 | import { EventBase, type WebhookEvent } from './base-event' 4 | import { ChatUser, type ChatUserData } from './chat-user' 5 | import { flatten } from '../util/flatten' 6 | 7 | export interface ChatMessageEventData { 8 | message_id: string 9 | broadcaster: ChatUserData 10 | sender: ChatUserData 11 | content: string 12 | emotes: unknown 13 | } 14 | 15 | export class ChatMessage extends EventBase { 16 | /** 17 | * The chat messages's ID 18 | */ 19 | messageId: string 20 | 21 | /** 22 | * The message chatroom's owner's details 23 | */ 24 | broadcaster: ChatUser 25 | 26 | /** 27 | * The user who sent the chat message 28 | */ 29 | sender: ChatUser 30 | 31 | /** 32 | * The message content 33 | */ 34 | content: string 35 | 36 | /** 37 | * Emotes 38 | */ 39 | emotes: unknown 40 | 41 | /** @internal */ 42 | constructor(kient: Kient, data: WebhookEvent) { 43 | super(kient, data) 44 | 45 | const eventBody = destr(data.body) 46 | this.messageId = eventBody.message_id 47 | this.broadcaster = new ChatUser(kient, ChatUser.constructChatUser(eventBody.broadcaster)) 48 | this.sender = new ChatUser(kient, ChatUser.constructChatUser(eventBody.sender)) 49 | this.content = eventBody.content 50 | this.emotes = eventBody.emotes 51 | } 52 | 53 | toJSON() { 54 | return flatten(this) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/structures/chat-user.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | import { BaseUser } from './base-user' 4 | 5 | export interface ChatUserData { 6 | is_anonymous: boolean 7 | user_id: number 8 | username: string 9 | is_verified: boolean 10 | profile_picture: string 11 | channel_slug: string 12 | identity?: { 13 | username_color: string 14 | badges: Array<{ 15 | text: string 16 | type: string 17 | count: number 18 | }> 19 | } 20 | } 21 | 22 | export class ChatUser extends BaseUser { 23 | /** 24 | * The user's verification status 25 | */ 26 | isVerified: boolean 27 | 28 | /** 29 | * The user's channel slug 30 | */ 31 | slug: string 32 | 33 | /** 34 | * The user's chat appearance 35 | */ 36 | identity?: { 37 | /** 38 | * The user's color in chat 39 | */ 40 | usernameColor: string 41 | 42 | /** 43 | * The user's acquired chat badges 44 | */ 45 | badges: Array<{ 46 | /** 47 | * The badge's display name 48 | */ 49 | text: string 50 | 51 | /** 52 | * The badge's identifier 53 | */ 54 | type: string 55 | 56 | /** 57 | * How many of this badge the user has 58 | * Generally related to how many months a user has subscribed for 59 | * 60 | * TODO: This could use better clarification 61 | */ 62 | count?: number 63 | }> 64 | } 65 | 66 | /** @internal */ 67 | constructor(kient: Kient, data: Flattened) { 68 | super(kient, data) 69 | 70 | this.isVerified = data.isVerified 71 | this.slug = data.slug 72 | if (data.identity) { 73 | this.identity = data.identity 74 | } 75 | } 76 | 77 | static constructChatUser(data: ChatUserData): Flattened { 78 | return { 79 | id: data.user_id, 80 | username: data.username, 81 | profilePicture: data.profile_picture, 82 | isVerified: data.is_verified, 83 | slug: data.channel_slug, 84 | identity: data.identity 85 | ? { 86 | usernameColor: data.identity?.username_color, 87 | badges: data.identity?.badges, 88 | } 89 | : undefined, 90 | } 91 | } 92 | 93 | toJSON() { 94 | return flatten(this) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/structures/chat.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | import { Base } from './base' 4 | 5 | /** 6 | * Data structure of a chat message 7 | * 8 | * @group API Structures 9 | */ 10 | export class Chat extends Base { 11 | /** 12 | * The id of the sent message 13 | */ 14 | id: string 15 | 16 | /** 17 | * A boolean indicating if the message has been sent 18 | */ 19 | isSent: boolean 20 | 21 | /** @internal */ 22 | constructor(kient: Kient, data: Flattened) { 23 | super(kient) 24 | 25 | this.id = data.id 26 | this.isSent = data.isSent 27 | } 28 | 29 | toJSON() { 30 | return flatten(this) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/structures/detailed-event-subscription.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | import { EventSubscription } from './event-subscription' 4 | 5 | type DetailedEventSubscriptionParams = Omit< 6 | Flattened, 7 | 'createdAt' | 'updatedAt' 8 | > & { 9 | createdAt: string 10 | updatedAt: string 11 | } 12 | 13 | /** 14 | * Data structure of a subscription event 15 | * 16 | * @group API Structures 17 | */ 18 | export class DetailedEventSubscription extends EventSubscription { 19 | /** 20 | * The subscriptions's associated application ID 21 | */ 22 | appId: string 23 | 24 | /** 25 | * The subscriptions's associated user ID 26 | */ 27 | userId: number 28 | 29 | /** 30 | * The subscriptions's transit method 31 | */ 32 | method: string 33 | 34 | /** 35 | * The date the subscription was started 36 | */ 37 | createdAt: Date 38 | 39 | /** 40 | * The date the subscription was last updated 41 | */ 42 | updatedAt: Date 43 | 44 | /** @internal */ 45 | constructor(kient: Kient, data: DetailedEventSubscriptionParams) { 46 | super(kient, data) 47 | 48 | this.appId = data.appId 49 | this.userId = data.userId 50 | this.method = data.method 51 | this.createdAt = new Date(data.createdAt) 52 | this.updatedAt = new Date(data.updatedAt) 53 | } 54 | 55 | unsubscribe() { 56 | this._kient.api.event.unsubscribe([this.id]) 57 | } 58 | 59 | toJSON() { 60 | return flatten(this) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/structures/event-subscription.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | import { Base } from './base' 4 | 5 | /** 6 | * Data structure of a subscription event 7 | * 8 | * @group API Structures 9 | */ 10 | export class EventSubscription extends Base { 11 | /** 12 | * The subscriptions's ID 13 | */ 14 | id: string 15 | 16 | /** 17 | * The subscriptions's event name 18 | */ 19 | event: string 20 | 21 | /** 22 | * The subscriptions's event version number 23 | */ 24 | version: number 25 | 26 | /** @internal */ 27 | constructor(kient: Kient, data: Flattened) { 28 | super(kient) 29 | 30 | this.id = data.id 31 | this.event = data.event 32 | this.version = data.version 33 | } 34 | 35 | unsubscribe() { 36 | this._kient.api.event.unsubscribe([this.id]) 37 | } 38 | 39 | toJSON() { 40 | return flatten(this) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/structures/livestream-status.ts: -------------------------------------------------------------------------------- 1 | import destr from 'destr' 2 | import type { Kient } from '../kient' 3 | import { EventBase, type WebhookEvent } from './base-event' 4 | import { ChatUser, type ChatUserData } from './chat-user' 5 | import { flatten } from '../util/flatten' 6 | 7 | export interface LivestreamStatusEventData { 8 | broadcaster: ChatUserData 9 | is_live: boolean 10 | title: string 11 | started_at: string 12 | ended_at?: string 13 | } 14 | 15 | export class LivestreamStatus extends EventBase { 16 | /** 17 | * The broadcaster's details 18 | */ 19 | broadcaster: ChatUser 20 | 21 | /** 22 | * The live state of the broadcaster 23 | */ 24 | isLive: boolean 25 | 26 | /** 27 | * The title of the livestream 28 | */ 29 | title: string 30 | 31 | /** 32 | * The date the livestream had stated 33 | */ 34 | startedAt: Date 35 | 36 | /** 37 | * The date the livestream had ended 38 | */ 39 | endedDate?: Date 40 | 41 | /** @internal */ 42 | constructor(kient: Kient, data: WebhookEvent) { 43 | super(kient, data) 44 | 45 | const eventBody = destr(data.body) 46 | 47 | this.broadcaster = new ChatUser(kient, ChatUser.constructChatUser(eventBody.broadcaster)) 48 | this.isLive = eventBody.is_live 49 | this.title = eventBody.title 50 | this.startedAt = new Date(eventBody.started_at) 51 | if (eventBody.ended_at) { 52 | this.endedDate = new Date(eventBody.ended_at) 53 | } 54 | } 55 | 56 | toJSON() { 57 | return flatten(this) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/structures/token.ts: -------------------------------------------------------------------------------- 1 | import type { KientScope } from '../authentication/scopes' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | 4 | type TokenDataParams = Omit, 'scopes' | 'isAppToken'> 5 | 6 | /** 7 | * Response when generating an authorisation token 8 | * 9 | * @group API Structures 10 | */ 11 | export class Token { 12 | /** 13 | * The access token 14 | */ 15 | accessToken: string 16 | 17 | /** 18 | * The type of token presented 19 | */ 20 | tokenType: 'Bearer' 21 | 22 | /** 23 | * The refresh token used to get a new access token 24 | */ 25 | refreshToken?: string 26 | 27 | /** 28 | * The seconds until the access token expires 29 | */ 30 | expiresIn: number 31 | 32 | /** 33 | * A string of space seperated scopes available to this token 34 | */ 35 | scope?: string 36 | 37 | /** @internal */ 38 | constructor(data: TokenDataParams) { 39 | this.accessToken = data.accessToken 40 | this.tokenType = data.tokenType 41 | this.refreshToken = data.refreshToken 42 | this.expiresIn = data.expiresIn 43 | this.scope = data.scope 44 | } 45 | 46 | /** 47 | * An array of scopes available to this token 48 | */ 49 | get scopes() { 50 | return this.scope ? this.scope.split(' ') as KientScope[] : [] 51 | } 52 | 53 | /** 54 | * Returns true if the token is an app token type 55 | */ 56 | get isAppToken() { 57 | return !this.scope || !this.refreshToken 58 | } 59 | 60 | toJSON() { 61 | return flatten(this) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/structures/user.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from '../kient' 2 | import { flatten, type Flattened } from '../util/flatten' 3 | import { Base } from './base' 4 | import { BaseUser } from './base-user' 5 | 6 | /** 7 | * Data structure of a user account 8 | * 9 | * @group API Structures 10 | */ 11 | export class User extends BaseUser { 12 | /** 13 | * The user's email address 14 | * This will only display if the permissions of the token allow 15 | */ 16 | email?: string 17 | 18 | /** @internal */ 19 | constructor(kient: Kient, data: Flattened) { 20 | super(kient, data) 21 | 22 | this.email = data.email === '' ? undefined : data.email 23 | } 24 | 25 | toJSON() { 26 | return flatten(this) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/util/api-response.ts: -------------------------------------------------------------------------------- 1 | export interface APIResponse { 2 | message: string 3 | data: T 4 | } 5 | -------------------------------------------------------------------------------- /src/util/flatten.ts: -------------------------------------------------------------------------------- 1 | type ExcludeFunctionsAndPrivate = { 2 | [K in keyof T as K extends `_${string}` 3 | ? never 4 | : // biome-ignore lint/suspicious/noExplicitAny: Safe 5 | T[K] extends (...args: any[]) => any 6 | ? never 7 | : K]: T[K] extends object ? Flattened : T[K] 8 | } 9 | 10 | type Flattened = T extends Array 11 | ? Flattened[] 12 | : T extends object 13 | ? ExcludeFunctionsAndPrivate 14 | : T 15 | 16 | function flatten(obj: T, ...props: Record[]): Flattened { 17 | // Handle null or non-objects 18 | if (!obj || typeof obj !== 'object') { 19 | return obj as Flattened 20 | } 21 | 22 | // Handle arrays 23 | if (Array.isArray(obj)) { 24 | return obj.map((item) => flatten(item)) as Flattened 25 | } 26 | 27 | // Get all non-private properties (exclude keys starting with '_') 28 | const objProps = Object.keys(obj) 29 | .filter((key) => !key.startsWith('_')) 30 | .map((key) => ({ [key]: true })) 31 | 32 | // Merge provided props with object props safely 33 | const mergedProps: Record = Object.assign( 34 | {}, 35 | ...objProps, // Spread array of objects 36 | ...props, // Spread additional props 37 | ) 38 | 39 | const out: Record = {} 40 | 41 | for (const [prop, newProp] of Object.entries(mergedProps)) { 42 | if (!newProp) continue 43 | const outputKey = newProp === true ? prop : newProp 44 | 45 | // biome-ignore lint/suspicious/noExplicitAny: Safe 46 | const element = (obj as any)[prop] 47 | const elemIsObj = element && typeof element === 'object' 48 | // biome-ignore lint/suspicious/noShadowRestrictedNames: Safe 49 | const valueOf = elemIsObj && typeof element.valueOf === 'function' ? element.valueOf() : null 50 | const hasToJSON = elemIsObj && typeof element.toJSON === 'function' 51 | 52 | // Handle Date objects explicitly 53 | if (element instanceof Date) { 54 | out[outputKey] = element.toISOString() 55 | } 56 | // If it's an array, process each element 57 | else if (Array.isArray(element)) { 58 | out[outputKey] = element.map((elm) => (hasToJSON ? elm.toJSON() : flatten(elm))) 59 | } 60 | // If it has a toJSON method, use its result 61 | else if (hasToJSON) { 62 | out[outputKey] = element.toJSON() 63 | } 64 | // If it's an object with a primitive valueOf, use that 65 | else if (elemIsObj && valueOf && typeof valueOf !== 'object') { 66 | out[outputKey] = valueOf 67 | } 68 | // If it's a non-primitive object, flatten it 69 | else if (elemIsObj) { 70 | out[outputKey] = flatten(element) 71 | } 72 | // Otherwise, use the element as-is (primitives) 73 | else { 74 | out[outputKey] = element 75 | } 76 | } 77 | 78 | return out as Flattened 79 | } 80 | 81 | export { flatten, type Flattened } 82 | -------------------------------------------------------------------------------- /src/util/verify-webhook-signature.ts: -------------------------------------------------------------------------------- 1 | import crypto from 'node:crypto' 2 | 3 | export interface VerifySignatureParams { 4 | publicKey: string 5 | messageId: string 6 | signature: string 7 | timestamp: string 8 | body: string 9 | } 10 | 11 | export async function verifyWebhookSignature(params: VerifySignatureParams) { 12 | try { 13 | const data = `${params.messageId}.${params.timestamp}.${params.body}` 14 | 15 | const verifer = crypto.createVerify('RSA-SHA256') 16 | verifer.update(data) 17 | 18 | const signature = Buffer.from(params.signature, 'base64') 19 | const isValid = verifer.verify(params.publicKey, signature) 20 | if (!isValid) { 21 | console.warn('Webhook signature verification failed') 22 | } 23 | return isValid 24 | } catch (err) { 25 | console.error('Unable to verify signature of webhook event', err) 26 | return false 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/webhook.handler.ts: -------------------------------------------------------------------------------- 1 | import type { Kient } from 'kient' 2 | import type { WebhookEvent } from './structures/base-event' 3 | import { ChatMessage } from './structures/chat-message' 4 | import { ChannelFollow } from './structures/channel-follow' 5 | import { ChannelSubscription } from './structures/channel-subscription' 6 | import { ChannelSubscriptionGift } from './structures/channel-subscription-gift' 7 | import { LivestreamStatus } from './structures/livestream-status' 8 | 9 | export type WebhookEventNames = 10 | | 'chat.message.sent' 11 | | 'channel.followed' 12 | | 'channel.subscription.renewal' 13 | | 'channel.subscription.gifts' 14 | | 'channel.subscription.new' 15 | | 'livestream.status.updated' 16 | 17 | export const WebhookEvents = { 18 | Chat: { 19 | MessageSent: 'KIENT_CHAT_MESSAGE_SENT', 20 | }, 21 | Channel: { 22 | Follow: 'KIENT_CHANNEL_FOLLOW', 23 | Subscription: 'KIENT_CHANNEL_SUBSCRIPTION', 24 | Resubscription: 'KIENT_CHANNEL_RESUBSCRIPTION', 25 | GiftSubscriptions: 'KIENT_CHANNEL_GIFT_SUBSCRIPTIONS', 26 | }, 27 | Livestream: { 28 | StatusUpdated: 'KIENT_LIVESTREAM_STATUS_UPDATED', 29 | }, 30 | } as const 31 | 32 | export type WebhookEvents = { 33 | [WebhookEvents.Chat.MessageSent]: (chatMessage: ChatMessage) => void 34 | [WebhookEvents.Channel.Follow]: (channelFollow: ChannelFollow) => void 35 | [WebhookEvents.Channel.Subscription]: (channelSubscription: ChannelSubscription) => void 36 | [WebhookEvents.Channel.Resubscription]: (channelSubscription: ChannelSubscription) => void 37 | [WebhookEvents.Channel.GiftSubscriptions]: ( 38 | channelSubscriptionsGift: ChannelSubscriptionGift, 39 | ) => void 40 | [WebhookEvents.Livestream.StatusUpdated]: (livestreamStatus: LivestreamStatus) => void 41 | } 42 | 43 | export class WebhookHandler { 44 | private kient: Kient 45 | 46 | constructor(kient: Kient) { 47 | this.kient = kient 48 | } 49 | 50 | handleEvent(event: WebhookEvent) { 51 | switch (event.type as WebhookEventNames) { 52 | case 'chat.message.sent': { 53 | const chatMessage = new ChatMessage(this.kient, event) 54 | this.kient.emit('KIENT_CHAT_MESSAGE_SENT', chatMessage) 55 | break 56 | } 57 | 58 | case 'channel.followed': { 59 | const channelFollow = new ChannelFollow(this.kient, event) 60 | this.kient.emit('KIENT_CHANNEL_FOLLOW', channelFollow) 61 | break 62 | } 63 | 64 | case 'channel.subscription.new': { 65 | const channelSubscription = new ChannelSubscription(this.kient, event) 66 | this.kient.emit('KIENT_CHANNEL_SUBSCRIPTION', channelSubscription) 67 | break 68 | } 69 | 70 | case 'channel.subscription.renewal': { 71 | const channelSubscription = new ChannelSubscription(this.kient, event) 72 | this.kient.emit('KIENT_CHANNEL_RESUBSCRIPTION', channelSubscription) 73 | break 74 | } 75 | 76 | case 'channel.subscription.gifts': { 77 | const channelSubscriptionGift = new ChannelSubscriptionGift(this.kient, event) 78 | this.kient.emit('KIENT_CHANNEL_GIFT_SUBSCRIPTIONS', channelSubscriptionGift) 79 | break 80 | } 81 | 82 | case 'livestream.status.updated': { 83 | const livestreamStatus = new LivestreamStatus(this.kient, event) 84 | this.kient.emit('KIENT_LIVESTREAM_STATUS_UPDATED', livestreamStatus) 85 | break 86 | } 87 | 88 | default: 89 | break 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/webhook.server.ts: -------------------------------------------------------------------------------- 1 | import { Hono } from 'hono' 2 | 3 | import type { Kient } from 'kient' 4 | import { verifyWebhookSignature } from './util/verify-webhook-signature' 5 | 6 | export class WebhookServer { 7 | private kient: Kient 8 | private instance: Hono 9 | 10 | constructor(kient: Kient) { 11 | this.kient = kient 12 | this.instance = new Hono() 13 | this.initialiseRoutes() 14 | } 15 | 16 | private initialiseRoutes() { 17 | this.instance.post('/webhook', async (c) => { 18 | if (this.kient._kickPublicKey) { 19 | const messageId = c.req.header('Kick-Event-Message-Id') 20 | const subscriptionId = c.req.header('Kick-Event-Subscription-Id') 21 | const signature = c.req.header('Kick-Event-Signature') 22 | const timestamp = c.req.header('Kick-Event-Message-Timestamp') 23 | const body = await c.req.text() 24 | 25 | if (!messageId || !timestamp || !body || !signature) { 26 | console.error('Missing required parameters for signature verification') 27 | return c.body(null, 400) 28 | } 29 | 30 | const signatureValid = verifyWebhookSignature({ 31 | publicKey: this.kient._kickPublicKey, 32 | messageId, 33 | signature, 34 | timestamp, 35 | body, 36 | }) 37 | if (!signatureValid) { 38 | return c.body(null, 400) 39 | } 40 | 41 | const eventType = c.req.header('Kick-Event-Type') 42 | const eventVersion = c.req.header('Kick-Event-Version') 43 | 44 | if (!eventType || !eventVersion || !subscriptionId) { 45 | console.error('Missing required event type or version') 46 | return c.body(null, 400) 47 | } 48 | 49 | this.kient.handleWebhookEvent({ 50 | messageId, 51 | subscriptionId, 52 | timestamp, 53 | type: eventType, 54 | version: eventVersion, 55 | body, 56 | }) 57 | } else { 58 | console.warn('Not handling webhook event as public key is not available') 59 | } 60 | 61 | return c.body(null, 200) 62 | }) 63 | } 64 | 65 | get fetch() { 66 | return this.instance.fetch 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | // Enable latest features 4 | "lib": [ 5 | "ESNext" 6 | ], 7 | "target": "ESNext", 8 | "module": "ESNext", 9 | "moduleDetection": "force", 10 | "allowJs": true, 11 | // "isolatedDeclarations": true, 12 | // "declaration": true, 13 | // "declarationDir": "./types", 14 | // Bundler mode 15 | "moduleResolution": "Bundler", 16 | "allowImportingTsExtensions": true, 17 | "verbatimModuleSyntax": false, 18 | "noEmit": true, 19 | "resolveJsonModule": true, 20 | // Best practices 21 | "strict": true, 22 | "skipLibCheck": true, 23 | "noFallthroughCasesInSwitch": true, 24 | // Some stricter flags (disabled by default) 25 | "noUnusedLocals": false, 26 | "noUnusedParameters": false, 27 | "noPropertyAccessFromIndexSignature": false, 28 | "paths": { 29 | "kient": [ 30 | "./src/index.ts" 31 | ] 32 | }, 33 | "outDir": "dist" 34 | }, 35 | "reflection": true, 36 | "include": [ 37 | "src", 38 | "example" 39 | ], 40 | "exclude": [ 41 | "node_modules" 42 | ] 43 | } -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugin": [ 3 | "typedoc-plugin-markdown", 4 | "typedoc-vitepress-theme", 5 | "typedoc-plugin-missing-exports", 6 | "./docs/.typedoc/theme.js" 7 | ], 8 | "theme": "kientTheme", 9 | "entryPoints": [ 10 | "./src/index.ts" 11 | ], 12 | "exclude": [ 13 | "docs" 14 | ], 15 | "out": "./docs/typedoc", 16 | "readme": "none", 17 | "categorizeByGroup": true, 18 | "excludeExternals": true, 19 | "excludeInternal": true, 20 | /** 21 | * typedoc-plugin-missing-exports 22 | */ 23 | "internalModule": "Internal", 24 | "collapseInternalModule": true, 25 | "placeInternalsInOwningModule": true, 26 | /** 27 | * typedoc-vitepress-theme 28 | */ 29 | "docsRoot": "./docs", 30 | "useCodeBlocks": true, 31 | "parametersFormat": "table", 32 | "interfacePropertiesFormat": "table", 33 | "classPropertiesFormat": "table", 34 | "enumMembersFormat": "table", 35 | "typeDeclarationFormat": "table", 36 | "propertyMembersFormat": "table" 37 | } --------------------------------------------------------------------------------